This is an automated email from the ASF dual-hosted git repository. amashenkov pushed a commit to branch ignite-24979 in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit c7d54dfd68c7e3c16ef06728690358f48a9e2f95 Author: amashenkov <[email protected]> AuthorDate: Tue Apr 1 13:37:26 2025 +0300 Optimize TypeUtils.fromInternal and toInternal methods. --- .../internal/sql/engine/exec/ExecutionContext.java | 2 +- .../internal/sql/engine/exec/SqlRowHandler.java | 6 +- .../sql/engine/exec/exp/IgniteSqlFunctions.java | 3 +- .../prepare/ddl/DdlSqlToCommandConverter.java | 12 +- .../prepare/pruning/PartitionPruningPredicate.java | 3 +- .../ignite/internal/sql/engine/util/TypeUtils.java | 133 ++++++++++++++++++++- .../sql/engine/exec/row/SqlRowHandlerTest.java | 3 +- .../prepare/ddl/DdlSqlToCommandConverterTest.java | 3 +- .../internal/sql/engine/util/TypeUtilsTest.java | 10 ++ 9 files changed, 151 insertions(+), 24 deletions(-) diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionContext.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionContext.java index ee5abe01aa8..32b064f1c35 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionContext.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionContext.java @@ -298,7 +298,7 @@ public class ExecutionContext<RowT> implements DataContext { return null; } - return TypeUtils.toInternal(param, storageType == null ? param.getClass() : storageType); + return storageType == null ? TypeUtils.toInternal(param, param.getClass()) : TypeUtils.toInternal(param, storageType); } /** diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/SqlRowHandler.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/SqlRowHandler.java index e31442dfdcb..4fcff1628c4 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/SqlRowHandler.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/SqlRowHandler.java @@ -35,11 +35,9 @@ import org.apache.ignite.internal.sql.engine.exec.SqlRowHandler.RowWrapper; import org.apache.ignite.internal.sql.engine.exec.row.RowSchema; import org.apache.ignite.internal.sql.engine.exec.row.RowSchemaTypes; import org.apache.ignite.internal.sql.engine.exec.row.TypeSpec; -import org.apache.ignite.internal.sql.engine.util.Commons; import org.apache.ignite.internal.sql.engine.util.TypeUtils; import org.apache.ignite.internal.type.DecimalNativeType; import org.apache.ignite.internal.type.NativeType; -import org.apache.ignite.internal.type.NativeTypeSpec; import org.jetbrains.annotations.Nullable; /** @@ -262,7 +260,7 @@ public class SqlRowHandler implements RowHandler<RowWrapper> { NativeType nativeType = RowSchemaTypes.toNativeType(schemaType); - value = TypeUtils.fromInternal(value, NativeTypeSpec.toClass(nativeType.spec(), schemaType.isNullable())); + value = TypeUtils.fromInternal(value, nativeType.spec()); assert value != null : nativeType; @@ -365,7 +363,7 @@ public class SqlRowHandler implements RowHandler<RowWrapper> { return null; } - return TypeUtils.toInternal(value, Commons.nativeTypeToClass(nativeType)); + return TypeUtils.toInternal(value, nativeType.spec()); } @Override diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctions.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctions.java index e469dd76672..375f3bf5a49 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctions.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctions.java @@ -37,6 +37,7 @@ import org.apache.ignite.internal.lang.IgniteStringBuilder; import org.apache.ignite.internal.sql.engine.util.Commons; import org.apache.ignite.internal.sql.engine.util.IgniteMath; import org.apache.ignite.internal.sql.engine.util.TypeUtils; +import org.apache.ignite.internal.type.NativeTypeSpec; import org.apache.ignite.sql.SqlException; import org.jetbrains.annotations.Nullable; @@ -451,7 +452,7 @@ public class IgniteSqlFunctions { } public static int currentTime(DataContext ctx) { - return (int) TypeUtils.toInternal(LocalTime.now(), LocalTime.class); + return (int) TypeUtils.toInternal(LocalTime.now(), NativeTypeSpec.TIME); } /** LEAST2. */ diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java index b6be840005f..e6f6645063f 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java @@ -42,9 +42,6 @@ import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_VALIDATION_ERR; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; import java.time.Period; import java.util.ArrayList; import java.util.Arrays; @@ -140,6 +137,7 @@ import org.apache.ignite.internal.sql.engine.sql.IgniteSqlZoneOption; import org.apache.ignite.internal.sql.engine.sql.IgniteSqlZoneOptionMode; import org.apache.ignite.internal.sql.engine.type.UuidType; import org.apache.ignite.internal.sql.engine.util.Commons; +import org.apache.ignite.internal.type.NativeTypeSpec; import org.apache.ignite.lang.IgniteException; import org.apache.ignite.sql.ColumnType; import org.apache.ignite.sql.SqlException; @@ -993,12 +991,12 @@ public class DdlSqlToCommandConverter { try { literal = SqlParserUtil.parseDateLiteral(literal.getValueAs(String.class), literal.getParserPosition()); int val = literal.getValueAs(DateString.class).getDaysSinceEpoch(); - return fromInternal(val, LocalDate.class); + return fromInternal(val, NativeTypeSpec.DATE); } catch (CalciteContextException e) { literal = SqlParserUtil.parseTimestampLiteral(literal.getValueAs(String.class), literal.getParserPosition()); TimestampString tsString = literal.getValueAs(TimestampString.class); int val = convertToIntExact(TimeUnit.MILLISECONDS.toDays(tsString.getMillisSinceEpoch())); - return fromInternal(val, LocalDate.class); + return fromInternal(val, NativeTypeSpec.DATE); } } case TIME: { @@ -1009,13 +1007,13 @@ public class DdlSqlToCommandConverter { } literal = SqlParserUtil.parseTimeLiteral(strLiteral, literal.getParserPosition()); int val = literal.getValueAs(TimeString.class).getMillisOfDay(); - return fromInternal(val, LocalTime.class); + return fromInternal(val, NativeTypeSpec.TIME); } case DATETIME: { literal = SqlParserUtil.parseTimestampLiteral(literal.getValueAs(String.class), literal.getParserPosition()); var tsString = literal.getValueAs(TimestampString.class); - return fromInternal(tsString.getMillisSinceEpoch(), LocalDateTime.class); + return fromInternal(tsString.getMillisSinceEpoch(), NativeTypeSpec.DATETIME); } case TIMESTAMP: // TODO: IGNITE-17376 diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/pruning/PartitionPruningPredicate.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/pruning/PartitionPruningPredicate.java index 8879501c4ac..6627300e88c 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/pruning/PartitionPruningPredicate.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/pruning/PartitionPruningPredicate.java @@ -159,8 +159,7 @@ public final class PartitionPruningPredicate { NativeType physicalType = descriptor.physicalType(); Object valueInInternalForm = expressionFactory.scalar(node).get(context); - Class<?> storageType = NativeTypeSpec.toClass(physicalType.spec(), descriptor.nullable()); - Object value = TypeUtils.fromInternal(valueInInternalForm, storageType); + Object value = TypeUtils.fromInternal(valueInInternalForm, physicalType.spec()); partitionCalculator.append(value); } diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java index 32b321816cf..546fdf12f26 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/TypeUtils.java @@ -272,14 +272,73 @@ public class TypeUtils { var nativeTypeSpec = NativeTypeSpec.fromClass((Class<?>) storageType); assert nativeTypeSpec != null : "No native type spec for type: " + storageType; - var customType = SafeCustomTypeInternalConversion.INSTANCE.tryConvertToInternal(val, nativeTypeSpec); - return customType != null ? customType : val; + return SafeCustomTypeInternalConversion.INSTANCE.tryConvertToInternal(val, nativeTypeSpec); } } /** - * FromInternal. - * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859 + * Converts the given value to its presentation used by the execution engine. + */ + public static Object toInternal(Object val, NativeTypeSpec spec) { + switch (spec) { + case INT8: + return SqlFunctions.toByte(val); + case INT16: + return SqlFunctions.toShort(val); + case INT32: + return SqlFunctions.toInt(val); + case INT64: + return SqlFunctions.toLong(val); + case FLOAT: + return SqlFunctions.toFloat(val); + case DOUBLE: + return SqlFunctions.toDouble(val); + case DECIMAL: + return SqlFunctions.toBigDecimal(val); + case STRING: + return val; + case BYTES: { + if (val instanceof String) { + return new ByteString(((String) val).getBytes(StandardCharsets.UTF_8)); + } else if (val instanceof byte[]) { + return new ByteString((byte[]) val); + } else { + assert val instanceof ByteString : "Expected ByteString but got " + val + ", type=" + val.getClass().getTypeName(); + return val; + } + } + case DATE: + return (int) ((LocalDate) val).toEpochDay(); + case TIME: + return (int) (TimeUnit.NANOSECONDS.toMillis(((LocalTime) val).toNanoOfDay())); + case DATETIME: { + var dt = (LocalDateTime) val; + + return TimeUnit.SECONDS.toMillis(dt.toEpochSecond(ZoneOffset.UTC)) + TimeUnit.NANOSECONDS.toMillis(dt.getNano()); + } + case TIMESTAMP: { + var timeStamp = (Instant) val; + + return timeStamp.toEpochMilli(); + } + case BOOLEAN: + return SqlFunctions.toBoolean(val); + // case DURATION: + // return TimeUnit.SECONDS.toMillis(((Duration) val).getSeconds()) + // + TimeUnit.NANOSECONDS.toMillis(((Duration) val).getNano()); + // case PREIOD: + // return (int) ((Period) val).toTotalMonths(); + case UUID: + // Fallthrough. UUID is a custom type. + default: { + var customType = SafeCustomTypeInternalConversion.INSTANCE.tryConvertToInternal(val, spec); + return customType != null ? customType : val; + } + } + } + + /** + * Converts the value from its presentation used by the execution engine. */ public static @Nullable Object fromInternal(@Nullable Object val, Type storageType) { if (val == null) { @@ -302,8 +361,70 @@ public class TypeUtils { var nativeTypeSpec = NativeTypeSpec.fromClass((Class<?>) storageType); assert nativeTypeSpec != null : "No native type spec for type: " + storageType; - var customType = SafeCustomTypeInternalConversion.INSTANCE.tryConvertFromInternal(val, nativeTypeSpec); - return customType != null ? customType : val; + return SafeCustomTypeInternalConversion.INSTANCE.tryConvertFromInternal(val, nativeTypeSpec); + } + } + + /** + * Converts the value from its presentation used by the execution engine. + */ + public static @Nullable Object fromInternal(@Nullable Object val, NativeTypeSpec spec) { + if (val == null) { + return null; + } + switch (spec) { + case INT8: + case INT16: + case INT32: + case INT64: + case FLOAT: + case DOUBLE: { + assert val instanceof Number; + return val; + } + case DECIMAL: { + assert val instanceof BigDecimal; + return val; + } + case STRING: { + assert val instanceof String; + return val; + } + case BYTES: + return ((ByteString) val).getBytes(); + case DATE: { + assert val instanceof Integer; + return LocalDate.ofEpochDay((Integer) val); + } + case TIME: { + assert val instanceof Integer; + return LocalTime.ofNanoOfDay(TimeUnit.MILLISECONDS.toNanos(Long.valueOf((Integer) val))); + } + case DATETIME: { + assert val instanceof Long; + return LocalDateTime.ofInstant(Instant.ofEpochMilli((Long) val), ZoneOffset.UTC); + } + case TIMESTAMP: { + assert val instanceof Long; + return Instant.ofEpochMilli((Long) val); + } + case BOOLEAN: { + assert val instanceof Boolean; + return val; + } + // case DURATION: { + // assert val instanceof Long; + // return Duration.ofMillis((Long) val); + // } + // case PREIOD: { + // assert val instanceof Integer; + // return Period.of((Integer) val / 12, (Integer) val % 12, 0); + // } + case UUID: + // Fallthrough. UUID is a custom type. + default: { + return SafeCustomTypeInternalConversion.INSTANCE.tryConvertFromInternal(val, spec); + } } } diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/row/SqlRowHandlerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/row/SqlRowHandlerTest.java index bcaaa445cea..1b800ded7eb 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/row/SqlRowHandlerTest.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/row/SqlRowHandlerTest.java @@ -372,8 +372,7 @@ public class SqlRowHandlerTest extends IgniteAbstractTest { } else { BaseTypeSpec baseTypeSpec = (BaseTypeSpec) typeSpec; NativeType nativeType = baseTypeSpec.nativeType(); - Class<?> type = Commons.nativeTypeToClass(nativeType); - return TypeUtils.toInternal(value, type); + return TypeUtils.toInternal(value, nativeType.spec()); } } } diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverterTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverterTest.java index d56c893f5ca..d4517da6058 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverterTest.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverterTest.java @@ -86,6 +86,7 @@ import org.apache.ignite.internal.sql.engine.prepare.PlanningContext; import org.apache.ignite.internal.sql.engine.util.Commons; import org.apache.ignite.internal.sql.engine.util.SqlTestUtils; import org.apache.ignite.internal.testframework.WithSystemProperty; +import org.apache.ignite.internal.type.NativeTypeSpec; import org.apache.ignite.sql.ColumnType; import org.hamcrest.CustomMatcher; import org.hamcrest.Matcher; @@ -618,7 +619,7 @@ public class DdlSqlToCommandConverterTest extends AbstractDdlSqlToCommandConvert List<DynamicTest> testItems = new ArrayList<>(); PlanningContext ctx = createContext(); - fillTestCase("VARBINARY", "x'0102'", testItems, true, ctx, fromInternal(new byte[]{(byte) 1, (byte) 2}, byte[].class)); + fillTestCase("VARBINARY", "x'0102'", testItems, true, ctx, fromInternal(new byte[]{(byte) 1, (byte) 2}, NativeTypeSpec.BYTES)); fillTestCase("VARBINARY", "'0102'", testItems, false, ctx); fillTestCase("VARBINARY", "1", testItems, false, ctx); diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/TypeUtilsTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/TypeUtilsTest.java index 60b832effe1..20bf8be5e93 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/TypeUtilsTest.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/TypeUtilsTest.java @@ -55,6 +55,7 @@ import org.apache.ignite.internal.sql.engine.type.IgniteCustomTypeSpec; import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory; import org.apache.ignite.internal.sql.engine.type.UuidType; import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest; +import org.apache.ignite.internal.type.NativeTypeSpec; import org.apache.ignite.internal.type.NativeTypes; import org.apache.ignite.lang.ErrorGroups.Sql; import org.apache.ignite.sql.ColumnType; @@ -262,12 +263,21 @@ public class TypeUtilsTest extends BaseIgniteAbstractTest { @ParameterizedTest @MethodSource("valueAndType") public void testToFromInternalMatch(Object value, Class<?> type) { + var nativeTypeSpec = NativeTypeSpec.fromClass(type); + Object internal = TypeUtils.toInternal(value, type); assertNotNull(internal, "Conversion to internal has produced null"); + internal = TypeUtils.toInternal(value, nativeTypeSpec); + assertNotNull(internal, "Conversion to internal has produced null"); + Object original = TypeUtils.fromInternal(internal, type); assertEquals(value, original, "toInternal -> fromInternal"); assertNotNull(original, "Conversion from internal has produced null"); + + original = TypeUtils.fromInternal(internal, nativeTypeSpec); + assertEquals(value, original, "toInternal -> fromInternal"); + assertNotNull(original, "Conversion from internal has produced null"); } private static Stream<Arguments> valueAndType() {
