This is an automated email from the ASF dual-hosted git repository.

amashenkov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new d071242834 IGNITE-18827: Sql. UUID. Implement min/max functions. 
(#1686)
d071242834 is described below

commit d0712428348f403b78fd7df5c617ecb582a497d5
Author: Max Zhuravkov <[email protected]>
AuthorDate: Wed Feb 22 21:53:00 2023 +0400

    IGNITE-18827: Sql. UUID. Implement min/max functions. (#1686)
---
 .../ignite/internal/sql/engine/ItMetadataTest.java |  10 +-
 .../ignite/internal/sql/engine/ItUuidTest.java     |  16 +-
 .../sql/engine/exec/exp/agg/Accumulators.java      | 329 +++++----------------
 .../engine/exec/exp/agg/AccumulatorsFactory.java   |  10 +-
 4 files changed, 99 insertions(+), 266 deletions(-)

diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItMetadataTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItMetadataTest.java
index 671963eced..cc14334d22 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItMetadataTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItMetadataTest.java
@@ -139,8 +139,8 @@ public class ItMetadataTest extends 
AbstractBasicIntegrationTest {
                 // + "INTERVAL_SEC_C2 INTERVAL SECOND(9), "
 
                 // Custom types
-                // TODO: IGNITE-16376 support additional data types.
-                // + "UUID_C UUID, "
+                + "UUID_C UUID, "
+                // TODO: IGNITE-18431: Sql. BitSet is not supported.
                 // + "BITSET_C BITMASK, "
                 // + "BITSET_C BITMASK(8), "
 
@@ -194,7 +194,7 @@ public class ItMetadataTest extends 
AbstractBasicIntegrationTest {
                         new 
MetadataMatcher().name("TIMESTAMP_C2").type(ColumnType.TIMESTAMP).precision(9).scale(UNDEFINED_SCALE),
 
                         // Interval types
-                        // TODO: Ignite doesn't support interval types.
+                        // TODO: IGNITE-17373: Ignite doesn't support interval 
types yet.
                         // new MetadataMatcher().name("INTERVAL_YEAR_C"),
                         // new MetadataMatcher().name("INTERVAL_MONTH_C"),
                         // new MetadataMatcher().name("INTERVAL_DAY_C"),
@@ -204,8 +204,8 @@ public class ItMetadataTest extends 
AbstractBasicIntegrationTest {
                         // new MetadataMatcher().name("INTERVAL_SEC_C2"),
 
                         // Custom types
-                        // TODO: IGNITE-16376 support additional data types.
-                        // new MetadataMatcher().name("UUID_C"),
+                        new MetadataMatcher().name("UUID_C"),
+                        // TODO: IGNITE-18431: Sql. BitSet is not supported.
                         // new MetadataMatcher().name("BITSET_C"),
                         // new MetadataMatcher().name("BITSET_C2"),
 
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItUuidTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItUuidTest.java
index d69949e994..2630f24fc8 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItUuidTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItUuidTest.java
@@ -22,7 +22,6 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-import java.util.Arrays;
 import java.util.UUID;
 import java.util.stream.Stream;
 import org.apache.calcite.runtime.CalciteContextException;
@@ -141,11 +140,18 @@ public class ItUuidTest extends 
AbstractBasicIntegrationTest {
                 .returns(1, UUID_1)
                 .returns(2, UUID_2)
                 .check();
+    }
 
-        // UUID can be used by several aggregate functions
-        for (var func : Arrays.asList("COUNT", "ANY_VALUE")) {
-            sql(format("SELECT {}(uuid_key) FROM t", func));
-        }
+    @Test
+    public void testBasicAggregates() {
+        sql(format("INSERT INTO t VALUES (1, CAST('{}' as UUID))", UUID_1));
+        sql(format("INSERT INTO t VALUES (2, CAST('{}' as UUID))", UUID_2));
+
+        assertQuery("SELECT COUNT(uuid_key) FROM t").returns(2L).check();
+        assertQuery("SELECT ANY_VALUE(uuid_key) FROM t").check();
+
+        assertQuery("SELECT MIN(uuid_key) FROM t").returns(UUID_2).check();
+        assertQuery("SELECT MAX(uuid_key) FROM t").returns(UUID_1).check();
     }
 
     @Test
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/Accumulators.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/Accumulators.java
index 3047060c85..f6b875cfbc 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/Accumulators.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/Accumulators.java
@@ -34,6 +34,8 @@ import java.util.Set;
 import java.util.function.Supplier;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
 import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
 
 /**
@@ -41,11 +43,21 @@ import 
org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
  * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
  */
 public class Accumulators {
+
+    private final IgniteTypeFactory typeFactory;
+
+    /**
+     * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
+     */
+    public Accumulators(IgniteTypeFactory typeFactory) {
+        this.typeFactory = typeFactory;
+    }
+
     /**
      * AccumulatorFactory.
      * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
      */
-    public static Supplier<Accumulator> accumulatorFactory(AggregateCall call) 
{
+    public Supplier<Accumulator> accumulatorFactory(AggregateCall call) {
         if (!call.isDistinct()) {
             return accumulatorFunctionFactory(call);
         }
@@ -55,11 +67,7 @@ public class Accumulators {
         return () -> new DistinctAccumulator(fac);
     }
 
-    /**
-     * AccumulatorFunctionFactory.
-     * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
-     */
-    public static Supplier<Accumulator> 
accumulatorFunctionFactory(AggregateCall call) {
+    private Supplier<Accumulator> accumulatorFunctionFactory(AggregateCall 
call) {
         // Update documentation in IgniteCustomType when you add an aggregate
         // that can work for any type out of the box.
         switch (call.getAggregation().getName()) {
@@ -72,9 +80,9 @@ public class Accumulators {
             case "$SUM0":
                 return sumEmptyIsZeroFactory(call);
             case "MIN":
-                return minFactory(call);
+                return minMaxFactory(true, call);
             case "MAX":
-                return maxFactory(call);
+                return minMaxFactory(false, call);
             case "SINGLE_VALUE":
                 return SingleVal.FACTORY;
             case "ANY_VALUE":
@@ -84,7 +92,7 @@ public class Accumulators {
         }
     }
 
-    private static Supplier<Accumulator> avgFactory(AggregateCall call) {
+    private Supplier<Accumulator> avgFactory(AggregateCall call) {
         switch (call.type.getSqlTypeName()) {
             case BIGINT:
             case DECIMAL:
@@ -102,7 +110,7 @@ public class Accumulators {
         }
     }
 
-    private static Supplier<Accumulator> sumFactory(AggregateCall call) {
+    private Supplier<Accumulator> sumFactory(AggregateCall call) {
         switch (call.type.getSqlTypeName()) {
             case BIGINT:
             case DECIMAL:
@@ -125,7 +133,7 @@ public class Accumulators {
         }
     }
 
-    private static Supplier<Accumulator> sumEmptyIsZeroFactory(AggregateCall 
call) {
+    private Supplier<Accumulator> sumEmptyIsZeroFactory(AggregateCall call) {
         switch (call.type.getSqlTypeName()) {
             case BIGINT:
             case DECIMAL:
@@ -148,49 +156,22 @@ public class Accumulators {
         }
     }
 
-    private static Supplier<Accumulator> minFactory(AggregateCall call) {
-        switch (call.type.getSqlTypeName()) {
-            case DOUBLE:
-            case REAL:
-            case FLOAT:
-                return DoubleMinMax.MIN_FACTORY;
-            case DECIMAL:
-                return DecimalMinMax.MIN_FACTORY;
-            case INTEGER:
-                return IntMinMax.MIN_FACTORY;
-            case CHAR:
-            case VARCHAR:
-                return VarCharMinMax.MIN_FACTORY;
-            case BIGINT:
-            default:
-                // IgniteCustomType: MIN for a custom type should go here.
-                if (call.type.getSqlTypeName() == ANY) {
-                    throw unsupportedAggregateFunction(call);
-                }
-                return LongMinMax.MIN_FACTORY;
-        }
-    }
+    private Supplier<Accumulator> minMaxFactory(boolean min, AggregateCall 
call) {
+        var type = call.getType();
+        var typeName = type.getSqlTypeName();
 
-    private static Supplier<Accumulator> maxFactory(AggregateCall call) {
-        switch (call.type.getSqlTypeName()) {
-            case DOUBLE:
-            case REAL:
-            case FLOAT:
-                return DoubleMinMax.MAX_FACTORY;
-            case DECIMAL:
-                return DecimalMinMax.MAX_FACTORY;
-            case INTEGER:
-                return IntMinMax.MAX_FACTORY;
+        switch (typeName) {
             case CHAR:
             case VARCHAR:
-                return VarCharMinMax.MAX_FACTORY;
-            case BIGINT:
+                return min ? VarCharMinMax.MIN_FACTORY : 
VarCharMinMax.MAX_FACTORY;
             default:
-                // IgniteCustomType: MAX for a custom type should go here.
-                if (call.type.getSqlTypeName() == ANY) {
+                if (type instanceof IgniteCustomType) {
+                    return MinMaxAccumulator.newAccumulator(min, typeFactory, 
type);
+                } else if (type.getSqlTypeName() == ANY) {
                     throw unsupportedAggregateFunction(call);
+                } else {
+                    return MinMaxAccumulator.newAccumulator(min, typeFactory, 
type);
                 }
-                return LongMinMax.MAX_FACTORY;
         }
     }
 
@@ -644,63 +625,81 @@ public class Accumulators {
         }
     }
 
-    private static class DoubleMinMax implements Accumulator {
-        public static final Supplier<Accumulator> MIN_FACTORY = () -> new 
DoubleMinMax(true);
+    private static final class MinMaxAccumulator implements Accumulator {
 
-        public static final Supplier<Accumulator> MAX_FACTORY = () -> new 
DoubleMinMax(false);
+        private static final long serialVersionUID = 0;
 
         private final boolean min;
 
-        private double val;
+        private final List<RelDataType> arguments;
 
-        private boolean empty = true;
+        private final RelDataType returnType;
+
+        @SuppressWarnings({"rawtypes"})
+        private Comparable val;
+
+        private MinMaxAccumulator(boolean min, RelDataTypeFactory typeFactory, 
RelDataType relDataType) {
+            var nullableType = 
typeFactory.createTypeWithNullability(relDataType, true);
 
-        private DoubleMinMax(boolean min) {
             this.min = min;
+            this.arguments = List.of(nullableType);
+            this.returnType = nullableType;
         }
 
-        /** {@inheritDoc} */
+        static Supplier<Accumulator> newAccumulator(boolean min, 
RelDataTypeFactory typeFactory, RelDataType type) {
+            return () -> new MinMaxAccumulator(min, typeFactory, type);
+        }
+
+        /** {@inheritDoc} **/
         @Override
+        @SuppressWarnings({"rawtypes"})
         public void add(Object... args) {
-            Double in = (Double) args[0];
+            Comparable in = (Comparable) args[0];
 
-            if (in == null) {
-                return;
-            }
-
-            val = empty ? in : min ? Math.min(val, in) : Math.max(val, in);
-            empty = false;
+            doApply(in);
         }
 
-        /** {@inheritDoc} */
+        /** {@inheritDoc} **/
         @Override
         public void apply(Accumulator other) {
-            DoubleMinMax other0 = (DoubleMinMax) other;
-
-            if (other0.empty) {
-                return;
-            }
-
-            val = empty ? other0.val : min ? Math.min(val, other0.val) : 
Math.max(val, other0.val);
-            empty = false;
+            MinMaxAccumulator other0 = (MinMaxAccumulator) other;
+            doApply(other0.val);
         }
 
-        /** {@inheritDoc} */
+        /** {@inheritDoc} **/
         @Override
         public Object end() {
-            return empty ? null : val;
+            return val;
         }
 
-        /** {@inheritDoc} */
+        /** {@inheritDoc} **/
         @Override
         public List<RelDataType> argumentTypes(IgniteTypeFactory typeFactory) {
-            return 
List.of(typeFactory.createTypeWithNullability(typeFactory.createSqlType(DOUBLE),
 true));
+            return arguments;
         }
 
-        /** {@inheritDoc} */
+        /** {@inheritDoc} **/
         @Override
         public RelDataType returnType(IgniteTypeFactory typeFactory) {
-            return 
typeFactory.createTypeWithNullability(typeFactory.createSqlType(DOUBLE), true);
+            return returnType;
+        }
+
+        @SuppressWarnings({"rawtypes", "unchecked"})
+        private void doApply(Comparable in) {
+            if (in == null) {
+                return;
+            }
+
+            if (val == null) {
+                val = in;
+            } else {
+                var cmp = val.compareTo(in);
+                if (min) {
+                    val = cmp > 0 ? in : val;
+                } else {
+                    val = cmp < 0 ? in : val;
+                }
+            }
         }
     }
 
@@ -791,182 +790,6 @@ public class Accumulators {
         }
     }
 
-    private static class IntMinMax implements Accumulator {
-        public static final Supplier<Accumulator> MIN_FACTORY = () -> new 
IntMinMax(true);
-
-        public static final Supplier<Accumulator> MAX_FACTORY = () -> new 
IntMinMax(false);
-
-        private final boolean min;
-
-        private int val;
-
-        private boolean empty = true;
-
-        private IntMinMax(boolean min) {
-            this.min = min;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void add(Object... args) {
-            Integer in = (Integer) args[0];
-
-            if (in == null) {
-                return;
-            }
-
-            val = empty ? in : min ? Math.min(val, in) : Math.max(val, in);
-            empty = false;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void apply(Accumulator other) {
-            IntMinMax other0 = (IntMinMax) other;
-
-            if (other0.empty) {
-                return;
-            }
-
-            val = empty ? other0.val : min ? Math.min(val, other0.val) : 
Math.max(val, other0.val);
-            empty = false;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Object end() {
-            return empty ? null : val;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public List<RelDataType> argumentTypes(IgniteTypeFactory typeFactory) {
-            return 
List.of(typeFactory.createTypeWithNullability(typeFactory.createSqlType(INTEGER),
 true));
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public RelDataType returnType(IgniteTypeFactory typeFactory) {
-            return 
typeFactory.createTypeWithNullability(typeFactory.createSqlType(INTEGER), true);
-        }
-    }
-
-    private static class LongMinMax implements Accumulator {
-        public static final Supplier<Accumulator> MIN_FACTORY = () -> new 
LongMinMax(true);
-
-        public static final Supplier<Accumulator> MAX_FACTORY = () -> new 
LongMinMax(false);
-
-        private final boolean min;
-
-        private long val;
-
-        private boolean empty = true;
-
-        private LongMinMax(boolean min) {
-            this.min = min;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void add(Object... args) {
-            Long in = (Long) args[0];
-
-            if (in == null) {
-                return;
-            }
-
-            val = empty ? in : min ? Math.min(val, in) : Math.max(val, in);
-            empty = false;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void apply(Accumulator other) {
-            LongMinMax other0 = (LongMinMax) other;
-
-            if (other0.empty) {
-                return;
-            }
-
-            val = empty ? other0.val : min ? Math.min(val, other0.val) : 
Math.max(val, other0.val);
-            empty = false;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Object end() {
-            return empty ? null : val;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public List<RelDataType> argumentTypes(IgniteTypeFactory typeFactory) {
-            return 
List.of(typeFactory.createTypeWithNullability(typeFactory.createSqlType(BIGINT),
 true));
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public RelDataType returnType(IgniteTypeFactory typeFactory) {
-            return 
typeFactory.createTypeWithNullability(typeFactory.createSqlType(BIGINT), true);
-        }
-    }
-
-    private static class DecimalMinMax implements Accumulator {
-        public static final Supplier<Accumulator> MIN_FACTORY = () -> new 
DecimalMinMax(true);
-
-        public static final Supplier<Accumulator> MAX_FACTORY = () -> new 
DecimalMinMax(false);
-
-        private final boolean min;
-
-        private BigDecimal val;
-
-        private DecimalMinMax(boolean min) {
-            this.min = min;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void add(Object... args) {
-            BigDecimal in = (BigDecimal) args[0];
-
-            if (in == null) {
-                return;
-            }
-
-            val = val == null ? in : min ? val.min(in) : val.max(in);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void apply(Accumulator other) {
-            DecimalMinMax other0 = (DecimalMinMax) other;
-
-            if (other0.val == null) {
-                return;
-            }
-
-            val = val == null ? other0.val : min ? val.min(other0.val) : 
val.max(other0.val);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Object end() {
-            return val;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public List<RelDataType> argumentTypes(IgniteTypeFactory typeFactory) {
-            return 
List.of(typeFactory.createTypeWithNullability(typeFactory.createSqlType(DECIMAL),
 true));
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public RelDataType returnType(IgniteTypeFactory typeFactory) {
-            return 
typeFactory.createTypeWithNullability(typeFactory.createSqlType(DECIMAL), true);
-        }
-    }
-
     private static class DistinctAccumulator implements Accumulator {
         private final Accumulator acc;
 
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/AccumulatorsFactory.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/AccumulatorsFactory.java
index 0b4ea007cf..455f38383e 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/AccumulatorsFactory.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/agg/AccumulatorsFactory.java
@@ -150,7 +150,8 @@ public class AccumulatorsFactory<RowT> implements 
Supplier<List<AccumulatorWrapp
         this.type = type;
         this.inputRowType = inputRowType;
 
-        prototypes = Commons.transform(aggCalls, WrapperPrototype::new);
+        var accumulators = new Accumulators(ctx.getTypeFactory());
+        prototypes = Commons.transform(aggCalls, call -> new 
WrapperPrototype(accumulators, call));
     }
 
     /** {@inheritDoc} */
@@ -162,13 +163,16 @@ public class AccumulatorsFactory<RowT> implements 
Supplier<List<AccumulatorWrapp
     private final class WrapperPrototype implements 
Supplier<AccumulatorWrapper<RowT>> {
         private Supplier<Accumulator> accFactory;
 
+        private final Accumulators accumulators;
+
         private final AggregateCall call;
 
         private Function<Object[], Object[]> inAdapter;
 
         private Function<Object, Object> outAdapter;
 
-        private WrapperPrototype(AggregateCall call) {
+        private WrapperPrototype(Accumulators accumulators, AggregateCall 
call) {
+            this.accumulators = accumulators;
             this.call = call;
         }
 
@@ -187,7 +191,7 @@ public class AccumulatorsFactory<RowT> implements 
Supplier<List<AccumulatorWrapp
             }
 
             // init factory and adapters
-            accFactory = Accumulators.accumulatorFactory(call);
+            accFactory = accumulators.accumulatorFactory(call);
             Accumulator accumulator = accFactory.get();
 
             inAdapter = createInAdapter(accumulator);

Reply via email to