This is an automated email from the ASF dual-hosted git repository.
korlov 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 e3221a56be4 IGNITE-25462 Get rid of SafeCustomTypeInternalConversion
(#6623)
e3221a56be4 is described below
commit e3221a56be4cdc73b7f8902d7890d4b5e0c00a8c
Author: korlov42 <[email protected]>
AuthorDate: Mon Sep 22 14:00:09 2025 +0300
IGNITE-25462 Get rid of SafeCustomTypeInternalConversion (#6623)
---
.../engine/datatypes/tests/BaseDataTypeTest.java | 3 +-
modules/sql-engine/src/main/codegen/config.fmpp | 1 -
.../sql/engine/exec/exp/ConverterUtils.java | 3 +-
.../sql/engine/exec/exp/CustomTypesConversion.java | 93 ----------
.../sql/engine/exec/exp/RexToLixTranslator.java | 3 +-
.../sql/engine/exec/exp/agg/Accumulators.java | 11 +-
.../internal/sql/engine/externalize/RelJson.java | 12 --
.../sql/engine/prepare/IgniteSqlValidator.java | 96 +---------
.../sql/engine/prepare/IgniteTypeCoercion.java | 46 +----
.../internal/sql/engine/rex/IgniteRexBuilder.java | 16 +-
.../sql/engine/sql/IgniteSqlTypeNameSpec.java | 98 -----------
.../sql/engine/sql/fun/IgniteSqlOperatorTable.java | 19 +-
.../sql/fun/NotCustomTypeOperandTypeChecker.java | 58 ------
.../internal/sql/engine/type/IgniteCustomType.java | 148 ----------------
.../engine/type/IgniteCustomTypeCoercionRules.java | 125 -------------
.../sql/engine/type/IgniteCustomTypeSpec.java | 160 -----------------
.../sql/engine/type/IgniteTypeFactory.java | 195 +--------------------
.../util/SafeCustomTypeInternalConversion.java | 66 -------
.../ignite/internal/sql/engine/util/TypeUtils.java | 68 ++-----
.../engine/prepare/LeastRestrictiveTypesTest.java | 89 ----------
.../internal/sql/engine/util/TypeUtilsTest.java | 51 ------
21 files changed, 44 insertions(+), 1317 deletions(-)
diff --git
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/tests/BaseDataTypeTest.java
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/tests/BaseDataTypeTest.java
index 7018052a759..d8332b85bb0 100644
---
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/tests/BaseDataTypeTest.java
+++
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/tests/BaseDataTypeTest.java
@@ -28,7 +28,6 @@ import java.util.stream.Stream;
import org.apache.calcite.sql.SqlKind;
import org.apache.ignite.internal.app.IgniteImpl;
import org.apache.ignite.internal.sql.BaseSqlIntegrationTest;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomTypeSpec;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.NativeTypeWrapper;
import org.apache.ignite.internal.sql.engine.util.QueryChecker;
@@ -40,7 +39,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.provider.Arguments;
/**
- * Base class for test cases for data types including {@link
IgniteCustomTypeSpec custom data types}.
+ * Base class for test cases for data types.
*
* <p>Usage:
* <ul>
diff --git a/modules/sql-engine/src/main/codegen/config.fmpp
b/modules/sql-engine/src/main/codegen/config.fmpp
index cdbd066449e..7fd7489719f 100644
--- a/modules/sql-engine/src/main/codegen/config.fmpp
+++ b/modules/sql-engine/src/main/codegen/config.fmpp
@@ -59,7 +59,6 @@ data: {
"org.apache.ignite.internal.sql.engine.sql.IgniteSqlIndexType",
"org.apache.ignite.internal.sql.engine.sql.IgniteSqlAlterZoneSet",
"org.apache.ignite.internal.sql.engine.sql.IgniteSqlAlterZoneRenameTo",
- "org.apache.ignite.internal.sql.engine.sql.IgniteSqlTypeNameSpec",
"org.apache.ignite.internal.sql.engine.sql.IgniteSqlAlterZoneSetDefault",
"org.apache.ignite.internal.sql.engine.sql.IgniteSqlKill",
"org.apache.ignite.internal.sql.engine.sql.IgniteSqlKillObjectType",
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ConverterUtils.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ConverterUtils.java
index 18cffd6d5e5..5be9dd63e2a 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ConverterUtils.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ConverterUtils.java
@@ -331,8 +331,7 @@ public class ConverterUtils {
return Expressions.call(UUID.class, "fromString", operand);
}
- var toCustomType = CustomTypesConversion.INSTANCE.tryConvert(operand,
toType);
- return toCustomType != null ? toCustomType :
EnumUtils.convert(operand, toType);
+ return EnumUtils.convert(operand, toType);
}
private static boolean isA(Type fromType, Primitive primitive) {
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/CustomTypesConversion.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/CustomTypesConversion.java
deleted file mode 100644
index f1dac993065..00000000000
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/CustomTypesConversion.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.sql.engine.exec.exp;
-
-import java.lang.reflect.Type;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Function;
-import org.apache.calcite.linq4j.tree.Expression;
-import org.apache.calcite.linq4j.tree.Expressions;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Provides cast expressions for {@link IgniteCustomType custom data types}.
- */
-final class CustomTypesConversion {
-
- static final CustomTypesConversion INSTANCE = new
CustomTypesConversion(Commons.typeFactory());
-
- private final Map<Class<?>, Function<Expression, Expression>>
castByInternalType = new HashMap<>();
-
- private final Map<String, Function<Expression, Expression>> castByTypeName
= new HashMap<>();
-
- private CustomTypesConversion(IgniteTypeFactory typeFactory) {
- // IgniteCustomType: Add cast function implementations.
- var customTypeSpecs = typeFactory.getCustomTypeSpecs();
-
- for (var spec : customTypeSpecs.values()) {
- // We use Object as an argument because:
- //
- // 1. type info is erased for dynamic parameters. See
DataContextInputGetter in RexExecutorImpl.
- // 2. so internal calls will throw a CastCastException instead of
a NoSuchMethodError in runtime
- // (It would be even better if such casts were not necessary).
-
- Function<Expression, Expression> castExpr =
- (operand) -> Expressions.call(spec.castFunction(),
Expressions.convert_(operand, Object.class));
- // ??? Should we add a hook here that can short-circuit when a
custom type can not be converted?
-
- castByInternalType.put(spec.storageType(), castExpr);
- castByTypeName.put(spec.typeName(), castExpr);
- }
- }
-
- /**
- * If the specified {@code internalType} represents is a custom data type,
- * then this method returns expression that converts an operand to it.
Otherwise returns {@code null}.
- * */
- @Nullable
- Expression tryConvert(Expression operand, Type internalType) {
- // internal type is always a Class.
- var cast = castByInternalType.get((Class<?>) internalType);
- if (cast == null) {
- return null;
- }
-
- return cast.apply(operand);
- }
-
- /**
- * If the specified {@code targetType} represents is a custom data type,
- * then this method returns expression that converts an operand to it.
Otherwise returns {@code null}.
- * */
- @Nullable
- Expression tryConvert(Expression operand, RelDataType targetType) {
- if (!(targetType instanceof IgniteCustomType)) {
- return null;
- }
-
- var customType = (IgniteCustomType) targetType;
- Function<Expression, Expression> cast =
castByTypeName.get(customType.getCustomTypeName());
-
- return cast.apply(operand);
- }
-}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
index 04f7ffb6d48..74f81490bb1 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
@@ -418,8 +418,7 @@ public class RexToLixTranslator implements
RexVisitor<RexToLixTranslator.Result>
Expression roundingMode =
Expressions.constant(typeFactory.getTypeSystem().roundingMode());
return Expressions.call(BuiltInMethod.VARIANT_CREATE.method,
roundingMode, operand, rtti);
case ANY:
- var toCustomType = CustomTypesConversion.INSTANCE.tryConvert(operand,
targetType);
- return (toCustomType != null) ? toCustomType: operand;
+ return operand;
case VARBINARY:
case BINARY:
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 2ff21e0e03a..a2681284095 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
@@ -42,7 +42,6 @@ import org.apache.calcite.sql.fun.SqlLiteralAggFunction;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.ignite.internal.catalog.commands.CatalogUtils;
import org.apache.ignite.internal.sql.engine.exec.exp.IgniteSqlFunctions;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.IgniteMath;
@@ -191,9 +190,7 @@ public class Accumulators {
case VARBINARY:
return min ? VarBinaryMinMax.MIN_FACTORY :
VarBinaryMinMax.MAX_FACTORY;
default:
- if (type instanceof IgniteCustomType) {
- return MinMaxAccumulator.newAccumulator(min, typeFactory,
type);
- } else if (type.getSqlTypeName() == ANY) {
+ if (type.getSqlTypeName() == ANY) {
throw unsupportedAggregateFunction(call);
} else {
return MinMaxAccumulator.newAccumulator(min, typeFactory,
type);
@@ -204,7 +201,7 @@ public class Accumulators {
private Supplier<Accumulator> singleValueFactory(AggregateCall call) {
RelDataType type = call.getType();
- if (type.getSqlTypeName() == ANY && !(type instanceof
IgniteCustomType)) {
+ if (type.getSqlTypeName() == ANY) {
throw unsupportedAggregateFunction(call);
}
@@ -214,7 +211,7 @@ public class Accumulators {
private Supplier<Accumulator> anyValueFactory(AggregateCall call) {
RelDataType type = call.getType();
- if (type.getSqlTypeName() == ANY && !(type instanceof
IgniteCustomType)) {
+ if (type.getSqlTypeName() == ANY) {
throw unsupportedAggregateFunction(call);
}
@@ -224,7 +221,7 @@ public class Accumulators {
private Supplier<Accumulator> groupingFactory(AggregateCall call) {
RelDataType type = call.getType();
- if (type.getSqlTypeName() == ANY && !(type instanceof
IgniteCustomType)) {
+ if (type.getSqlTypeName() == ANY) {
throw unsupportedAggregateFunction(call);
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/externalize/RelJson.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/externalize/RelJson.java
index e2e1af2e988..b01d0a50af2 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/externalize/RelJson.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/externalize/RelJson.java
@@ -116,7 +116,6 @@ import
org.apache.ignite.internal.sql.engine.trait.DistributionFunction;
import org.apache.ignite.internal.sql.engine.trait.DistributionTrait;
import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.util.IgniteUtils;
@@ -383,13 +382,6 @@ class RelJson {
if (node.getSqlTypeName().allowsScale()) {
map.put("scale", node.getScale());
}
- if (node instanceof IgniteCustomType) {
- // In case of a custom data type we must store its name to
correctly
- // deserialize it because we want to distinguish a custom type
from ANY.
- IgniteCustomType customType = (IgniteCustomType) node;
- map.put("type", toJson(SqlTypeName.ANY));
- map.put("customType", customType.getCustomTypeName());
- }
return map;
}
}
@@ -730,8 +722,6 @@ class RelJson {
}
Object fields = map.get("fields");
- // IgniteCustomType: In case of a custom data type JSON must
contain a name of that type.
- String customType = (String) map.get("customType");
if (fields != null) {
return toType(typeFactory, fields);
@@ -753,8 +743,6 @@ class RelJson {
toType(typeFactory, map.get("keyType")),
toType(typeFactory, map.get("valueType"))
);
- } else if (sqlTypeName == SqlTypeName.ANY && customType !=
null) {
- type = ((IgniteTypeFactory)
typeFactory).createCustomType(customType, precision);
} else if (precision == null) {
type = typeFactory.createSqlType(sqlTypeName);
} else if (scale == null) {
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java
index bb5bb0d9f8f..702241784ca 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java
@@ -68,7 +68,6 @@ import org.apache.calcite.sql.SqlCharStringLiteral;
import org.apache.calcite.sql.SqlDataTypeSpec;
import org.apache.calcite.sql.SqlDelete;
import org.apache.calcite.sql.SqlDynamicParam;
-import org.apache.calcite.sql.SqlFunction;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlInsert;
import org.apache.calcite.sql.SqlIntervalLiteral;
@@ -78,7 +77,6 @@ import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlMerge;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
-import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlOperatorTable;
import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.SqlTypeNameSpec;
@@ -110,9 +108,6 @@ import
org.apache.ignite.internal.sql.engine.schema.IgniteDataSource;
import org.apache.ignite.internal.sql.engine.schema.IgniteSystemView;
import org.apache.ignite.internal.sql.engine.schema.IgniteTable;
import org.apache.ignite.internal.sql.engine.sql.IgniteSqlExplain;
-import org.apache.ignite.internal.sql.engine.sql.fun.IgniteSqlOperatorTable;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
-import
org.apache.ignite.internal.sql.engine.type.IgniteCustomTypeCoercionRules;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.IgniteCustomAssignmentsRules;
@@ -346,13 +341,6 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
boolean canAssign = SqlTypeUtil.canAssignFrom(targetType,
sourceType);
- if (canAssign && ((targetType instanceof IgniteCustomType) ||
(sourceType instanceof IgniteCustomType))) {
- // SqlTypeUtil.canAssignFrom doesn't account for custom types,
therefore need to check
- // this explicitly. Since at the moment there are no custom
types which can be assigned from
- // each other, let's just check for equality.
- canAssign = SqlTypeUtil.equalSansNullability(typeFactory,
targetType, sourceType);
- }
-
if (!canAssign) {
// Throws proper exception if assignment is not possible due to
// problem with dynamic parameter type inference.
@@ -841,26 +829,6 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
return dataType;
}
- // Comparison and arithmetic operators are SqlCalls.
- SqlCall sqlCall = (SqlCall) expr;
- var lhs = getValidatedNodeType(sqlCall.operand(0));
- var rhs = getValidatedNodeType(sqlCall.operand(1));
-
- // IgniteCustomType:
- // Check compatibility for operands of binary comparison operation
between custom data types vs built-in SQL types.
- // We get here because in calcite ANY type can be assigned/casted to
all other types.
- // This check can be a part of some SqlOperandTypeChecker?
-
- if (lhs instanceof IgniteCustomType || rhs instanceof
IgniteCustomType) {
- boolean lhsRhsCompatible =
TypeUtils.typeFamiliesAreCompatible(typeFactory, lhs, rhs);
- boolean rhsLhsCompatible =
TypeUtils.typeFamiliesAreCompatible(typeFactory, rhs, lhs);
-
- if (!lhsRhsCompatible && !rhsLhsCompatible) {
- SqlCallBinding callBinding = new SqlCallBinding(this, scope,
(SqlCall) expr);
- throw callBinding.newValidationSignatureError();
- }
- }
-
return dataType;
}
@@ -992,24 +960,9 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
return;
}
- RelDataType returnCustomType = returnType instanceof IgniteCustomType
? returnType : null;
- RelDataType operandCustomType = operandType instanceof
IgniteCustomType ? operandType : null;
-
- IgniteCustomTypeCoercionRules coercionRules =
typeFactory().getCustomTypeCoercionRules();
-
- boolean check;
- if (operandCustomType != null && returnCustomType != null) {
- // it`s not allowed to convert between different custom types for
now.
- check = SqlTypeUtil.equalSansNullability(typeFactory, operandType,
returnType);
- } else if (operandCustomType != null) {
- check = coercionRules.needToCast(returnType, (IgniteCustomType)
operandCustomType);
- } else if (returnCustomType != null) {
- check = coercionRules.needToCast(operandType, (IgniteCustomType)
returnCustomType);
- } else {
- check = IgniteCustomAssignmentsRules.instance().canApplyFrom(
- returnType.getSqlTypeName(), operandType.getSqlTypeName()
- );
- }
+ boolean check = IgniteCustomAssignmentsRules.instance().canApplyFrom(
+ returnType.getSqlTypeName(), operandType.getSqlTypeName()
+ );
if (!check) {
throw newValidationError(expr,
@@ -1437,54 +1390,11 @@ public class IgniteSqlValidator extends
SqlValidatorImpl {
throw newValidationError(call,
IgniteResource.INSTANCE.unsupportedExpression("String literal expected"));
}
super.validateCall(call, scope);
-
- checkCallsWithCustomTypes(call, scope);
} finally {
callScopes.pop();
}
}
- private void checkCallsWithCustomTypes(SqlCall call, SqlValidatorScope
scope) {
- SqlOperator operator = call.getOperator();
-
- // IgniteCustomType:
- // Since custom data types use ANY that is a catch all type for type
checkers,
- // if a function is called with custom data type argument does not
belong to CUSTOM_TYPE_FUNCTIONS,
- // then this should be considered a validation error.
-
- if (call.getOperandList().isEmpty()
- || !(operator instanceof SqlFunction)
- ||
IgniteSqlOperatorTable.CUSTOM_TYPE_FUNCTIONS.contains(operator)) {
- return;
- }
-
- for (SqlNode node : call.getOperandList()) {
- RelDataType type = getValidatedNodeTypeIfKnown(node);
- // Argument type is not known yet (alias) or it is not a custom
data type.
- if ((!(type instanceof IgniteCustomType))) {
- continue;
- }
-
- String name = call.getOperator().getName();
-
- // Call to getAllowedSignatures throws NPE, if operandTypeChecker
is null.
- if (operator.getOperandTypeChecker() != null) {
- // If signatures are available, then return:
- // Cannot apply 'F' to arguments of type 'F(<ARG_TYPE>)'.
Supported form(s): 'F(<TYPE>)'
- String allowedSignatures = operator.getAllowedSignatures();
- throw newValidationError(call,
- RESOURCE.canNotApplyOp2Type(name,
- call.getCallSignature(this, scope),
- allowedSignatures));
- } else {
- // Otherwise return an error w/o supported forms:
- // Cannot apply 'F' to arguments of type 'F(<ARG_TYPE>)'
- throw newValidationError(call,
IgniteResource.INSTANCE.canNotApplyOp2Type(name,
- call.getCallSignature(this, scope)));
- }
- }
- }
-
/** {@inheritDoc} */
@Override
protected void inferUnknownTypes(RelDataType inferredType,
SqlValidatorScope scope, SqlNode node) {
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteTypeCoercion.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteTypeCoercion.java
index f319fe74002..6a12754742a 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteTypeCoercion.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteTypeCoercion.java
@@ -62,12 +62,9 @@ import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.calcite.sql.validate.implicit.TypeCoercionImpl;
import org.apache.calcite.util.Util;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
-import
org.apache.ignite.internal.sql.engine.type.IgniteCustomTypeCoercionRules;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.sql.engine.util.IgniteCustomAssignmentsRules;
import org.apache.ignite.internal.sql.engine.util.IgniteResource;
-import org.apache.ignite.internal.sql.engine.util.TypeUtils;
import org.jetbrains.annotations.Nullable;
/** Implicit type cast implementation. */
@@ -465,9 +462,6 @@ public class IgniteTypeCoercion extends TypeCoercionImpl {
if (SqlTypeUtil.isIntType(fromType) && fromType.getSqlTypeName()
!= toType.getSqlTypeName()) {
return true;
}
- } else if (toType.getSqlTypeName() == SqlTypeName.ANY ||
fromType.getSqlTypeName() == SqlTypeName.ANY) {
- // IgniteCustomType: whether we need implicit cast from one type
to another.
- return TypeUtils.customDataTypeNeedCast(typeFactory, fromType,
toType);
} else if (SqlTypeUtil.isNull(fromType)) {
// Need to cast NULL literal because type-checkers of built-in
function cannot properly handle explicit NULL
// since it belongs to a particular type family.
@@ -620,46 +614,20 @@ public class IgniteTypeCoercion extends TypeCoercionImpl {
return null;
}
- // IgniteCustomType: If one of the arguments is a custom data type,
- // check whether it is possible to convert another type to it.
- // Returns not null to indicate that a CAST operation can be added
- // to convert another type to this custom data type.
- if (type1 instanceof IgniteCustomType) {
- IgniteCustomType to = (IgniteCustomType) type1;
- return tryCustomTypeCoercionRules(type2, to);
- } else if (type2 instanceof IgniteCustomType) {
- IgniteCustomType to = (IgniteCustomType) type2;
- return tryCustomTypeCoercionRules(type1, to);
- } else {
- SqlTypeName t1 = type1.getSqlTypeName();
- SqlTypeName t2 = type2.getSqlTypeName();
-
- if (t1 == SqlTypeName.TIMESTAMP && t2 ==
SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE
- || t1 == SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE && t2
== SqlTypeName.TIMESTAMP) {
- return typeFactory.leastRestrictive(List.of(type1, type2));
- } else {
- return super.commonTypeForBinaryComparison(type1, type2);
- }
- }
- }
+ SqlTypeName t1 = type1.getSqlTypeName();
+ SqlTypeName t2 = type2.getSqlTypeName();
- private @Nullable RelDataType tryCustomTypeCoercionRules(RelDataType from,
IgniteCustomType to) {
- IgniteCustomTypeCoercionRules typeCoercionRules =
typeFactory.getCustomTypeCoercionRules();
- if (typeCoercionRules.needToCast(from, to)) {
- return to;
+ if (t1 == SqlTypeName.TIMESTAMP && t2 ==
SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE
+ || t1 == SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE && t2 ==
SqlTypeName.TIMESTAMP) {
+ return typeFactory.leastRestrictive(List.of(type1, type2));
} else {
- return null;
+ return super.commonTypeForBinaryComparison(type1, type2);
}
}
private static SqlNode castTo(SqlNode node, RelDataType type) {
SqlDataTypeSpec targetDataType;
- if (type instanceof IgniteCustomType) {
- var customType = (IgniteCustomType) type;
- var nameSpec = customType.createTypeNameSpec();
-
- targetDataType = new SqlDataTypeSpec(nameSpec, SqlParserPos.ZERO);
- } else if (type.getSqlTypeName() == SqlTypeName.UUID) {
+ if (type.getSqlTypeName() == SqlTypeName.UUID) {
targetDataType = new SqlDataTypeSpec(
new SqlBasicTypeNameSpec(SqlTypeName.UUID,
SqlParserPos.ZERO), null, type.isNullable(), SqlParserPos.ZERO
);
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rex/IgniteRexBuilder.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rex/IgniteRexBuilder.java
index abc6c611815..ae08c688f1a 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rex/IgniteRexBuilder.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rex/IgniteRexBuilder.java
@@ -30,12 +30,11 @@ import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.type.SqlTypeUtil;
import org.apache.calcite.util.NlsString;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.jetbrains.annotations.Nullable;
/**
- * {@link RexBuilder} that provides support for {@link IgniteCustomType custom
data types}.
+ * Extension of {@link RexBuilder}.
*/
public class IgniteRexBuilder extends RexBuilder {
public static final IgniteRexBuilder INSTANCE = new
IgniteRexBuilder(IgniteTypeFactory.INSTANCE);
@@ -52,18 +51,6 @@ public class IgniteRexBuilder extends RexBuilder {
/** {@inheritDoc} **/
@Override
public RexNode makeLiteral(@Nullable Object value, RelDataType type,
boolean allowCast, boolean trim) {
- // We need to override this method because otherwise
- // default implementation will call RexBuilder::guessType(@Nullable
Object value)
- // for a custom data type which will then raise the following
assertion:
- //
- // throw new AssertionError("unknown type " + value.getClass());
- //
- if (value != null && type instanceof IgniteCustomType) {
- // IgniteCustomType: Not comparable types are not supported.
- assert value instanceof Comparable : "Not comparable
IgniteCustomType:" + type + ". value: " + value;
- return makeLiteral((Comparable<?>) value, type,
type.getSqlTypeName());
- }
-
if (value != null) {
if (type.getSqlTypeName() == SqlTypeName.CHAR) {
if (type.isNullable()) {
@@ -123,6 +110,7 @@ public class IgniteRexBuilder extends RexBuilder {
}
// Copy-pasted from RexBuilder.
+ @SuppressWarnings("MethodOverridesInaccessibleMethodOfSuper")
private RexNode makeCastIntervalToExact(SqlParserPos pos, RelDataType
toType, RexNode exp) {
TimeUnit endUnit = exp.getType().getSqlTypeName().getEndUnit();
TimeUnit baseUnit = baseUnit(exp.getType().getSqlTypeName());
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlTypeNameSpec.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlTypeNameSpec.java
deleted file mode 100644
index 0a703e9aadb..00000000000
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlTypeNameSpec.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.sql.engine.sql;
-
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.sql.SqlIdentifier;
-import org.apache.calcite.sql.SqlLiteral;
-import org.apache.calcite.sql.SqlTypeNameSpec;
-import org.apache.calcite.sql.SqlWriter;
-import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.util.Litmus;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Type name specification that allows to derive custom data types.
- *
- * @see org.apache.ignite.internal.sql.engine.type.IgniteCustomType
- */
-public final class IgniteSqlTypeNameSpec extends SqlTypeNameSpec {
-
- /** Undefined precision. Use the same value as apache calcite. **/
- private static final int UNDEFINED_PRECISION = -1;
-
- /** Precision, if specified. **/
- private final int precision;
-
- /**
- * Creates a {@code SqlTypeNameSpec}.
- *
- * @param name Name of the type
- * @param precision -1 if not specified.
- * @param pos Parser position, must not be null
- */
- public IgniteSqlTypeNameSpec(SqlIdentifier name, @Nullable SqlLiteral
precision, SqlParserPos pos) {
- super(name, pos);
- this.precision = precision != null ? precision.intValue(true) :
UNDEFINED_PRECISION;
- }
-
- /**
- * Creates a {@code SqlTypeNameSpec} for the specified type with undefined
precision.
- *
- * @param name Name of the type
- * @param pos Parser position, must not be null
- */
- public IgniteSqlTypeNameSpec(SqlIdentifier name, SqlParserPos pos) {
- this(name, null, pos);
- }
-
- /** {@inheritDoc} **/
- @Override
- public RelDataType deriveType(SqlValidator validator) {
- IgniteTypeFactory typeFactory = (IgniteTypeFactory)
validator.getTypeFactory();
- return typeFactory.createCustomType(getTypeName().getSimple(),
precision);
- }
-
- /** {@inheritDoc} **/
- @Override
- public void unparse(SqlWriter writer, int leftPrec, int rightPrec) {
- writer.keyword(getTypeName().getSimple());
-
- if (precision != -1) {
- SqlWriter.Frame frame =
writer.startList(SqlWriter.FrameTypeEnum.FUN_CALL, "(", ")");
- writer.print(precision);
- writer.endList(frame);
- }
- }
-
- /** {@inheritDoc} **/
- @Override
- public boolean equalsDeep(SqlTypeNameSpec spec, Litmus litmus) {
- if (!(spec instanceof IgniteSqlTypeNameSpec)) {
- return litmus.fail("{} != {}", this, spec);
- } else {
- IgniteSqlTypeNameSpec that = (IgniteSqlTypeNameSpec) spec;
- if (that.precision != precision) {
- return litmus.fail("{} != {}", this, spec);
- }
- return litmus.succeed();
- }
- }
-}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/IgniteSqlOperatorTable.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/IgniteSqlOperatorTable.java
index dd8edff3533..b34f59d1a0b 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/IgniteSqlOperatorTable.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/IgniteSqlOperatorTable.java
@@ -58,9 +58,6 @@ public class IgniteSqlOperatorTable extends
ReflectiveSqlOperatorTable {
private static final SqlSingleOperandTypeChecker SAME_SAME =
new SameFamilyOperandTypeChecker(2);
- private static final SqlSingleOperandTypeChecker NOT_CUSTOM_TYPE =
- new NotCustomTypeOperandTypeChecker();
-
private static final SqlOperandTypeChecker DATETIME_MATCHING_INTERVAL =
new SqlDateTimeIntervalTypeChecker(true);
@@ -70,22 +67,22 @@ public class IgniteSqlOperatorTable extends
ReflectiveSqlOperatorTable {
private static final SqlOperandTypeChecker PLUS_OPERATOR_TYPES_CHECKER =
OperandTypes.NUMERIC_NUMERIC.and(SAME_SAME)
.or(OperandTypes.INTERVAL_SAME_SAME)
- .or(DATETIME_MATCHING_INTERVAL.and(NOT_CUSTOM_TYPE))
- .or(MATCHING_INTERVAL_DATETIME.and(NOT_CUSTOM_TYPE));
+ .or(DATETIME_MATCHING_INTERVAL)
+ .or(MATCHING_INTERVAL_DATETIME);
private static final SqlOperandTypeChecker MINUS_OPERATOR_TYPES_CHECKER =
OperandTypes.NUMERIC_NUMERIC.and(SAME_SAME)
.or(OperandTypes.INTERVAL_SAME_SAME)
-
.or(OperandTypes.DATETIME_INTERVAL.and(DATETIME_MATCHING_INTERVAL).and(NOT_CUSTOM_TYPE));
+
.or(OperandTypes.DATETIME_INTERVAL.and(DATETIME_MATCHING_INTERVAL));
private static final SqlSingleOperandTypeChecker
DIVISION_OPERATOR_TYPES_CHECKER =
OperandTypes.NUMERIC_NUMERIC.and(SAME_SAME)
- .or(OperandTypes.INTERVAL_NUMERIC.and(NOT_CUSTOM_TYPE));
+ .or(OperandTypes.INTERVAL_NUMERIC);
public static final SqlSingleOperandTypeChecker
MULTIPLY_OPERATOR_TYPES_CHECKER =
OperandTypes.NUMERIC_NUMERIC.and(SAME_SAME)
- .or(OperandTypes.INTERVAL_NUMERIC.and(NOT_CUSTOM_TYPE))
- .or(OperandTypes.NUMERIC_INTERVAL.and(NOT_CUSTOM_TYPE));
+ .or(OperandTypes.INTERVAL_NUMERIC)
+ .or(OperandTypes.NUMERIC_INTERVAL);
public static final SqlFunction LENGTH =
new SqlFunction(
@@ -458,13 +455,13 @@ public class IgniteSqlOperatorTable extends
ReflectiveSqlOperatorTable {
* {@code EVERY} aggregate function.
*/
public static final SqlAggFunction EVERY =
- new SqlMinMaxAggFunction("EVERY", SqlKind.MIN,
OperandTypes.BOOLEAN.and(NOT_CUSTOM_TYPE));
+ new SqlMinMaxAggFunction("EVERY", SqlKind.MIN,
OperandTypes.BOOLEAN);
/**
* {@code SOME} aggregate function.
*/
public static final SqlAggFunction SOME =
- new SqlMinMaxAggFunction("SOME", SqlKind.MAX,
OperandTypes.BOOLEAN.and(NOT_CUSTOM_TYPE));
+ new SqlMinMaxAggFunction("SOME", SqlKind.MAX,
OperandTypes.BOOLEAN);
/**
* The <code>CURRENT_TIMESTAMP [(<i>precision</i>)]</code> function.
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/NotCustomTypeOperandTypeChecker.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/NotCustomTypeOperandTypeChecker.java
deleted file mode 100644
index 35116dca71f..00000000000
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/fun/NotCustomTypeOperandTypeChecker.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.sql.engine.sql.fun;
-
-import org.apache.calcite.sql.SqlCallBinding;
-import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.SqlOperator;
-import org.apache.calcite.sql.type.SqlSingleOperandTypeChecker;
-import org.apache.ignite.internal.schema.AssemblyException;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
-
-/**
- * Type checking strategy which makes sure there are no operands of custom
types.
- */
-public class NotCustomTypeOperandTypeChecker implements
SqlSingleOperandTypeChecker {
- /*
- By default, type checkers allows operands of type ANY. The problem is that
it in fact may
- represent custom type rather than be placeholder for any possible value.
This type checker
- makes sure that operand of type ANY is indeed placeholder for any type
rather than operand
- of a custom type.
- */
-
- @Override
- public boolean checkSingleOperandType(SqlCallBinding callBinding, SqlNode
operand, int operandIdx, boolean throwOnFailure) {
- return !(callBinding.getOperandType(operandIdx) instanceof
IgniteCustomType);
- }
-
- @Override
- public boolean checkOperandTypes(SqlCallBinding callBinding, boolean
throwOnFailure) {
- for (int i = 0; i < callBinding.getOperandCount(); i++) {
- if (!checkSingleOperandType(callBinding, callBinding.operand(i),
i, throwOnFailure)) {
- return false;
- }
- }
-
- return true;
- }
-
- @Override
- public String getAllowedSignatures(SqlOperator op, String opName) {
- throw new AssemblyException("Should not be called");
- }
-}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java
deleted file mode 100644
index 7ab9711dad1..00000000000
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomType.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.sql.engine.type;
-
-import org.apache.calcite.rel.type.RelDataTypeFamily;
-import org.apache.calcite.rel.type.RelDataTypeImpl;
-import org.apache.calcite.sql.SqlIdentifier;
-import org.apache.calcite.sql.SqlLiteral;
-import org.apache.calcite.sql.SqlNumericLiteral;
-import org.apache.calcite.sql.SqlTypeNameSpec;
-import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.type.SqlTypeFamily;
-import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.ignite.internal.sql.engine.exec.exp.agg.Accumulators;
-import org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator;
-import org.apache.ignite.internal.sql.engine.sql.IgniteSqlTypeNameSpec;
-
-/**
- * A base class for custom data types.
- *
- * <p><b>Custom data type implementation check list.</b>
- *
- * <p>Create a subclass of {@link IgniteCustomType}.
- *
- * <p>Define {@link IgniteCustomTypeSpec type spec} for your type that
describes the following properties:
- * <ul>
- * <li>{@link IgniteCustomTypeSpec#typeName() type name}.</li>
- * <li>{@link IgniteCustomTypeSpec#nativeType() native type}.</li>
- * <li>{@link IgniteCustomTypeSpec#columnType() column type}.</li>
- * <li>{@link IgniteCustomTypeSpec#storageType() storage type}.</li>
- * <li>{@link IgniteCustomTypeSpec#castFunction() cast function}.
- * See {@link IgniteCustomTypeSpec#getCastFunction(Class, String)
getCastFunction}.
- * </li>
- * </ul>
- *
- * <p>Code base contains comments that start with {@code IgniteCustomType:} to
provide extra information.
- *
- * <p>Update {@link IgniteTypeFactory}'s constructor to register your type and
to specify type coercion rules.
- *
- * <p>Update type inference for dynamic parameters in {@link
IgniteSqlValidator}.
- *
- * <p>Further steps:
- * <ul>
- * <li>Update an SQL parser generator code to support your type - see
{@code DataTypeEx()}.</li>
- * <li>Update {@link Accumulators}
- * if your type supports some aggregation functions.
- * By default all custom data type support {@code COUNT} and {@code
ANY_VALUE}.</li>
- * <li>Update serialisation/deserialisation in {@code RelJson} to store
extra attributes if necessary.</li>
- * <li>There probably some methods in {@link IgniteTypeSystem} that maybe
subject to change
- * when a custom data type is implemented.</li>
- * </ul>
- *
- * <p>Type conversion is implemented in {@code CustomTypesConversion} and uses
rules defined for your custom type.
- *
- * <p>Client code/JDBC:
- * <ul>
- * <li>Update {@code JdbcDatabaseMetadata::getTypeInfo} to return
information about your type.</li>
- * <li>Update {@code JdbcColumnMeta::typeName} to return the correct name
for your time.</li>
- * </ul>
- *
- * <p><b>Update this documentation when you are going to change this
procedure.</b>
- *
-*/
-public abstract class IgniteCustomType extends RelDataTypeImpl {
-
- private final IgniteCustomTypeSpec spec;
-
- private final boolean nullable;
-
- private final int precision;
-
- /** Constructor. */
- protected IgniteCustomType(IgniteCustomTypeSpec spec, boolean nullable,
int precision) {
- this.spec = spec;
- this.nullable = nullable;
- this.precision = precision;
-
- computeDigest();
- }
-
- /** Returns the name of this type. A short handfor {@code
spec().typeName() }. **/
- public final String getCustomTypeName() {
- return spec.typeName();
- }
-
- /**
- * Returns the {@link IgniteCustomTypeSpec specification} of this type.
- */
- public final IgniteCustomTypeSpec spec() {
- return spec;
- }
-
- /** {@inheritDoc} */
- @Override public final boolean isNullable() {
- return nullable;
- }
-
- /** {@inheritDoc} */
- @Override public RelDataTypeFamily getFamily() {
- return SqlTypeFamily.ANY;
- }
-
- /** {@inheritDoc} */
- @Override public final SqlTypeName getSqlTypeName() {
- return SqlTypeName.ANY;
- }
-
- /** {@inheritDoc} */
- @Override
- public final int getPrecision() {
- return precision;
- }
-
- /** Creates an instance of this type with the specified nullability. **/
- public abstract IgniteCustomType createWithNullability(boolean nullable);
-
- /**
- * Creates an {@link SqlTypeNameSpec} for this custom data type, which is
used as an argument for the CAST function.
- *
- * @return An SQL type name spec.
- */
- public final SqlTypeNameSpec createTypeNameSpec() {
- SqlIdentifier typeNameId = new SqlIdentifier(getCustomTypeName(),
SqlParserPos.ZERO);
-
- if (getPrecision() == PRECISION_NOT_SPECIFIED) {
- return new IgniteSqlTypeNameSpec(typeNameId, SqlParserPos.ZERO);
- } else {
- SqlNumericLiteral precision =
SqlLiteral.createExactNumeric(Integer.toString(getPrecision()),
SqlParserPos.ZERO);
-
- return new IgniteSqlTypeNameSpec(typeNameId, precision,
SqlParserPos.ZERO);
- }
- }
-}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomTypeCoercionRules.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomTypeCoercionRules.java
deleted file mode 100644
index d74dc14ff44..00000000000
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomTypeCoercionRules.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.sql.engine.type;
-
-import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.calcite.sql.validate.implicit.TypeCoercion;
-import org.apache.ignite.internal.sql.engine.prepare.IgniteTypeCoercion;
-
-/**
- * Defines rules for coercing {@link SqlTypeName built-in SQL types} to {@link
IgniteCustomType custom data types}.
- *
- * @see IgniteTypeCoercion ignite type coercion.
- * @see TypeCoercion calcite's TypeCoercion interface.
- */
-public final class IgniteCustomTypeCoercionRules {
-
- private final Map<String, Set<SqlTypeName>> canCastFrom;
-
- IgniteCustomTypeCoercionRules(Map<String, IgniteCustomTypeSpec> typeSpecs,
Map<String, Set<SqlTypeName>> canCastFrom) {
- for (var rule : canCastFrom.entrySet()) {
- var typeName = rule.getKey();
- if (!typeSpecs.containsKey(typeName)) {
- var error = format("Unable to define type coercion rule. "
- + "Unexpected custom type: {}. Rules: {}. Known types:
{}", typeName, rule.getValue(), typeSpecs.keySet()
- );
- throw new IllegalArgumentException(error);
- }
- }
-
- this.canCastFrom = canCastFrom;
- }
-
- /**
- * Checks whether the cast operation is needed to convert {@code fromType}
to the custom type {@code toType}.
- *
- * <p>NOTE: <b>This method returns {@code false}, when called with the
same argument as both parameters, because
- * there is no need to add casts between the same types.</b>
- *
- * @param fromType Source data type.
- * @param toType Target custom data type.
- */
- public boolean needToCast(RelDataType fromType, IgniteCustomType toType) {
- // The implementation of this method must always use
::canCastFrom(typeName),
- // because canCastFrom is can be used to generate rules for runtime
execution.
- var rules = canCastFrom(toType.getCustomTypeName());
-
- return rules.contains(fromType.getSqlTypeName());
- }
-
- /** Returns a set of built-in SQL types the given custom type can be
converted from. **/
- public Set<SqlTypeName> canCastFrom(String typeName) {
- return canCastFrom.getOrDefault(typeName, Collections.emptySet());
- }
-
- /** Creates a builder to define a table of type coercion rules. **/
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * A builder for {@link IgniteCustomTypeCoercionRules}.
- */
- public static class Builder {
-
- private final Map<String, Set<SqlTypeName>> canCastFrom = new
HashMap<>();
-
- Builder() {
-
- }
-
- /**
- * Adds a rule that allows cast from the given custom type to the
specified built-in SQL type.
- */
- public Builder addRule(String typeName, SqlTypeName to) {
- var rules = canCastFrom.computeIfAbsent(typeName, (k) ->
EnumSet.noneOf(SqlTypeName.class));
- rules.add(to);
- return this;
- }
-
- /**
- * Adds rules that allow casts from the given custom type to the
specified built-in SQL types.
- */
- public Builder addRules(String typeName, Collection<SqlTypeName>
typeNames) {
- var rules = canCastFrom.computeIfAbsent(typeName, (k) ->
EnumSet.noneOf(SqlTypeName.class));
- rules.addAll(typeNames);
- return this;
- }
-
- /**
- * Builds a table of type coercion rules for the given custom data
types.
- *
- * @param typeSpecs A map of custom type specs.
- * @return A table of type coercion rules.
- *
- * @throws IllegalArgumentException if a this builder contains rules
for custom types not present in {@code typeSpecs}.
- */
- public IgniteCustomTypeCoercionRules build(Map<String,
IgniteCustomTypeSpec> typeSpecs) {
- return new IgniteCustomTypeCoercionRules(typeSpecs, canCastFrom);
- }
- }
-}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomTypeSpec.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomTypeSpec.java
deleted file mode 100644
index 3641c8af36e..00000000000
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteCustomTypeSpec.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.sql.engine.type;
-
-import java.lang.reflect.Method;
-import java.util.Objects;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.ignite.internal.sql.engine.exec.ExecutionServiceImpl;
-import org.apache.ignite.internal.sql.engine.exec.exp.ExpressionFactoryImpl;
-import org.apache.ignite.internal.tostring.S;
-import org.apache.ignite.internal.type.NativeType;
-import org.apache.ignite.sql.ColumnMetadata;
-import org.apache.ignite.sql.ColumnType;
-
-/**
- * Specification that defines properties of a {@link IgniteCustomType custom
data type} that are shared by all instances of that type.
- *
- * @see IgniteCustomType custom data type.
- */
-public final class IgniteCustomTypeSpec {
-
- private final String typeName;
-
- private final NativeType nativeType;
-
- private final ColumnType columnType;
-
- private final Class<?> storageType;
-
- private final Method castFunction;
-
- /**
- * Creates a specification for a type that with the specified {@code
storage type}.
- *
- * @param typeName Type name.
- * @param nativeType Native type.
- * @param columnType Column type.
- * @param storageType Storage type.
- * @param castFunction Cast function.
- */
- public IgniteCustomTypeSpec(String typeName, NativeType nativeType,
ColumnType columnType,
- Class<? extends Comparable<?>> storageType, Method castFunction) {
-
- this.typeName = typeName;
- this.nativeType = nativeType;
- this.columnType = columnType;
- this.storageType = storageType;
- this.castFunction = castFunction;
- }
-
- /** Returns the name of the type. */
- public String typeName() {
- return typeName;
- }
-
- /**
- * Returns the {@link NativeType} for this custom data type.
- *
- * <p>At the moment it serves the following purpose:
- * <ul>
- * <li>
- * Used by {@link
IgniteTypeFactory#relDataTypeToNative(RelDataType)} to retrieve underlying
- * {@link NativeType} for DDL queries.
- * </li>
- * <li>
- * To retrieve a java type to perform type conversions by
- * {@link ExecutionServiceImpl}.
- * </li>
- * </ul>
- */
- public NativeType nativeType() {
- return nativeType;
- }
-
- /**
- * Returns the {@link ColumnType} of this data type. Provides type
information for {@link ColumnMetadata}.
- */
- public ColumnType columnType() {
- return columnType;
- }
-
- /**
- * Returns the storage type of this data type.
- *
- * <p>This method is called by {@link
IgniteTypeFactory#getJavaClass(RelDataType)} to provide types for a expression
interpreter.
- *
- * @see ExpressionFactoryImpl
- */
- public Class<?> storageType() {
- return storageType;
- }
-
- /** Implementation of a cast function for this type. */
- public Method castFunction() {
- return castFunction;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- IgniteCustomTypeSpec that = (IgniteCustomTypeSpec) o;
- return typeName.equals(that.typeName) &&
nativeType.equals(that.nativeType) && storageType.equals(that.storageType)
- && columnType == that.columnType;
- }
-
- /**
- * Returns a method that implements a cast function for a custom data type.
- *
- * <p>Requirements:
- * <ul>
- * <li>It must be a {@code public static} method.</li>
- * <li>It must have the following signature: {@code Object ->
typeSpec::nativeType.javaClass}.</li>
- * <li>It must implement conversion from the type itself.</li>
- * <li>It must implement conversion from String to {@code
typeSpec::nativeType.javaClass}.</li>
- * </ul>
- *
- * @param clazz A class that defines a cast function.
- * @param method A name of a method.
- * @return A method that implements a cast function.
- */
- public static Method getCastFunction(Class<?> clazz, String method) {
- try {
- return clazz.getMethod(method, Object.class);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException("Incorrect cast function
method: " + method, e);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- return Objects.hash(typeName, nativeType, storageType, columnType);
- }
-
- /** {@inheritDoc} */
- @Override
- public String toString() {
- return S.toString(IgniteCustomTypeSpec.class, this);
- }
-}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteTypeFactory.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteTypeFactory.java
index a784a2cad48..570fc8e947b 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteTypeFactory.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/type/IgniteTypeFactory.java
@@ -33,17 +33,12 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
-import java.util.Collection;
-import java.util.EnumSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Objects;
-import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;
-import java.util.stream.Collectors;
import org.apache.calcite.avatica.util.ByteString;
import org.apache.calcite.avatica.util.TimeUnit;
import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
@@ -82,9 +77,6 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl {
/** Default charset. */
private final Charset charset;
- /** A registry that contains custom data types. **/
- private final CustomDataTypes customDataTypes;
-
{
implementedJavaTypes.put(LocalDate.class, () ->
createTypeWithNullability(createSqlType(SqlTypeName.DATE),
true));
@@ -115,8 +107,6 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl {
// If JVM default charset is not supported by Calcite - use UTF-8.
charset = StandardCharsets.UTF_8;
}
-
- customDataTypes = new CustomDataTypes(Set.of());
}
/** {@inheritDoc} */
@@ -173,7 +163,7 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl {
public Type getJavaClass(RelDataType type) {
if (type instanceof JavaType) {
return ((JavaType) type).getJavaClass();
- } else if (type instanceof BasicSqlType || type instanceof
IntervalSqlType || type instanceof IgniteCustomType) {
+ } else if (type instanceof BasicSqlType || type instanceof
IntervalSqlType) {
switch (type.getSqlTypeName()) {
case VARCHAR:
case CHAR:
@@ -221,11 +211,6 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl
{
case SYMBOL:
return Enum.class;
case ANY:
- if (type instanceof IgniteCustomType) {
- var customType = (IgniteCustomType) type;
- return customType.spec().storageType();
- }
- // fallthrough
case OTHER:
return Object.class;
case NULL:
@@ -257,8 +242,7 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl {
*/
public static NativeType relDataTypeToNative(RelDataType relType) {
assert relType instanceof BasicSqlType
- || relType instanceof IntervalSqlType
- || relType instanceof IgniteCustomType : "Not supported:" +
relType;
+ || relType instanceof IntervalSqlType : "Not supported:" +
relType;
switch (relType.getSqlTypeName()) {
case BOOLEAN:
@@ -319,11 +303,6 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl
{
case UUID:
return NativeTypes.UUID;
case ANY:
- if (relType instanceof IgniteCustomType) {
- var customType = (IgniteCustomType) relType;
- return customType.spec().nativeType();
- }
- // fallthrough
default:
throw new IllegalArgumentException("Type is not supported: " +
relType);
}
@@ -346,7 +325,7 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl {
public Type getResultClass(RelDataType type) {
if (type instanceof JavaType) {
return ((JavaType) type).getJavaClass();
- } else if (type instanceof BasicSqlType || type instanceof
IntervalSqlType || type instanceof IgniteCustomType) {
+ } else if (type instanceof BasicSqlType || type instanceof
IntervalSqlType) {
switch (type.getSqlTypeName()) {
case VARCHAR:
case CHAR:
@@ -400,12 +379,6 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl
{
case SYMBOL:
return Enum.class;
case ANY:
- if (type instanceof IgniteCustomType) {
- var customType = (IgniteCustomType) type;
- var nativeType = customType.spec().nativeType();
- return nativeType.spec().javaClass();
- }
- // fallthrough
case OTHER:
return Object.class;
case NULL:
@@ -445,13 +418,10 @@ public class IgniteTypeFactory extends
JavaTypeFactoryImpl {
return first(types);
}
- IgniteCustomType firstCustomType = null;
boolean hasAnyType = false;
boolean hasNullOrNullable = false;
boolean hasUuidType = false;
boolean hasBuiltInType = false;
- boolean hasNullable = false;
- IgniteCustomType firstNullable = null;
for (var type : types) {
SqlTypeName sqlTypeName = type.getSqlTypeName();
@@ -465,23 +435,7 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl
{
hasNullOrNullable = true;
}
- if (type instanceof IgniteCustomType) {
- if (firstCustomType == null) {
- firstCustomType = (IgniteCustomType) type;
- } else {
- IgniteCustomType customType = (IgniteCustomType) type;
- if (!Objects.equals(firstCustomType.getCustomTypeName(),
customType.getCustomTypeName())) {
- // IgniteCustomType: Conversion between custom data
types is not supported.
- return null;
- }
- }
-
- if (type.isNullable() && firstNullable == null) {
- hasNullable = type.isNullable();
- firstNullable = (IgniteCustomType) type;
- }
-
- } else if (sqlTypeName == SqlTypeName.ANY) {
+ if (sqlTypeName == SqlTypeName.ANY) {
hasAnyType = true;
} else {
if (sqlTypeName == SqlTypeName.UUID) {
@@ -534,19 +488,10 @@ public class IgniteTypeFactory extends
JavaTypeFactoryImpl {
// when at least one of its arguments have sqlTypeName = ANY.
assert resultType instanceof BasicSqlType : "leastRestrictive is
expected to return a new instance of a type: " + resultType;
- if (hasAnyType && hasBuiltInType && firstCustomType != null) {
- // There is no least restrictive type between ANY, built-in type,
and a custom data type.
- return null;
- } else if ((hasAnyType && hasBuiltInType) || (hasAnyType &&
firstCustomType != null)) {
+ if (hasAnyType && hasBuiltInType) {
// When at least one of arguments have sqlTypeName = ANY,
// return it in order to be consistent with default implementation.
return resultType;
- } else if (firstCustomType != null && !hasBuiltInType) {
- // When there is only one custom data type and no other built-in
types,
- // return the custom data type.
- // We must return a nullable type, when there are nullable and
not-nullable types,
- // because nullable type is less restrictive than not-nullable.
- return hasNullable ? firstNullable : firstCustomType;
} else {
return null;
}
@@ -647,76 +592,12 @@ public class IgniteTypeFactory extends
JavaTypeFactoryImpl {
//noinspection SuspiciousMethodCalls
if (implementedJavaTypes.containsKey(type)) {
return createJavaType((Class<?>) type);
- } else if (customDataTypes.javaTypes.contains(type)) {
- throw new IllegalArgumentException("Custom data type should not be
created via createType call: " + type);
} else {
return super.createType(type);
}
}
- /** {@inheritDoc} **/
- @Override
- public RelDataType createTypeWithNullability(RelDataType type, boolean
nullable) {
- if (type instanceof IgniteCustomType) {
- return canonize(((IgniteCustomType)
type).createWithNullability(nullable));
- } else {
- return super.createTypeWithNullability(type, nullable);
- }
- }
-
- /** {@inheritDoc} **/
- @Override
- public RelDataType createJavaType(Class clazz) {
- if (customDataTypes.javaTypes.contains(clazz)) {
- throw new IllegalArgumentException("Custom data type should not be
created via createJavaType call: " + clazz);
- } else {
- return super.createJavaType(clazz);
- }
- }
-
- /**
- * Creates a custom data type with the given {@code typeName} and
precision.
- *
- * @param typeName Type name.
- * @param precision Precision if supported.
- * @return A custom data type.
- */
- public IgniteCustomType createCustomType(String typeName, int precision) {
- IgniteCustomTypeFactory customTypeFactory =
customDataTypes.typeFactories.get(typeName);
- if (customTypeFactory == null) {
- throw new IllegalArgumentException("Unexpected custom data type: "
+ typeName);
- }
-
- // By default a type must not be nullable.
- // See SqlTypeFactory::createSqlType.
- IgniteCustomType customType = customTypeFactory.newType(false,
precision);
- assert !customType.isNullable() : "makeCustomType must not return a
nullable type: " + typeName + " " + customType;
- return (IgniteCustomType) canonize(customType);
- }
-
- /**
- * Creates a custom data type with the given {@code typeName} and without
precision.
- *
- * <p>A shorthand for {@code createCustomType(typeName, -1)}.
- *
- * @param typeName Type name.
- * @return A custom data type.
- */
- public IgniteCustomType createCustomType(String typeName) {
- return createCustomType(typeName, PRECISION_NOT_SPECIFIED);
- }
-
- /** Returns {@link IgniteCustomTypeSpec type specifications} of registered
custom data types. */
- public Map<String, IgniteCustomTypeSpec> getCustomTypeSpecs() {
- return customDataTypes.typeSpecs;
- }
-
- /** Returns type coercion rules to custom data types. */
- public IgniteCustomTypeCoercionRules getCustomTypeCoercionRules() {
- return customDataTypes.typeCoercionRules;
- }
-
- private boolean allEquals(List<RelDataType> types) {
+ private static boolean allEquals(List<RelDataType> types) {
assert types.size() > 1;
RelDataType first = first(types);
@@ -728,68 +609,4 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl
{
return true;
}
-
- private static final class CustomDataTypes {
-
- /**
- * Contains java types used by registered custom data types.
- *
- * <p>We need those to reject attempts to create custom data types via
- * {@link IgniteTypeFactory#createType(Type)}/{@link
IgniteTypeFactory#createJavaType(Class)}
- * methods of {@link IgniteTypeFactory}.
- */
- private final Set<Type> javaTypes;
-
- /**
- * Stores functions that are being used by {@link
#createCustomType(String, int)} to create type instances.
- */
- private final Map<String, IgniteCustomTypeFactory> typeFactories;
-
- private final Map<String, IgniteCustomTypeSpec> typeSpecs;
-
- private final IgniteCustomTypeCoercionRules typeCoercionRules;
-
- CustomDataTypes(Set<NewCustomType> customDataTypes) {
- this.javaTypes = customDataTypes.stream()
- .map(t -> t.spec.storageType())
- .collect(Collectors.toSet());
-
- this.typeSpecs = customDataTypes.stream()
- .map(t -> Map.entry(t.spec.typeName(), t.spec))
- .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
-
- this.typeFactories =
customDataTypes.stream().collect(Collectors.toMap((v) -> v.spec.typeName(), (v)
-> v.typeFactory));
-
- var builder = IgniteCustomTypeCoercionRules.builder();
- for (var newType : customDataTypes) {
- builder.addRules(newType.spec.typeName(),
newType.canBeCoercedTo);
- }
- this.typeCoercionRules = builder.build(typeSpecs);
- }
- }
-
- private static final class NewCustomType {
- final IgniteCustomTypeSpec spec;
-
- final IgniteCustomTypeFactory typeFactory;
-
- final Set<SqlTypeName> canBeCoercedTo =
EnumSet.noneOf(SqlTypeName.class);
-
- NewCustomType(IgniteCustomTypeSpec spec, IgniteCustomTypeFactory
typeFactory) {
- this.spec = spec;
- this.typeFactory = typeFactory;
- }
-
- /**
- * Adds a type coercion rule to from the given built-in SQL types to
this custom data type.
- */
- void addCoercionRules(Collection<SqlTypeName> types) {
- canBeCoercedTo.addAll(types);
- }
- }
-
- @FunctionalInterface
- interface IgniteCustomTypeFactory {
- IgniteCustomType newType(boolean nullable, int precision);
- }
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/SafeCustomTypeInternalConversion.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/SafeCustomTypeInternalConversion.java
deleted file mode 100644
index ca278219033..00000000000
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/SafeCustomTypeInternalConversion.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.internal.sql.engine.util;
-
-import java.util.EnumMap;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomTypeSpec;
-import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.sql.ColumnType;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * The sole purpose of this class is to provide safe-conversion to and from
internal types,
- * preventing class cast exceptions inside when using {@link TypeUtils}
methods for to/from type conversion.
- */
-final class SafeCustomTypeInternalConversion {
-
- static final SafeCustomTypeInternalConversion INSTANCE = new
SafeCustomTypeInternalConversion(Commons.typeFactory());
-
- private final EnumMap<ColumnType, Class<?>> internalTypes = new
EnumMap<>(ColumnType.class);
-
- private SafeCustomTypeInternalConversion(IgniteTypeFactory typeFactory) {
- // IgniteCustomType: We can automatically compute val -> internal type
mapping
- // by using type specs from the type factory.
- var customTypes = typeFactory.getCustomTypeSpecs();
-
- for (IgniteCustomTypeSpec t : customTypes.values()) {
- internalTypes.put(t.nativeType().spec(), t.storageType());
- }
- }
-
- @Nullable
- Object tryConvertToInternal(Object val, ColumnType storageType) {
- Class<?> internalType = internalTypes.get(storageType);
-
- assert internalType == null || internalType.isInstance(val) :
storageTypeMismatch(val, internalType);
-
- return val;
- }
-
- Object tryConvertFromInternal(Object val, ColumnType storageType) {
- Class<?> internalType = internalTypes.get(storageType);
-
- assert internalType == null || internalType.isInstance(val) :
storageTypeMismatch(val, internalType);
-
- return val;
- }
-
- private static String storageTypeMismatch(Object value, Class<?> type) {
- return String.format("storageType is %s value must also be %s but it
was: %s", type, type, 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 368ef3d4033..e3c7c85d806 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
@@ -20,7 +20,7 @@ package org.apache.ignite.internal.sql.engine.util;
import static org.apache.calcite.sql.type.SqlTypeName.BINARY_TYPES;
import static org.apache.calcite.sql.type.SqlTypeName.CHAR_TYPES;
import static org.apache.calcite.sql.type.SqlTypeName.STRING_TYPES;
-import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
+import static
org.apache.ignite.internal.sql.engine.util.IgniteMath.convertToIntExact;
import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_VALIDATION_ERR;
import java.lang.reflect.Type;
@@ -38,7 +38,6 @@ import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -67,8 +66,6 @@ import
org.apache.ignite.internal.sql.engine.exec.row.RowSchemaTypes;
import org.apache.ignite.internal.sql.engine.exec.row.RowType;
import org.apache.ignite.internal.sql.engine.exec.row.TypeSpec;
import org.apache.ignite.internal.sql.engine.prepare.ParameterType;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
-import
org.apache.ignite.internal.sql.engine.type.IgniteCustomTypeCoercionRules;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.type.DecimalNativeType;
import org.apache.ignite.internal.type.NativeType;
@@ -353,16 +350,13 @@ public class TypeUtils {
case BOOLEAN:
assert val instanceof Boolean : val.getClass();
return val;
- // TODO https://issues.apache.org/jira/browse/IGNITE-23295 Support
native types for DURATION and PERIOD
- // case DURATION:
- // return TimeUnit.SECONDS.toMillis(((Duration)
val).getSeconds())
- // + TimeUnit.NANOSECONDS.toMillis(((Duration)
val).getNano());
- // case PREIOD:
- // return (int) ((Period) val).toTotalMonths();
+ case DURATION:
+ return ((Duration) val).toMillis();
+ case PERIOD:
+ return convertToIntExact(((Period) val).toTotalMonths());
default: {
- var customType =
SafeCustomTypeInternalConversion.INSTANCE.tryConvertToInternal(val, spec);
- return customType != null ? customType : val;
+ throw new AssertionError("Type is not supported: " + spec);
}
}
}
@@ -408,6 +402,7 @@ public class TypeUtils {
case DECIMAL:
case UUID:
case STRING:
+ case BOOLEAN:
return val;
case BYTE_ARRAY:
return ((ByteString) val).getBytes();
@@ -419,8 +414,6 @@ public class TypeUtils {
return LocalDateTime.ofInstant(Instant.ofEpochMilli((Long)
val), ZoneOffset.UTC);
case TIMESTAMP:
return Instant.ofEpochMilli((Long) val);
- case BOOLEAN:
- return val;
case DURATION: {
assert val instanceof Long;
return Duration.ofMillis((Long) val);
@@ -430,7 +423,7 @@ public class TypeUtils {
return Period.of((Integer) val / 12, (Integer) val % 12, 0);
}
default: {
- return
SafeCustomTypeInternalConversion.INSTANCE.tryConvertFromInternal(val, spec);
+ throw new AssertionError("Type is not supported: " + spec);
}
}
}
@@ -472,11 +465,6 @@ public class TypeUtils {
case BINARY:
case VARBINARY:
case ANY:
- if (type instanceof IgniteCustomType) {
- IgniteCustomType customType = (IgniteCustomType) type;
- return customType.spec().columnType();
- }
- // fallthrough
case OTHER:
return ColumnType.BYTE_ARRAY;
case INTERVAL_YEAR:
@@ -673,25 +661,6 @@ public class TypeUtils {
return true;
}
- /**
- * Checks whether one type can be casted to another if one of type is a
custom data type.
- *
- * <p>This method expects at least one of its arguments to be a custom
data type.
- */
- public static boolean customDataTypeNeedCast(IgniteTypeFactory factory,
RelDataType fromType, RelDataType toType) {
- IgniteCustomTypeCoercionRules typeCoercionRules =
factory.getCustomTypeCoercionRules();
- if (toType instanceof IgniteCustomType) {
- IgniteCustomType to = (IgniteCustomType) toType;
- return typeCoercionRules.needToCast(fromType, to);
- } else if (fromType instanceof IgniteCustomType) {
- boolean sameType = SqlTypeUtil.equalSansNullability(fromType,
toType);
- return !sameType;
- } else {
- String message = format("Invalid arguments. Expected at least one
custom data type but got {} and {}", fromType, toType);
- throw new AssertionError(message);
- }
- }
-
/**
* Checks that {@code toType} and {@code fromType} have compatible type
families taking into account custom data types. Types {@code T1}
* and {@code T2} have compatible type families if {@code T1} can be
assigned to {@code T2} and vice-versa.
@@ -726,20 +695,8 @@ public class TypeUtils {
return true;
}
- if (fromType instanceof IgniteCustomType && toType instanceof
IgniteCustomType) {
- IgniteCustomType fromCustom = (IgniteCustomType) fromType;
- IgniteCustomType toCustom = (IgniteCustomType) toType;
-
- // IgniteCustomType: different custom data types are not
compatible.
- return Objects.equals(fromCustom.getCustomTypeName(),
toCustom.getCustomTypeName());
- } else if (fromType instanceof IgniteCustomType || toType instanceof
IgniteCustomType) {
- // IgniteCustomType: custom data types are not compatible with
other types.
- return false;
- } else if (SqlTypeUtil.canAssignFrom(toType, fromType)) {
- return SqlTypeUtil.canAssignFrom(fromType, toType);
- } else {
- return false;
- }
+ return SqlTypeUtil.canAssignFrom(toType, fromType)
+ && SqlTypeUtil.canAssignFrom(fromType, toType);
}
/**
@@ -799,10 +756,7 @@ public class TypeUtils {
boolean simpleType = type instanceof BasicSqlType;
boolean nullable = type.isNullable();
- if (type instanceof IgniteCustomType) {
- NativeType nativeType =
IgniteTypeFactory.relDataTypeToNative(type);
- return RowSchemaTypes.nativeTypeWithNullability(nativeType,
nullable);
- } else if (SqlTypeName.ANY == type.getSqlTypeName()) {
+ if (SqlTypeName.ANY == type.getSqlTypeName()) {
// TODO Some JSON functions that return ANY as well :
https://issues.apache.org/jira/browse/IGNITE-20163
return new BaseTypeSpec(null, nullable);
} else if (SqlTypeUtil.isNull(type)) {
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/LeastRestrictiveTypesTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/LeastRestrictiveTypesTest.java
index 55454714d24..7ae53bde1ef 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/LeastRestrictiveTypesTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/LeastRestrictiveTypesTest.java
@@ -18,7 +18,6 @@
package org.apache.ignite.internal.sql.engine.prepare;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
import java.util.ArrayList;
import java.util.Arrays;
@@ -26,14 +25,9 @@ import java.util.List;
import java.util.stream.Stream;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
-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.util.Commons;
-import org.apache.ignite.internal.type.NativeTypes;
-import org.apache.ignite.sql.ColumnType;
import org.jetbrains.annotations.Nullable;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@@ -63,15 +57,9 @@ public class LeastRestrictiveTypesTest {
private static final RelDataType VARCHAR =
TYPE_FACTORY.createSqlType(SqlTypeName.VARCHAR, 36);
- private static final TestCustomType CUSTOM_TYPE = new
TestCustomType(false);
-
- private static final RelDataType NULLABLE_CUSTOM_TYPE =
CUSTOM_TYPE.createWithNullability(true);
-
// ANY produced by the default implementation of leastRestrictiveType has
nullability = true
private static final RelDataType ANY =
TYPE_FACTORY.createTypeWithNullability(TYPE_FACTORY.createSqlType(SqlTypeName.ANY),
true);
- private static final RelDataType NULL =
TYPE_FACTORY.createTypeWithNullability(TYPE_FACTORY.createSqlType(SqlTypeName.NULL),
true);
-
@ParameterizedTest
@MethodSource("tinyIntTests")
public void testTinyInt(RelDataType t1, RelDataType t2,
LeastRestrictiveType leastRestrictiveType) {
@@ -226,32 +214,6 @@ public class LeastRestrictiveTypesTest {
return tests.stream();
}
- @ParameterizedTest
- @MethodSource("customTypeTests")
- public void testUuid(RelDataType t1, RelDataType t2, LeastRestrictiveType
leastRestrictiveType) {
- expectLeastRestrictiveType(t1, t2, leastRestrictiveType);
- expectLeastRestrictiveType(t2, t1, leastRestrictiveType);
- }
-
- private static Stream<Arguments> customTypeTests() {
- List<Arguments> tests = new ArrayList<>();
-
- tests.add(Arguments.arguments(CUSTOM_TYPE, TINYINT,
LeastRestrictiveType.none()));
- tests.add(Arguments.arguments(CUSTOM_TYPE, SMALLINT,
LeastRestrictiveType.none()));
- tests.add(Arguments.arguments(CUSTOM_TYPE, INTEGER,
LeastRestrictiveType.none()));
- tests.add(Arguments.arguments(CUSTOM_TYPE, FLOAT,
LeastRestrictiveType.none()));
- tests.add(Arguments.arguments(CUSTOM_TYPE, REAL,
LeastRestrictiveType.none()));
- tests.add(Arguments.arguments(CUSTOM_TYPE, DOUBLE,
LeastRestrictiveType.none()));
- tests.add(Arguments.arguments(CUSTOM_TYPE, DECIMAL,
LeastRestrictiveType.none()));
- tests.add(Arguments.arguments(CUSTOM_TYPE, BIGINT,
LeastRestrictiveType.none()));
- tests.add(Arguments.arguments(CUSTOM_TYPE, VARCHAR,
LeastRestrictiveType.none()));
- tests.add(Arguments.arguments(CUSTOM_TYPE, CUSTOM_TYPE, new
LeastRestrictiveType(CUSTOM_TYPE)));
- tests.add(Arguments.arguments(NULLABLE_CUSTOM_TYPE, CUSTOM_TYPE, new
LeastRestrictiveType(NULLABLE_CUSTOM_TYPE)));
- tests.add(Arguments.arguments(NULL, CUSTOM_TYPE, new
LeastRestrictiveType(CUSTOM_TYPE)));
-
- return tests.stream();
- }
-
@ParameterizedTest
@MethodSource("anyTests")
public void testAny(RelDataType t1, RelDataType t2, LeastRestrictiveType
leastRestrictiveType) {
@@ -272,35 +234,10 @@ public class LeastRestrictiveTypesTest {
tests.add(Arguments.arguments(ANY, DECIMAL, anyType));
tests.add(Arguments.arguments(ANY, BIGINT, anyType));
tests.add(Arguments.arguments(ANY, VARCHAR, anyType));
- tests.add(Arguments.arguments(ANY, CUSTOM_TYPE, anyType));
return tests.stream();
}
- @Test
- public void testCustomDataTypeLeastRestrictiveTypeForMoreThanTwoTypes() {
- // no least restrictive type between ANY, a built-in type and a custom
data type.
- assertNull(TYPE_FACTORY.leastRestrictive(List.of(CUSTOM_TYPE, INTEGER,
ANY)));
- assertNull(TYPE_FACTORY.leastRestrictive(List.of(INTEGER, ANY,
CUSTOM_TYPE)));
- assertNull(TYPE_FACTORY.leastRestrictive(List.of(ANY, CUSTOM_TYPE,
INTEGER)));
- assertNull(TYPE_FACTORY.leastRestrictive(List.of(ANY, CUSTOM_TYPE,
NULLABLE_CUSTOM_TYPE, INTEGER)));
- assertNull(TYPE_FACTORY.leastRestrictive(List.of(ANY, NULL,
CUSTOM_TYPE, NULLABLE_CUSTOM_TYPE, INTEGER)));
- }
-
- @Test
- public void testCustomDataTypeNullableTypesAreLessRestrictive() {
- assertEquals(NULLABLE_CUSTOM_TYPE,
TYPE_FACTORY.leastRestrictive(List.of(NULLABLE_CUSTOM_TYPE, CUSTOM_TYPE,
CUSTOM_TYPE)));
- assertEquals(NULLABLE_CUSTOM_TYPE,
TYPE_FACTORY.leastRestrictive(List.of(CUSTOM_TYPE, NULLABLE_CUSTOM_TYPE,
CUSTOM_TYPE)));
- assertEquals(NULLABLE_CUSTOM_TYPE,
TYPE_FACTORY.leastRestrictive(List.of(CUSTOM_TYPE, CUSTOM_TYPE,
NULLABLE_CUSTOM_TYPE)));
- }
-
- @Test
- public void testCustomDataTypeIgnoreNulls() {
- assertEquals(NULLABLE_CUSTOM_TYPE,
TYPE_FACTORY.leastRestrictive(List.of(NULLABLE_CUSTOM_TYPE, CUSTOM_TYPE,
NULL)));
- assertEquals(NULLABLE_CUSTOM_TYPE,
TYPE_FACTORY.leastRestrictive(List.of(NULL, NULLABLE_CUSTOM_TYPE,
CUSTOM_TYPE)));
- assertEquals(NULLABLE_CUSTOM_TYPE,
TYPE_FACTORY.leastRestrictive(List.of(CUSTOM_TYPE, NULL,
NULLABLE_CUSTOM_TYPE)));
- }
-
@ParameterizedTest
@MethodSource("types")
public void testLeastRestrictiveTypeForAnyAndMoreThanTwoTypes(RelDataType
type) {
@@ -323,7 +260,6 @@ public class LeastRestrictiveTypesTest {
tests.add(Arguments.arguments(DECIMAL));
tests.add(Arguments.arguments(BIGINT));
tests.add(Arguments.arguments(VARCHAR));
- tests.add(Arguments.arguments(CUSTOM_TYPE));
return tests.stream();
}
@@ -349,29 +285,4 @@ public class LeastRestrictiveTypesTest {
RelDataType actualType =
TYPE_FACTORY.leastRestrictive(Arrays.asList(type1, type2));
assertEquals(expectedType.relDataType, actualType, "leastRestrictive("
+ type1 + "," + type2 + ")");
}
-
- private static final class TestCustomType extends IgniteCustomType {
-
- private static final IgniteCustomTypeSpec SPEC = new
IgniteCustomTypeSpec("TestType",
- NativeTypes.INT8, ColumnType.INT8, Byte.class,
- IgniteCustomTypeSpec.getCastFunction(TestCustomType.class,
"cast"));
-
- @Override
- public IgniteCustomType createWithNullability(boolean nullable) {
- return new TestCustomType(nullable);
- }
-
- private TestCustomType(boolean nullable) {
- super(SPEC, nullable, -1);
- }
-
- @Override
- protected void generateTypeString(StringBuilder sb, boolean
withDetail) {
- sb.append("TestType");
- }
-
- public static byte cast(Object ignore) {
- throw new AssertionError();
- }
- }
}
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 9c066eebfdf..6cead4f4e85 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
@@ -56,8 +56,6 @@ import
org.apache.ignite.internal.sql.engine.exec.row.RowSchemaTypes;
import org.apache.ignite.internal.sql.engine.exec.row.RowType;
import org.apache.ignite.internal.sql.engine.exec.row.TypeSpec;
import org.apache.ignite.internal.sql.engine.framework.ArrayRowHandler;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomType;
-import org.apache.ignite.internal.sql.engine.type.IgniteCustomTypeSpec;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
import org.apache.ignite.internal.type.NativeTypes;
@@ -329,27 +327,6 @@ public class TypeUtilsTest extends BaseIgniteAbstractTest {
return supportedTypes().map(t -> expectCompatible(t, nullType));
}
- /** Type compatibility rules for custom data types. */
- @TestFactory
- public Stream<DynamicTest> testCustomDataTypeCompatibility() {
- IgniteCustomType type1 = new TestCustomType("type1");
- IgniteCustomType type2 = new TestCustomType("type2");
- RelDataType someType = TYPE_FACTORY.createSqlType(SqlTypeName.ANY);
-
- return Stream.of(
- // types with same custom type name are compatible.
- expectCompatible(type1, new
TestCustomType(type1.getCustomTypeName())),
-
- // different custom types are never compatible.
- expectIncompatible(type1, type2),
- expectIncompatible(type2, type1),
-
- // custom types are not compatible with other data types.
- expectIncompatible(someType, type1),
- expectIncompatible(type1, someType)
- );
- }
-
private static Stream<RelDataType> supportedTypes() {
List<SqlTypeName> types = new ArrayList<>();
@@ -366,10 +343,6 @@ public class TypeUtilsTest extends BaseIgniteAbstractTest {
relDataTypes.add(TYPE_FACTORY.createSqlType(typeName));
});
- for (String typeName : TYPE_FACTORY.getCustomTypeSpecs().keySet()) {
- relDataTypes.add(TYPE_FACTORY.createCustomType(typeName));
- }
-
return relDataTypes.stream();
}
@@ -604,30 +577,6 @@ public class TypeUtilsTest extends BaseIgniteAbstractTest {
);
}
- private static final class TestCustomType extends IgniteCustomType {
-
- private TestCustomType(String typeName) {
- super(new IgniteCustomTypeSpec(typeName,
- NativeTypes.INT8, ColumnType.INT8, Byte.class,
- IgniteCustomTypeSpec.getCastFunction(TestCustomType.class,
"cast")), false, -1);
- }
-
- @Override
- protected void generateTypeString(StringBuilder sb, boolean
withDetail) {
- sb.append(getCustomTypeName());
- }
-
- @Override
- public IgniteCustomType createWithNullability(boolean nullable) {
- throw new AssertionError();
- }
-
- @SuppressWarnings("unused")
- public static byte cast(Object ignore) {
- throw new AssertionError();
- }
- }
-
static class RelToExecTestCase {
final RelDataType input;