This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new a75bf47a4a0 IGNITE-25818: Sql. Bump calcite version to 1.41 (#7249)
a75bf47a4a0 is described below
commit a75bf47a4a06792e338f021fef486a3862955a37
Author: Max Zhuravkov <[email protected]>
AuthorDate: Tue Dec 23 16:02:21 2025 +0200
IGNITE-25818: Sql. Bump calcite version to 1.41 (#7249)
---
gradle/libs.versions.toml | 2 +-
.../org/apache/ignite/InitParametersBuilder.java | 2 +-
.../sql/group1/aggregate/group/test_group_by.test | 12 +-
.../sql/engine/exec/exp/RexToLixTranslator.java | 97 +++++++-------
.../engine/prepare/IgniteSqlToRelConvertor.java | 141 +++++++++++++++++----
.../sql/engine/prepare/IgniteTypeCoercion.java | 4 +-
.../ignite/internal/sql/engine/util/RexUtils.java | 47 ++++++-
.../sql/engine/planner/AbstractPlannerTest.java | 36 +++++-
.../sql/engine/planner/CastResolutionTest.java | 5 +-
.../planner/CorrelatedSubqueryPlannerTest.java | 7 +-
.../sql/engine/planner/DynamicParametersTest.java | 9 +-
.../sql/engine/planner/ImplicitCastsTest.java | 1 +
.../planner/IndexSearchBoundsPlannerTest.java | 16 ++-
.../datatypes/NumericInTypeCoercionTest.java | 104 +++++++++++++--
.../prepare/ddl/DdlSqlToCommandConverterTest.java | 13 +-
.../sql/engine/sql/SqlReservedWordsTest.java | 1 +
.../internal/sql/engine/util/QueryCheckerTest.java | 2 +-
.../src/test/resources/tpcds/plan/q15.plan | 2 +-
.../src/test/resources/tpcds/plan/q45.plan | 2 +-
.../src/test/resources/tpcds/plan/q50.plan | 2 +-
.../src/test/resources/tpcds/plan/q62.plan | 2 +-
.../src/test/resources/tpcds/plan/q64.plan | 4 +-
.../src/test/resources/tpcds/plan/q78.plan | 2 +-
.../src/test/resources/tpcds/plan/q8.plan | 8 +-
.../src/test/resources/tpcds/plan/q99.plan | 2 +-
.../src/test/resources/tpch/plan/q22.plan | 4 +-
26 files changed, 394 insertions(+), 133 deletions(-)
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b984f2713d0..5675596abb9 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -59,7 +59,7 @@ hamcrestOptional = "2.0.0"
hamcrestPath = "1.0.1"
hamcrestJson = "0.3"
scalecube = "2.6.15"
-calcite = "1.40.0"
+calcite = "1.41.0"
value = "2.12.0"
janino = "3.1.12"
jsonpath = "2.10.0"
diff --git
a/modules/runner/src/main/java/org/apache/ignite/InitParametersBuilder.java
b/modules/runner/src/main/java/org/apache/ignite/InitParametersBuilder.java
index 431a1a5e810..7a5a37537c6 100644
--- a/modules/runner/src/main/java/org/apache/ignite/InitParametersBuilder.java
+++ b/modules/runner/src/main/java/org/apache/ignite/InitParametersBuilder.java
@@ -23,7 +23,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
-import javax.annotation.Nullable;
+import org.jetbrains.annotations.Nullable;
/** Builder of {@link InitParameters}. */
public class InitParametersBuilder {
diff --git
a/modules/sql-engine/src/integrationTest/sql/group1/aggregate/group/test_group_by.test
b/modules/sql-engine/src/integrationTest/sql/group1/aggregate/group/test_group_by.test
index 6cd2d03f655..1cad5cbf535 100644
---
a/modules/sql-engine/src/integrationTest/sql/group1/aggregate/group/test_group_by.test
+++
b/modules/sql-engine/src/integrationTest/sql/group1/aggregate/group/test_group_by.test
@@ -188,13 +188,17 @@ SELECT SUM(i) FROM integers GROUP BY GROUPING SETS
(POWER(ROUND(ABS(SQRT(i*i)),
3
NULL
-# expression with aliases can't be used in group by <columns> clause.
-statement error: Column 'K' not found in any table
+# expression with aliases can be used in group by <columns> clause.
+query II
SELECT 1 AS k, SUM(i) FROM integers GROUP BY k+1 ORDER BY 2
+----
+1 6
-# expression with aliases can't be used in group by <grouping sets> clause.
-statement error: Column 'K' not found in any table
+# expression with aliases can be used in group by <grouping sets> clause.
+query II
SELECT 1 AS k, SUM(i) FROM integers GROUP BY GROUPING SETS ((k+1)) ORDER BY 2
+----
+1 6
# group by column refs should be recognized, even if one uses an explicit
table specifier and the other does not
query II
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 7c53c185b64..e37fc4f446e 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
@@ -60,6 +60,7 @@ import org.apache.calcite.linq4j.tree.ParameterExpression;
import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.linq4j.tree.Statement;
import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexCall;
import org.apache.calcite.rex.RexCallBinding;
@@ -72,6 +73,7 @@ import org.apache.calcite.rex.RexLambdaRef;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexLocalRef;
import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexNodeAndFieldIndex;
import org.apache.calcite.rex.RexOver;
import org.apache.calcite.rex.RexPatternFieldRef;
import org.apache.calcite.rex.RexProgram;
@@ -82,6 +84,7 @@ import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.rex.RexVisitor;
import org.apache.calcite.runtime.SpatialTypeFunctions;
import org.apache.calcite.runtime.rtti.RuntimeTypeInformation;
+import org.apache.calcite.runtime.variant.VariantValue;
import org.apache.calcite.schema.FunctionContext;
import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.SqlOperator;
@@ -354,53 +357,54 @@ public class RexToLixTranslator implements
RexVisitor<RexToLixTranslator.Result>
final Supplier<Expression> defaultExpression = () ->
ConverterUtils.convert(operand, targetType);
-// if (sourceType.getSqlTypeName() == SqlTypeName.VARIANT) {
-// // Converting VARIANT to VARIANT uses the default conversion
-// if (targetType.getSqlTypeName() == SqlTypeName.VARIANT) {
-// return defaultExpression.get();
-// }
-// // Converting a VARIANT to any other type calls the Variant.cast method
-// // First cast operand to a VariantValue (it may be an Object)
-// Expression operandCast = Expressions.convert_(operand,
VariantValue.class);
-// Expression cast =
-// Expressions.call(operandCast,
BuiltInMethod.VARIANT_CAST.method,
-// RuntimeTypeInformation.createExpression(targetType));
-// // The cast returns an Object, so we need a convert to the expected
Java type
-// RelDataType nullableTarget =
typeFactory.createTypeWithNullability(targetType, true);
-// return Expressions.convert_(cast,
typeFactory.getJavaClass(nullableTarget));
-// }
-//
-// if (targetType.getSqlTypeName() == SqlTypeName.ROW) {
-// assert sourceType.getSqlTypeName() == SqlTypeName.ROW;
-// List<RelDataTypeField> targetTypes = targetType.getFieldList();
-// List<RelDataTypeField> sourceTypes = sourceType.getFieldList();
-// assert targetTypes.size() == sourceTypes.size();
-// List<Expression> fields = new ArrayList<>();
-// for (int i = 0; i < targetTypes.size(); i++) {
-// RelDataTypeField targetField = targetTypes.get(i);
-// RelDataTypeField sourceField = sourceTypes.get(i);
-// Expression field = Expressions.arrayIndex(operand,
Expressions.constant(i));
-// // In the generated Java code 'field' is an Object,
-// // we need to also cast it to the correct type to enable correct
method dispatch in Java.
-// // We force the type to be nullable; this way, instead of (int) we
get (Integer).
-// // Casting an object ot an int is not legal.
-// RelDataType nullableSourceFieldType =
-// typeFactory.createTypeWithNullability(sourceField.getType(),
true);
-// Type javaType = typeFactory.getJavaClass(nullableSourceFieldType);
-// if (!javaType.getTypeName().equals("java.lang.Void")
-// && !nullableSourceFieldType.isStruct()) {
-// // Cannot cast to Void - this is the type of NULL literals.
-// field = Expressions.convert_(field, javaType);
-// }
-// Expression convert =
-// getConvertExpression(sourceField.getType(),
targetField.getType(), field, format);
-// fields.add(convert);
-// }
-// return Expressions.call(BuiltInMethod.ARRAY.method, fields);
-// }
+ if (sourceType.getSqlTypeName() == SqlTypeName.VARIANT) {
+ // Converting VARIANT to VARIANT uses the default conversion
+ if (targetType.getSqlTypeName() == SqlTypeName.VARIANT) {
+ return defaultExpression.get();
+ }
+ // Converting a VARIANT to any other type calls the Variant.cast method
+ // First cast operand to a VariantValue (it may be an Object)
+ Expression operandCast = Expressions.convert_(operand,
VariantValue.class);
+ Expression cast =
+ Expressions.call(operandCast, BuiltInMethod.VARIANT_CAST.method,
+ RuntimeTypeInformation.createExpression(targetType));
+ // The cast returns an Object, so we need a convert to the expected Java
type
+ RelDataType nullableTarget =
typeFactory.createTypeWithNullability(targetType, true);
+ return Expressions.convert_(cast,
typeFactory.getJavaClass(nullableTarget));
+ }
+
+ if (targetType.getSqlTypeName() == SqlTypeName.ROW) {
+ assert sourceType.getSqlTypeName() == SqlTypeName.ROW;
+ List<RelDataTypeField> targetTypes = targetType.getFieldList();
+ List<RelDataTypeField> sourceTypes = sourceType.getFieldList();
+ assert targetTypes.size() == sourceTypes.size();
+ List<Expression> fields = new ArrayList<>();
+ for (int i = 0; i < targetTypes.size(); i++) {
+ RelDataTypeField targetField = targetTypes.get(i);
+ RelDataTypeField sourceField = sourceTypes.get(i);
+ Expression field = Expressions.arrayIndex(operand,
Expressions.constant(i));
+ // In the generated Java code 'field' is an Object,
+ // we need to also cast it to the correct type to enable correct
method dispatch in Java.
+ // We force the type to be nullable; this way, instead of (int) we get
(Integer).
+ // Casting an object ot an int is not legal.
+ RelDataType nullableSourceFieldType =
+ typeFactory.createTypeWithNullability(sourceField.getType(),
true);
+ Type javaType = typeFactory.getJavaClass(nullableSourceFieldType);
+ if (!javaType.getTypeName().equals("java.lang.Void")
+ && !nullableSourceFieldType.isStruct()) {
+ // Cannot cast to Void - this is the type of NULL literals.
+ field = Expressions.convert_(field, javaType);
+ }
+ Expression convert =
+ getConvertExpression(sourceField.getType(),
targetField.getType(), field, format);
+ fields.add(convert);
+ }
+ return Expressions.call(BuiltInMethod.ARRAY.method, fields);
+ }
switch (targetType.getSqlTypeName()) {
case ARRAY:
+ case MULTISET:
final RelDataType sourceDataType = sourceType.getComponentType();
final RelDataType targetDataType = targetType.getComponentType();
assert sourceDataType != null;
@@ -1908,6 +1912,11 @@ public class RexToLixTranslator implements
RexVisitor<RexToLixTranslator.Result>
return new Result(isNullVariable, valueVariable);
}
+ @Override
+ public Result visitNodeAndFieldIndex(RexNodeAndFieldIndex nodeAndFieldIndex)
{
+ throw new RuntimeException("cannot translate expression " +
nodeAndFieldIndex);
+ }
+
Expression checkNull(Expression expr) {
if (Primitive.flavor(expr.getType())
== Primitive.Flavor.PRIMITIVE) {
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlToRelConvertor.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlToRelConvertor.java
index adb6012cf4b..d64c508775b 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlToRelConvertor.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlToRelConvertor.java
@@ -19,12 +19,17 @@ package org.apache.ignite.internal.sql.engine.prepare;
import static java.util.Objects.requireNonNull;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptTable;
+import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.prepare.Prepare;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelRoot;
@@ -43,8 +48,8 @@ import org.apache.calcite.sql.SqlInsert;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlMerge;
import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.SqlUpdate;
-import org.apache.calcite.sql.util.SqlShuttle;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.calcite.sql.validate.SqlValidatorUtil;
@@ -52,13 +57,41 @@ import org.apache.calcite.sql2rel.InitializerContext;
import org.apache.calcite.sql2rel.SqlRexConvertletTable;
import org.apache.calcite.sql2rel.SqlToRelConverter;
import org.apache.calcite.tools.RelBuilder;
-import org.apache.calcite.util.ControlFlowException;
import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.Util;
import org.apache.ignite.internal.sql.engine.schema.IgniteDataSource;
import org.jetbrains.annotations.Nullable;
/** Converts a SQL parse tree into a relational algebra operators. */
public class IgniteSqlToRelConvertor extends SqlToRelConverter implements
InitializerContext {
+
+ private static final MethodHandle REPLACE_SUB_QUERIES;
+
+ private static final Throwable INIT_ERROR;
+
+ static {
+ // TODO https://issues.apache.org/jira/browse/IGNITE-27398 Remove this
workaround
+ MethodHandle handle;
+ Throwable err;
+ try {
+ Lookup lookup =
MethodHandles.privateLookupIn(SqlToRelConverter.class, MethodHandles.lookup());
+ Class<?> bbClass =
lookup.findClass("org.apache.calcite.sql2rel.SqlToRelConverter$Blackboard");
+ Class<?> logicClass =
lookup.findClass("org.apache.calcite.plan.RelOptUtil$Logic");
+ Class<?> sqlNodeClass = SqlNode.class;
+ MethodType tpe = MethodType.methodType(void.class, bbClass,
sqlNodeClass, logicClass);
+
+ handle = lookup.findVirtual(SqlToRelConverter.class,
"replaceSubQueries", tpe);
+ err = null;
+ } catch (Throwable e) {
+ // Postpone error reporting to have a better chance of logging an
error.
+ err = e;
+ handle = null;
+ }
+
+ INIT_ERROR = err;
+ REPLACE_SUB_QUERIES = handle;
+ }
+
private final Deque<SqlCall> datasetStack = new ArrayDeque<>();
private RelBuilder relBuilder;
@@ -73,12 +106,19 @@ public class IgniteSqlToRelConvertor extends
SqlToRelConverter implements Initia
super(viewExpander, validator, catalogReader, cluster,
convertletTable, cfg);
relBuilder = config.getRelBuilderFactory().create(cluster, null);
+
+ if (INIT_ERROR != null) {
+ throw new IllegalStateException("Failed to initialize " +
IgniteSqlToRelConvertor.class.getName(), INIT_ERROR);
+ }
}
/** {@inheritDoc} */
@Override protected RelRoot convertQueryRecursive(SqlNode qry, boolean
top, @Nullable RelDataType targetRowType) {
if (qry.getKind() == SqlKind.MERGE) {
return RelRoot.of(convertMerge((SqlMerge) qry), qry.getKind());
+ } else if (qry.getKind() == SqlKind.UPDATE) {
+ // TODO https://issues.apache.org/jira/browse/IGNITE-27398 Remove
this workaround and use calcite's method.
+ return RelRoot.of(convertUpdateFixed((SqlUpdate) qry),
qry.getKind());
} else {
return super.convertQueryRecursive(qry, top, targetRowType);
}
@@ -99,31 +139,23 @@ public class IgniteSqlToRelConvertor extends
SqlToRelConverter implements Initia
throw new UnsupportedOperationException("Not implemented yet");
}
- private static class DefaultChecker extends SqlShuttle {
- private boolean hasDefaults(SqlCall call) {
- try {
- call.accept(this);
- return false;
- } catch (ControlFlowException e) {
- return true;
- }
- }
-
- @Override public @Nullable SqlNode visit(SqlCall call) {
- if (call.getKind() == SqlKind.DEFAULT) {
- throw new ControlFlowException();
- }
-
- return super.visit(call);
- }
- }
-
@Override public RelNode convertValues(SqlCall values, RelDataType
targetRowType) {
- DefaultChecker checker = new DefaultChecker();
-
- boolean hasDefaults = checker.hasDefaults(values);
-
- if (hasDefaults) {
+ // TODO https://issues.apache.org/jira/browse/IGNITE-27396
+ // FIX: Original convertValuesImpl adds additional type casts that are
not correct
+ // and break NOT NULL constraints.
+ //
+ // See these lines in convertValuesImpl:
+ // if (!(def instanceof RexDynamicParam) &&
!def.getType().equals(fieldType)) {
+ // def = rexBuilder.makeCast(operand.getParserPosition(), fieldType,
def);
+ // }
+ // exps.add(def, SqlValidatorUtil.alias(operand, i));
+ //
+ // Example: INSERT INTO t1 VALUES(1, (SELECT NULL))
+ //
+ // if fieldType is NOT NULLABLE INT and def's type is NULLABLE INT then
+ // resulting expression is wrapped into CAST(NULLABLE INT AS NOT
NULLABLE INT)
+ // but that cast expression always results in 0 (INT) thus breaking a
NOT NULL constraint.
+ if (datasetStack.peek() instanceof SqlInsert) {
SqlValidatorScope scope = validator.getOverScope(values);
assert scope != null;
Blackboard bb = createBlackboard(scope, null, false);
@@ -131,7 +163,6 @@ public class IgniteSqlToRelConvertor extends
SqlToRelConverter implements Initia
convertValuesImplEx(bb, values, targetRowType);
return bb.root();
} else {
- // a bit lightweight than default processing one.
return super.convertValues(values, targetRowType);
}
}
@@ -345,4 +376,60 @@ public class IgniteSqlToRelConvertor extends
SqlToRelConverter implements Initia
public RelOptTable getTargetTable(SqlNode call) {
return super.getTargetTable(call);
}
+
+ // TODO https://issues.apache.org/jira/browse/IGNITE-27398 Remove this
workaround
+ // This method is a copy of SqlToRelConverter convertUpdate.
+ private RelNode convertUpdateFixed(SqlUpdate call) {
+ final SqlSelect sourceSelect =
+ requireNonNull(call.getSourceSelect(),
+ () -> "sourceSelect for " + call);
+ final SqlValidatorScope scope = validator.getWhereScope(sourceSelect);
+ Blackboard bb = createBlackboard(scope, null, false);
+
+ RelOptTable targetTable = getTargetTable(call);
+
+ // convert update column list from SqlIdentifier to String
+ final List<String> targetColumnNameList = new ArrayList<>();
+ final RelDataType targetRowType = targetTable.getRowType();
+ for (SqlNode node : call.getTargetColumnList()) {
+ SqlIdentifier id = (SqlIdentifier) node;
+ RelDataTypeField field =
+ SqlValidatorUtil.getTargetField(
+ targetRowType, typeFactory, id, catalogReader,
targetTable);
+ if (field == null) {
+ throw new AssertionError("column " + id + " not found");
+ }
+ targetColumnNameList.add(field.getName());
+ }
+
+ // A call to replaceSubQueries(bb, call,
RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
+ try {
+ REPLACE_SUB_QUERIES.invoke(this, bb, call,
RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
+ } catch (Throwable e) {
+ throw new AssertionError("Failed to replace subqueries", e);
+ }
+
+ // FIX: The condition below is incorrect, it ignores virtual columns
that present is the target table.
+ // sourceSelect` should contain target columns values plus source
expressions
+ //
+ // if (sourceSelect.getSelectList().size()
+ // != targetTable.getRowType().getFieldCount() +
call.getSourceExpressionList().size()) {
+ // throw new AssertionError(
+ // "Unexpected select list size. Select list should
contain both target table columns and "
+ // + "set expressions");
+ // }
+
+ RelNode sourceRel = convertSelect(sourceSelect, false);
+ bb.setRoot(sourceRel, false);
+
+ // sourceRel already contains all source expressions. Only create
references to those fields.
+ List<RexNode> rexExpressionList =
+ Util.transform(
+ Util.last(sourceRel.getRowType().getFieldList(),
targetColumnNameList.size()),
+ expressionField -> new
RexInputRef(expressionField.getIndex(),
+ expressionField.getType()));
+
+ return LogicalTableModify.create(targetTable, catalogReader, sourceRel,
+ LogicalTableModify.Operation.UPDATE, targetColumnNameList,
rexExpressionList, false);
+ }
}
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 45e16ace9a6..13d2ea2101c 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
@@ -212,7 +212,7 @@ public class IgniteTypeCoercion extends TypeCoercionImpl {
}
if (operatorIsQuantify(operator)) {
- return quantifyOperationCoercion(binding);
+ return inOperationCoercionFixed(binding);
}
return super.inOperationCoercion(binding);
@@ -230,7 +230,7 @@ public class IgniteTypeCoercion extends TypeCoercionImpl {
return operatorIsIn(operator) || operatorIsQuantify(operator);
}
- private boolean quantifyOperationCoercion(SqlCallBinding binding) {
+ private boolean inOperationCoercionFixed(SqlCallBinding binding) {
// This method is a copy-paste of
org.apache.calcite.sql.validate.implicit.TypeCoercionImpl.inOperationCoercion
// with stripped validation of operation kind.
assert operatorIsQuantify(binding.getOperator());
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
index 5041ca85076..c564c2e42e8 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/RexUtils.java
@@ -190,7 +190,8 @@ public class RexUtils {
return true;
}
- /** Try to transform expression into DNF form.
+ /**
+ * Try to transform expression into DNF form.
*
* @param rexBuilder Expression builder.
* @param node Expression to process.
@@ -212,7 +213,8 @@ public class RexUtils {
final RexBuilder rexBuilder;
final int maxOrNodes;
- /** Constructor.
+ /**
+ * Constructor.
*
* @param rexBuilder Rex builder.
* @param maxOrNodes Limit for OR nodes, if limit is reached further
processing will be stopped.
@@ -342,7 +344,7 @@ public class RexUtils {
return null;
}
- return bounds;
+ return bounds;
}
/**
@@ -1440,8 +1442,10 @@ public class RexUtils {
return wasChanged ? newSearchBounds : searchBounds;
}
- /** Check if given {@link RexNode} is a 'loss-less' cast, that is, a cast
from which
- * the original value of the field can be certainly recovered. */
+ /**
+ * Check if given {@link RexNode} is a 'loss-less' cast, that is, a cast
from which the original value of the field can be certainly
+ * recovered.
+ */
public static boolean isLosslessCast(RexNode node) {
if (!node.isA(SqlKind.CAST)) {
return false;
@@ -1473,6 +1477,37 @@ public class RexUtils {
return source.getPrecision() <= target.getPrecision();
}
- return RexUtil.isLosslessCast(source, target);
+ return isLosslessCast(source, target);
+ }
+
+ // TODO: https://issues.apache.org/jira/browse/IGNITE-27390
+ // This is copy of RexUtil.isLosslessCast from Calcite 1.40. We should
replace RexUtils.isLosslessCast
+ // with calcite's implementation.
+ private static boolean isLosslessCast(RelDataType source, RelDataType
target) {
+ final SqlTypeName sourceSqlTypeName = source.getSqlTypeName();
+ final SqlTypeName targetSqlTypeName = target.getSqlTypeName();
+ // 1) Both INT numeric types
+ if (SqlTypeFamily.INTEGER.getTypeNames().contains(sourceSqlTypeName)
+ &&
SqlTypeFamily.INTEGER.getTypeNames().contains(targetSqlTypeName)) {
+ return targetSqlTypeName.compareTo(sourceSqlTypeName) >= 0;
+ }
+ // 2) Both CHARACTER types: it depends on the precision (length)
+ if (SqlTypeFamily.CHARACTER.getTypeNames().contains(sourceSqlTypeName)
+ &&
SqlTypeFamily.CHARACTER.getTypeNames().contains(targetSqlTypeName)) {
+ return targetSqlTypeName.compareTo(sourceSqlTypeName) >= 0
+ && source.getPrecision() <= target.getPrecision();
+ }
+ // 3) From NUMERIC family to CHARACTER family: it depends on the
precision/scale
+ if (sourceSqlTypeName.getFamily() == SqlTypeFamily.NUMERIC
+ && targetSqlTypeName.getFamily() == SqlTypeFamily.CHARACTER) {
+ int sourceLength = source.getPrecision() + 1; // include sign
+ if (source.getScale() != -1 && source.getScale() != 0) {
+ sourceLength += source.getScale() + 1; // include decimal mark
+ }
+ final int targetPrecision = target.getPrecision();
+ return targetPrecision == RelDataType.PRECISION_NOT_SPECIFIED ||
targetPrecision >= sourceLength;
+ }
+ // Return FALSE by default
+ return false;
}
}
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractPlannerTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractPlannerTest.java
index 6949462627c..5bb7e3869d7 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractPlannerTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/AbstractPlannerTest.java
@@ -62,14 +62,17 @@ import org.apache.calcite.rel.core.TableScan;
import org.apache.calcite.rel.hint.HintStrategyTable;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexCall;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexShuttle;
+import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.schema.ColumnStrategy;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.sql.SqlExplainLevel;
import org.apache.calcite.sql.SqlFunction;
+import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.type.BasicSqlType;
import org.apache.calcite.sql.type.SqlTypeName;
@@ -744,9 +747,7 @@ public abstract class AbstractPlannerTest extends
IgniteAbstractTest {
// Hints are not serializable.
clearHints(expected);
- // TODO https://issues.apache.org/jira/browse/IGNITE-19162 Remove
this rewriter
- // when the issue with sub-millisecond precision is resolved.
- RelNode replaced = new
RewriteTimeTimestampLiterals().visit((IgniteRel) expected);
+ RelNode replaced = new
RewriteExpressionsToComparisonFormShuttle().visit((IgniteRel) expected);
if (replaced != expected) {
expected = replaced;
}
@@ -1158,11 +1159,18 @@ public abstract class AbstractPlannerTest extends
IgniteAbstractTest {
}
/**
- * Truncates TIME/TIMESTAMP literals to millis, because sub-millisecond
values are lost during serilization,
- * since calcite's runtime does not support sub-millisecond precision for
these types.
+ * Rewrites all expressions so they match their deserialized form.
+ *
+ * <ul>
+ * <li>Truncates TIME/TIMESTAMP literals to millis, because
sub-millisecond values are lost during serilization,
+ * since calcite's runtime does not support sub-millisecond precision for
these types.</li>
+ * <li>Expands all calls to {@code SEARCH} operator) see See RelJson
toJson(RexNode node).</li>
+ * <li>Flattens ANDs and ORs.</li>
+ * </ul>
*/
- private static class RewriteTimeTimestampLiterals extends IgniteRelShuttle
{
-
+ private static class RewriteExpressionsToComparisonFormShuttle extends
IgniteRelShuttle {
+ // TODO https://issues.apache.org/jira/browse/IGNITE-19162 Remove this
rewriter
+ // when the issue with sub-millisecond precision is resolved.
final RexShuttle rexVisitor = new RexShuttle() {
@Override
public RexNode visitLiteral(RexLiteral literal) {
@@ -1191,6 +1199,20 @@ public abstract class AbstractPlannerTest extends
IgniteAbstractTest {
return super.visitLiteral(literal);
}
}
+
+ @Override
+ public RexNode visitCall(RexCall call) {
+ RexNode newCall = super.visitCall(call);
+ RexBuilder rexBuilder = Commons.emptyCluster().getRexBuilder();
+
+ if (newCall.isA(SqlKind.SEARCH)) {
+ return RexUtil.expandSearch(rexBuilder, null, newCall);
+ } else if (newCall.isA(SqlKind.AND) ||
newCall.isA(SqlKind.OR)) {
+ return RexUtil.flatten(rexBuilder, newCall);
+ } else {
+ return newCall;
+ }
+ }
};
@Override
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CastResolutionTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CastResolutionTest.java
index 01cba2520c2..c05521fde05 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CastResolutionTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CastResolutionTest.java
@@ -62,7 +62,10 @@ public class CastResolutionTest extends AbstractPlannerTest {
private static final Set<String> FRACTIONAL_NAMES =
FRACTIONAL_TYPES.stream().map(SqlTypeName::getName).collect(Collectors.toSet());
- private static final Set<String> EXACT_NUMERIC =
EXACT_TYPES.stream().map(SqlTypeName::getName).collect(Collectors.toSet());
+ private static final Set<String> EXACT_NUMERIC = EXACT_TYPES.stream()
+ .filter(t -> !SqlTypeName.UNSIGNED_TYPES.contains(t))
+ .map(SqlTypeName::getName)
+ .collect(Collectors.toSet());
private static final Set<String> CHAR_NAMES =
CHAR_TYPES.stream().map(SqlTypeName::getName).collect(Collectors.toSet());
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedSubqueryPlannerTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedSubqueryPlannerTest.java
index 446d2c1f142..cab4fc6775a 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedSubqueryPlannerTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/CorrelatedSubqueryPlannerTest.java
@@ -196,13 +196,14 @@ public class CorrelatedSubqueryPlannerTest extends
AbstractPlannerTest {
List<LogicalCorrelate> correlates = findNodes(rel,
byClass(LogicalCorrelate.class));
- assertEquals(4, correlates.size());
+ // TODO https://issues.apache.org/jira/browse/IGNITE-27403
investigate changes in this test.
+ assertEquals(2, correlates.size());
// There are collisions by correlation id.
assertEquals(correlates.get(0).getCorrelationId(),
correlates.get(1).getCorrelationId());
- assertEquals(correlates.get(0).getCorrelationId(),
correlates.get(2).getCorrelationId());
- assertEquals(correlates.get(0).getCorrelationId(),
correlates.get(3).getCorrelationId());
+ // TODO https://issues.apache.org/jira/browse/IGNITE-27403
investigate changes in this test.
+ // Cannot decorrelate further
rel = planner.replaceCorrelatesCollisions(rel);
correlates = findNodes(rel, byClass(LogicalCorrelate.class));
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DynamicParametersTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DynamicParametersTest.java
index 3881f96f932..8f0211d227b 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DynamicParametersTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DynamicParametersTest.java
@@ -70,8 +70,9 @@ public class DynamicParametersTest extends
AbstractPlannerTest {
public Stream<DynamicTest> testArithExprs() {
return Stream.of(
sql("SELECT 1 + ?",
1).parameterTypes(nullable(NativeTypes.INT32)).ok(),
- sql("SELECT NULL + ?",
1).parameterTypes(nullable(NativeTypes.INT32)).project("null:INTEGER"),
- sql("SELECT ? + NULL",
1).parameterTypes(nullable(NativeTypes.INT32)).project("null:INTEGER"),
+ // TODO https://issues.apache.org/jira/browse/IGNITE-27395
SELECT NULL + ?int is not simplified to NULL
+ sql("SELECT NULL + ?",
1).parameterTypes(nullable(NativeTypes.INT32)).project("+(null:NULL, ?0)"),
+ sql("SELECT ? + NULL",
1).parameterTypes(nullable(NativeTypes.INT32)).project("+(?0, null)"),
sql("SELECT 1 + ?",
"1").parameterTypes(nullable(NativeTypes.STRING))
.fails("Cannot apply '+' to arguments of type
'<INTEGER> + <VARCHAR>'"),
@@ -120,7 +121,7 @@ public class DynamicParametersTest extends
AbstractPlannerTest {
return Stream.of(
sql("SELECT ? IN ('1', '2')",
1).parameterTypes(nullable(NativeTypes.INT32))
.fails("Values passed to IN operator must have
compatible types"),
- sql("SELECT ? IN (1, 2)",
1).parameterTypes(nullable(NativeTypes.INT32)).project("OR(=(?0, 1), =(?0,
2))"),
+ sql("SELECT ? IN (1, 2)",
1).parameterTypes(nullable(NativeTypes.INT32)).project("SEARCH(?0, Sarg[1,
2])"),
sql("SELECT ? IN (1)", Unspecified.UNKNOWN)
.fails("Unable to determine type of a dynamic
parameter"),
@@ -468,7 +469,7 @@ public class DynamicParametersTest extends
AbstractPlannerTest {
checkStatement()
.sql("SELECT COALESCE(?, ?)", null, null)
.parameterTypes(nullable(null), nullable(null))
- .project("CASE(IS NOT NULL(?0), ?0, ?1)"),
+ .project("CASE(IS NOT NULL(?0), CAST(?0):NULL, ?1)"),
checkStatement()
.sql("SELECT COALESCE(?, 1)", Unspecified.UNKNOWN)
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ImplicitCastsTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ImplicitCastsTest.java
index 64f06f3d969..88b7a83dba7 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ImplicitCastsTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/ImplicitCastsTest.java
@@ -112,6 +112,7 @@ public class ImplicitCastsTest extends AbstractPlannerTest {
private static Stream<Arguments> joinColumnTypes() {
List<RelDataType> numericTypes = SqlTypeName.NUMERIC_TYPES.stream()
+ .filter(t -> !SqlTypeName.UNSIGNED_TYPES.contains(t))
// Real/Float got mixed up.
.filter(t -> t != SqlTypeName.FLOAT)
.map(TYPE_FACTORY::createSqlType)
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
index 06df65c41b6..363eac3d610 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/IndexSearchBoundsPlannerTest.java
@@ -339,10 +339,18 @@ public class IndexSearchBoundsPlannerTest extends
AbstractPlannerTest {
);
// Implicit cast of 2 to VARCHAR.
- assertBounds("SELECT * FROM TEST WHERE C1 = 1 AND C2 IN (2::VARCHAR,
'3')",
- exact(1),
- multi(exact("2"), exact("3"))
- );
+ // TODO https://issues.apache.org/jira/browse/IGNITE-27391
+ assertPlan("SELECT * FROM TEST WHERE C1 = 1 AND C2 IN (2::VARCHAR,
'3')",
+ List.of(publicSchema),
nodeOrAnyChild(isInstanceOf(IgniteIndexScan.class)
+ .and(scan -> {
+ boolean boundsMatch =
matchBounds(scan.searchBounds(), exact(1));
+ String condition = scan.condition() != null ?
scan.condition().toString() : null;
+ String expected =
+ "AND(=($t0, 1), OR(=(CAST($t1):VARCHAR
CHARACTER SET \"UTF-8\", _UTF-8'2'), =($t1, _UTF-8'3')))";
+ boolean conditionMatch = Objects.equals(condition,
expected);
+ return boundsMatch && conditionMatch;
+ })), List.of(),
+ "LogicalTableScanConverterRule", "UnionConverterRule");
}
/** Tests bounds with dynamic parameters. */
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/NumericInTypeCoercionTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/NumericInTypeCoercionTest.java
index 2442a547510..38ca01d2e4a 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/NumericInTypeCoercionTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/datatypes/NumericInTypeCoercionTest.java
@@ -20,8 +20,12 @@ package
org.apache.ignite.internal.sql.engine.planner.datatypes;
import static
org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator.DECIMAL_DYNAMIC_PARAM_PRECISION;
import static
org.apache.ignite.internal.sql.engine.prepare.IgniteSqlValidator.DECIMAL_DYNAMIC_PARAM_SCALE;
+import java.text.DecimalFormat;
import java.util.List;
+import java.util.Map;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.apache.calcite.rex.RexNode;
import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
@@ -32,6 +36,7 @@ import org.apache.ignite.internal.sql.engine.rel.IgniteValues;
import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
import org.apache.ignite.internal.sql.engine.util.SqlTestUtils;
+import org.apache.ignite.internal.type.DecimalNativeType;
import org.apache.ignite.internal.type.NativeType;
import org.apache.ignite.internal.type.NativeTypes;
import org.apache.ignite.sql.ColumnType;
@@ -2710,16 +2715,97 @@ public class NumericInTypeCoercionTest extends
BaseTypeCoercionTest {
.build()
);
- // SHORT values can intersect with a DECIMAL with a 5 digits in
integer parts, so for SHORT (INT16) we need to generate values
- // take it into consideration.
- boolean closerToBound = numericPair.first().spec() == ColumnType.INT16;
-
- String value = "(" + generateLiteral(numericPair.second(),
closerToBound) + ")";
+ String value = "(" + generateLiteralForPair(numericPair, true) + ")";
Predicate<IgniteTableScan> matcher = checkPlan(first, second);
assertPlan("SELECT c1 FROM T1 WHERE c1 IN " + value, schema, matcher);
}
+ private static String generateLiteralForPair(NumericPair numericPair,
boolean literalIsInRange) {
+ NativeType columnType = numericPair.first();
+ NativeType literalType = numericPair.second();
+
+ Map<ColumnType, Integer> precisionPerType = Map.of(
+ ColumnType.INT8, 3,
+ ColumnType.INT16, 5,
+ ColumnType.INT32, 10,
+ ColumnType.INT64, 19,
+ ColumnType.FLOAT, 10,
+ ColumnType.DOUBLE, 19
+ );
+
+ Integer columnDigits = precisionPerType.get(columnType.spec());
+ int columnFractions = 0;
+
+ if (columnType instanceof DecimalNativeType) {
+ DecimalNativeType decimal = (DecimalNativeType) columnType;
+ columnDigits = decimal.precision();
+ columnFractions = decimal.scale();
+ columnDigits -= columnFractions;
+ } else if (isFloatingPointType(columnType)) {
+ columnFractions = 2;
+ }
+
+ Integer literalDigits = precisionPerType.get(literalType.spec());
+ int literalFractions = 0;
+ if (literalType instanceof DecimalNativeType) {
+ DecimalNativeType decimal = (DecimalNativeType) literalType;
+ literalDigits = decimal.precision();
+ literalFractions = decimal.scale();
+ literalDigits -= literalFractions;
+ } else if (isFloatingPointType(literalType)) {
+ literalFractions = 2;
+ }
+
+ int numDigits;
+ int numFractions;
+
+ if (literalIsInRange) {
+ numDigits = Math.min(columnDigits, literalDigits);
+ numFractions = Math.min(columnFractions, literalFractions);
+ } else {
+ numDigits = Math.max(columnDigits, literalDigits) + 1;
+ numFractions = Math.max(columnFractions, literalFractions);
+ }
+
+ String intPart = IntStream.rangeClosed(1, numDigits)
+ .mapToObj(String::valueOf)
+ .collect(Collectors.joining(""))
+ .substring(0, numDigits);
+
+ String strVal;
+ if (numFractions > 0) {
+ String fracPart = IntStream.rangeClosed(1, numFractions)
+ .mapToObj(String::valueOf)
+ .collect(Collectors.joining(""))
+ .substring(0, numFractions);
+
+ strVal = intPart + "." + fracPart;
+ } else {
+ strVal = intPart;
+ }
+
+ Object litVal;
+ if (isFloatingPointType(literalType)) {
+ // Format floats and double
+ String format = "0." + "#".repeat(numDigits + numFractions) +
"E0";
+ DecimalFormat decimalFormat = new DecimalFormat(format);
+ if (literalType.spec() == ColumnType.FLOAT) {
+ litVal = decimalFormat.format(Float.parseFloat(strVal));
+ } else {
+ litVal = decimalFormat.format(Double.parseDouble(strVal));
+ }
+ } else {
+ litVal = strVal;
+ }
+ return SqlTestUtils.makeLiteral(litVal, literalType);
+ }
+
+ private static boolean isFloatingPointType(NativeType type1) {
+ ColumnType secondType = type1.spec();
+ return secondType == ColumnType.FLOAT || secondType ==
ColumnType.DOUBLE;
+ }
+
@ParameterizedTest
@MethodSource("inOperandsLiteralsOutOfRange")
public void literalsOutOfRange(
@@ -2736,17 +2822,15 @@ public class NumericInTypeCoercionTest extends
BaseTypeCoercionTest {
// SHORT values can intersect with a DECIMAL with a 5 digits in
integer parts, so for SHORT (INT16) we need to generate values
// take it into consideration.
- boolean closerToBound = numericPair.first().spec() == ColumnType.INT16;
-
- String value = "(" + generateLiteral(numericPair.second(),
closerToBound) + ")";
+ String value = "(" + generateLiteralForPair(numericPair, false) + ")";
Predicate<IgniteValues> matcher = isInstanceOf(IgniteValues.class);
assertPlan("SELECT c1 FROM T1 WHERE c1 IN " + value, schema, matcher);
}
/**
- * This test ensures that combination of {@link
#inOperandsLiteralsWithinRange()} and {@link #inOperandsLiteralsOutOfRange()}
- * doesn't miss any type pair from {@link NumericPair}.
+ * This test ensures that combination of {@link
#inOperandsLiteralsWithinRange()} and {@link #inOperandsLiteralsOutOfRange()}
doesn't
+ * miss any type pair from {@link NumericPair}.
*/
@Test
void inOperandsLiteralsIncludeAllPairs() {
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 e4ff3591205..5afb6934c60 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
@@ -64,6 +64,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.sql.SqlDdl;
@@ -116,6 +117,10 @@ import org.mockito.Mockito;
public class DdlSqlToCommandConverterTest extends
AbstractDdlSqlToCommandConverterTest {
private static final Integer TEST_ZONE_ID = 100;
+ private static final List<SqlTypeName> SIGNED_NUMERIC_TYPES =
NUMERIC_TYPES.stream()
+ .filter(t -> !SqlTypeName.UNSIGNED_TYPES.contains(t))
+ .collect(Collectors.toList());
+
@BeforeEach
void setUp() {
Supplier<TableStatsStalenessConfiguration> statStalenessProperties =
() -> new TableStatsStalenessConfiguration(
@@ -379,7 +384,7 @@ public class DdlSqlToCommandConverterTest extends
AbstractDdlSqlToCommandConvert
List<DynamicTest> testItems = new ArrayList<>();
PlanningContext ctx = createContext();
- for (SqlTypeName numType : NUMERIC_TYPES) {
+ for (SqlTypeName numType : SIGNED_NUMERIC_TYPES) {
for (SqlTypeName intervalType : INTERVAL_TYPES) {
RelDataType initialNumType =
Commons.typeFactory().createSqlType(numType);
Object value =
SqlTestUtils.generateValueByType(initialNumType);
@@ -399,7 +404,7 @@ public class DdlSqlToCommandConverterTest extends
AbstractDdlSqlToCommandConvert
PlanningContext ctx = createContext();
for (SqlTypeName intervalType : INTERVAL_TYPES) {
- for (SqlTypeName numType : NUMERIC_TYPES) {
+ for (SqlTypeName numType : SIGNED_NUMERIC_TYPES) {
String value = makeUsableIntervalValue(intervalType.getName());
fillTestCase(numType.getName(), value, testItems, false, ctx);
@@ -504,7 +509,7 @@ public class DdlSqlToCommandConverterTest extends
AbstractDdlSqlToCommandConvert
String[] numbers = {"100.4", "100.6", "100", "'100'", "'100.1'"};
- List<SqlTypeName> typesWithoutDecimal = new ArrayList<>(NUMERIC_TYPES);
+ List<SqlTypeName> typesWithoutDecimal = new
ArrayList<>(SIGNED_NUMERIC_TYPES);
typesWithoutDecimal.remove(DECIMAL);
for (String value : numbers) {
@@ -559,7 +564,7 @@ public class DdlSqlToCommandConverterTest extends
AbstractDdlSqlToCommandConvert
String[] values = {"'01:01:02'", "'2020-01-02 01:01:01'",
"'2020-01-02'", "true", "'true'", "x'01'", "INTERVAL '1' DAY"};
for (String value : values) {
- for (SqlTypeName numericType : NUMERIC_TYPES) {
+ for (SqlTypeName numericType : SIGNED_NUMERIC_TYPES) {
fillTestCase(numericType.getName(), value, testItems, false,
ctx);
}
}
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlReservedWordsTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlReservedWordsTest.java
index a722691dab0..213a95bbd6d 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlReservedWordsTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlReservedWordsTest.java
@@ -219,6 +219,7 @@ public class SqlReservedWordsTest extends
AbstractParserTest {
"USER",
"USING",
"UUID",
+ "UNSIGNED",
"VALUE",
"VALUES",
"VARIANT",
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerTest.java
index 682bb305faf..3d59c2f2668 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/util/QueryCheckerTest.java
@@ -86,7 +86,7 @@ public class QueryCheckerTest extends BaseIgniteAbstractTest {
.mapToObj(i -> List.of("N1"))
.collect(Collectors.toList()));
CLUSTER.setDataProvider("T1",
TestBuilders.tableScan(DataProvider.fromCollection(
- List.of(new Object[]{1, 1, 1, 1, 1}, new Object[]{2, 2, 1, 1,
1})
+ List.of(new Object[]{1, 1, 1, 1, 1}, new Object[]{2, 2, 2, 2,
2})
)));
}
diff --git a/modules/sql-engine/src/test/resources/tpcds/plan/q15.plan
b/modules/sql-engine/src/test/resources/tpcds/plan/q15.plan
index b3ef27d27b1..62d381538cf 100644
--- a/modules/sql-engine/src/test/resources/tpcds/plan/q15.plan
+++ b/modules/sql-engine/src/test/resources/tpcds/plan/q15.plan
@@ -12,7 +12,7 @@ Sort
projection: [CA_ZIP, CS_SALES_PRICE]
est: (rows=111896)
HashJoin
- predicate: AND(=(CS_BILL_CUSTOMER_SK, C_CUSTOMER_SK),
OR(=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'85669'), =(SUBSTR(CA_ZIP, 1, 5),
_UTF-8'86197'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'88274'), =(SUBSTR(CA_ZIP, 1, 5),
_UTF-8'83405'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'86475'), =(SUBSTR(CA_ZIP, 1, 5),
_UTF-8'85392'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'85460'), =(SUBSTR(CA_ZIP, 1, 5),
_UTF-8'80348'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'81792'), SEARCH(CA_STATE,
Sarg[_UTF-8'CA':VARCHAR(2) CHARACTER SET "UTF-8" [...]
+ predicate: AND(=(CS_BILL_CUSTOMER_SK, C_CUSTOMER_SK),
OR(SEARCH(SUBSTR(CA_ZIP, 1, 5), Sarg[_UTF-8'80348':VARCHAR(10) CHARACTER SET
"UTF-8", _UTF-8'81792':VARCHAR(10) CHARACTER SET "UTF-8",
_UTF-8'83405':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'85392':VARCHAR(10)
CHARACTER SET "UTF-8", _UTF-8'85460':VARCHAR(10) CHARACTER SET "UTF-8",
_UTF-8'85669':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'86197':VARCHAR(10)
CHARACTER SET "UTF-8", _UTF-8'86475':VARCHAR(10) CHARACTER SET "UTF-8", [...]
type: inner
est: (rows=111896)
HashJoin
diff --git a/modules/sql-engine/src/test/resources/tpcds/plan/q45.plan
b/modules/sql-engine/src/test/resources/tpcds/plan/q45.plan
index ee142c0d998..d729a0b3b2f 100644
--- a/modules/sql-engine/src/test/resources/tpcds/plan/q45.plan
+++ b/modules/sql-engine/src/test/resources/tpcds/plan/q45.plan
@@ -12,7 +12,7 @@ Limit
projection: [CA_ZIP, CA_COUNTY, WS_SALES_PRICE]
est: (rows=10786141)
Filter
- predicate: OR(=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'85669'),
=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'86197'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'88274'),
=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'83405'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'86475'),
=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'85392'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'85460'),
=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'80348'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'81792'),
IS NOT NULL(i))
+ predicate: OR(SEARCH(SUBSTR(CA_ZIP, 1, 5),
Sarg[_UTF-8'80348':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'81792':VARCHAR(10)
CHARACTER SET "UTF-8", _UTF-8'83405':VARCHAR(10) CHARACTER SET "UTF-8",
_UTF-8'85392':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'85460':VARCHAR(10)
CHARACTER SET "UTF-8", _UTF-8'85669':VARCHAR(10) CHARACTER SET "UTF-8",
_UTF-8'86197':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'86475':VARCHAR(10)
CHARACTER SET "UTF-8", _UTF-8'88274':VARCHAR(10) CHARACTER SET "U [...]
est: (rows=10786141)
HashJoin
predicate: =(I_ITEM_ID, I_ITEM_ID$0)
diff --git a/modules/sql-engine/src/test/resources/tpcds/plan/q50.plan
b/modules/sql-engine/src/test/resources/tpcds/plan/q50.plan
index 9d93f05588f..02aab08763f 100644
--- a/modules/sql-engine/src/test/resources/tpcds/plan/q50.plan
+++ b/modules/sql-engine/src/test/resources/tpcds/plan/q50.plan
@@ -9,7 +9,7 @@ Sort
est: (rows=28459)
Project
fieldNames: [S_STORE_NAME, S_COMPANY_ID, S_STREET_NUMBER,
S_STREET_NAME, S_STREET_TYPE, S_SUITE_NUMBER, S_CITY, S_COUNTY, S_STATE, S_ZIP,
$f10, $f11, $f12, $f13, $f14]
- projection: [S_STORE_NAME, S_COMPANY_ID, S_STREET_NUMBER,
S_STREET_NAME, S_STREET_TYPE, S_SUITE_NUMBER, S_CITY, S_COUNTY, S_STATE, S_ZIP,
CASE(<=(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), 30), 1, 0),
CASE(AND(>(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), 30),
<=(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), 60)), 1, 0),
CASE(AND(>(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), 60),
<=(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), 90)), 1, 0),
CASE(AND(>(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), 90), [...]
+ projection: [S_STORE_NAME, S_COMPANY_ID, S_STREET_NUMBER,
S_STREET_NAME, S_STREET_TYPE, S_SUITE_NUMBER, S_CITY, S_COUNTY, S_STATE, S_ZIP,
CASE(<=(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), 30), 1, 0),
CASE(SEARCH(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), Sarg[(30..60]]), 1, 0),
CASE(SEARCH(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), Sarg[(60..90]]), 1, 0),
CASE(SEARCH(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), Sarg[(90..120]]), 1, 0),
CASE(>(-(SR_RETURNED_DATE_SK, SS_SOLD_DATE_SK), 120), 1, 0)]
est: (rows=31882)
HashJoin
predicate: =(SS_STORE_SK, S_STORE_SK)
diff --git a/modules/sql-engine/src/test/resources/tpcds/plan/q62.plan
b/modules/sql-engine/src/test/resources/tpcds/plan/q62.plan
index ab5c0227e2b..24d69c6a993 100644
--- a/modules/sql-engine/src/test/resources/tpcds/plan/q62.plan
+++ b/modules/sql-engine/src/test/resources/tpcds/plan/q62.plan
@@ -9,7 +9,7 @@ Sort
est: (rows=87765)
Project
fieldNames: [EXPR$0, SM_TYPE, WEB_NAME, $f3, $f4, $f5, $f6, $f7]
- projection: [SUBSTR(W_WAREHOUSE_NAME, 1, 20), SM_TYPE, WEB_NAME,
CASE(<=(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK), 30), 1, 0),
CASE(AND(>(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK), 30), <=(-(WS_SHIP_DATE_SK,
WS_SOLD_DATE_SK), 60)), 1, 0), CASE(AND(>(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK),
60), <=(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK), 90)), 1, 0),
CASE(AND(>(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK), 90), <=(-(WS_SHIP_DATE_SK,
WS_SOLD_DATE_SK), 120)), 1, 0), CASE(>(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK),
[...]
+ projection: [SUBSTR(W_WAREHOUSE_NAME, 1, 20), SM_TYPE, WEB_NAME,
CASE(<=(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK), 30), 1, 0),
CASE(SEARCH(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK), Sarg[(30..60]]), 1, 0),
CASE(SEARCH(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK), Sarg[(60..90]]), 1, 0),
CASE(SEARCH(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK), Sarg[(90..120]]), 1, 0),
CASE(>(-(WS_SHIP_DATE_SK, WS_SOLD_DATE_SK), 120), 1, 0)]
est: (rows=179846)
HashJoin
predicate: =(WS_WAREHOUSE_SK, W_WAREHOUSE_SK)
diff --git a/modules/sql-engine/src/test/resources/tpcds/plan/q64.plan
b/modules/sql-engine/src/test/resources/tpcds/plan/q64.plan
index c663026fbf3..7a99a7e3fc8 100644
--- a/modules/sql-engine/src/test/resources/tpcds/plan/q64.plan
+++ b/modules/sql-engine/src/test/resources/tpcds/plan/q64.plan
@@ -180,7 +180,7 @@ Sort
est: (rows=2250)
TableScan
table: PUBLIC.ITEM
- predicate: AND(SEARCH(I_COLOR,
Sarg[_UTF-8'azure':VARCHAR(20) CHARACTER SET "UTF-8", _UTF-8'blush':VARCHAR(20)
CHARACTER SET "UTF-8", _UTF-8'gainsboro':VARCHAR(20) CHARACTER SET "UTF-8",
_UTF-8'hot':VARCHAR(20) CHARACTER SET "UTF-8", _UTF-8'lemon':VARCHAR(20)
CHARACTER SET "UTF-8", _UTF-8'misty':VARCHAR(20) CHARACTER SET
"UTF-8"]:VARCHAR(20) CHARACTER SET "UTF-8"), >=(I_CURRENT_PRICE, 80.00),
SEARCH(CAST(I_CURRENT_PRICE):DECIMAL(12, 2), Sar [...]
+ predicate: AND(SEARCH(I_COLOR,
Sarg[_UTF-8'azure':VARCHAR(20) CHARACTER SET "UTF-8", _UTF-8'blush':VARCHAR(20)
CHARACTER SET "UTF-8", _UTF-8'gainsboro':VARCHAR(20) CHARACTER SET "UTF-8",
_UTF-8'hot':VARCHAR(20) CHARACTER SET "UTF-8", _UTF-8'lemon':VARCHAR(20)
CHARACTER SET "UTF-8", _UTF-8'misty':VARCHAR(20) CHARACTER SET
"UTF-8"]:VARCHAR(20) CHARACTER SET "UTF-8"), >=(I_CURRENT_PRICE, 80.00),
SEARCH(CAST(I_CURRENT_PRICE):DECIMAL(12, 2), Sar [...]
fieldNames: [I_ITEM_SK,
I_CURRENT_PRICE, I_COLOR, I_PRODUCT_NAME]
est: (rows=2250)
Filter
@@ -413,7 +413,7 @@ Sort
est: (rows=2250)
TableScan
table: PUBLIC.ITEM
- predicate: AND(SEARCH(I_COLOR,
Sarg[_UTF-8'azure':VARCHAR(20) CHARACTER SET "UTF-8", _UTF-8'blush':VARCHAR(20)
CHARACTER SET "UTF-8", _UTF-8'gainsboro':VARCHAR(20) CHARACTER SET "UTF-8",
_UTF-8'hot':VARCHAR(20) CHARACTER SET "UTF-8", _UTF-8'lemon':VARCHAR(20)
CHARACTER SET "UTF-8", _UTF-8'misty':VARCHAR(20) CHARACTER SET
"UTF-8"]:VARCHAR(20) CHARACTER SET "UTF-8"), >=(I_CURRENT_PRICE, 80.00),
SEARCH(CAST(I_CURRENT_PRICE):DECIMAL(12, 2), Sar [...]
+ predicate: AND(SEARCH(I_COLOR,
Sarg[_UTF-8'azure':VARCHAR(20) CHARACTER SET "UTF-8", _UTF-8'blush':VARCHAR(20)
CHARACTER SET "UTF-8", _UTF-8'gainsboro':VARCHAR(20) CHARACTER SET "UTF-8",
_UTF-8'hot':VARCHAR(20) CHARACTER SET "UTF-8", _UTF-8'lemon':VARCHAR(20)
CHARACTER SET "UTF-8", _UTF-8'misty':VARCHAR(20) CHARACTER SET
"UTF-8"]:VARCHAR(20) CHARACTER SET "UTF-8"), >=(I_CURRENT_PRICE, 80.00),
SEARCH(CAST(I_CURRENT_PRICE):DECIMAL(12, 2), Sar [...]
fieldNames: [I_ITEM_SK,
I_CURRENT_PRICE, I_COLOR, I_PRODUCT_NAME]
est: (rows=2250)
Filter
diff --git a/modules/sql-engine/src/test/resources/tpcds/plan/q78.plan
b/modules/sql-engine/src/test/resources/tpcds/plan/q78.plan
index 48856fdbfbd..07699e582b6 100644
--- a/modules/sql-engine/src/test/resources/tpcds/plan/q78.plan
+++ b/modules/sql-engine/src/test/resources/tpcds/plan/q78.plan
@@ -7,7 +7,7 @@ Sort
projection: [SS_CUSTOMER_SK, ROUND(/(SS_QTY, +(CASE(IS NOT NULL(WS_QTY),
CAST(WS_QTY):BIGINT NOT NULL, 0:BIGINT), CASE(IS NOT NULL(CS_QTY),
CAST(CS_QTY):BIGINT NOT NULL, 0:BIGINT))), 2), SS_QTY, SS_WC, SS_SP, +(CASE(IS
NOT NULL(WS_QTY), CAST(WS_QTY):BIGINT NOT NULL, 0:BIGINT), CASE(IS NOT
NULL(CS_QTY), CAST(CS_QTY):BIGINT NOT NULL, 0:BIGINT)), +(CASE(IS NOT
NULL(WS_WC), CAST(WS_WC):DECIMAL(14, 2) NOT NULL, 0.00:DECIMAL(14, 2)), CASE(IS
NOT NULL(CS_WC), CAST(CS_WC):DECIMAL(14, 2) NO [...]
est: (rows=5169421725)
Filter
- predicate: OR(CASE(IS NOT NULL(WS_QTY), >(CAST(WS_QTY):BIGINT NOT
NULL, 0), false), CASE(IS NOT NULL(CS_QTY), >(CAST(CS_QTY):BIGINT NOT NULL, 0),
false))
+ predicate: OR(>(CAST(WS_QTY):BIGINT NOT NULL, 0),
>(CAST(CS_QTY):BIGINT NOT NULL, 0))
est: (rows=5169421725)
MergeJoin
predicate: AND(=(CS_SOLD_YEAR, SS_SOLD_YEAR), =(CS_ITEM_SK,
SS_ITEM_SK), =(CS_CUSTOMER_SK, SS_CUSTOMER_SK))
diff --git a/modules/sql-engine/src/test/resources/tpcds/plan/q8.plan
b/modules/sql-engine/src/test/resources/tpcds/plan/q8.plan
index cf3561a60b9..405ff63bd96 100644
--- a/modules/sql-engine/src/test/resources/tpcds/plan/q8.plan
+++ b/modules/sql-engine/src/test/resources/tpcds/plan/q8.plan
@@ -67,16 +67,16 @@ Limit
est: (rows=832)
TableScan
table: PUBLIC.CUSTOMER_ADDRESS
- predicate: OR(=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'47602'),
=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'16704'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'35863'),
=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'28577'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'83910'),
=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'36201'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'58412'),
=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'48162'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'28055'),
=(SUBSTR(CA_ZIP, 1, 5), _UTF-8'41419'), =(SUBSTR(CA_ZIP, 1, 5), _UTF-8'80332'),
=(SUBSTR(CA_ZIP, 1 [...]
+ predicate: SEARCH(SUBSTR(CA_ZIP, 1, 5),
Sarg[_UTF-8'10298':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'10374':VARCHAR(10)
CHARACTER SET "UTF-8", _UTF-8'10425':VARCHAR(10) CHARACTER SET "UTF-8",
_UTF-8'11340':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'11489':VARCHAR(10)
CHARACTER SET "UTF-8", _UTF-8'11618':VARCHAR(10) CHARACTER SET "UTF-8",
_UTF-8'11652':VARCHAR(10) CHARACTER SET "UTF-8", _UTF-8'11686':VARCHAR(10)
CHARACTER SET "UTF-8", _UTF-8'11855':VARCHAR(10) CHARACTER [...]
fieldNames: [CA_ZIP]
projection: [SUBSTR(CA_ZIP, 1, 5)]
est: (rows=50000)
Exchange
- distribution: hash by [CA_ZIP]
+ distribution: random
est: (rows=1665)
Project
fieldNames: [CA_ZIP]
- projection: [CA_ZIP]
+ projection: [SUBSTR(CA_ZIP, 1, 5)]
est: (rows=1665)
Filter
predicate: >(CNT, 10)
@@ -100,7 +100,7 @@ Limit
est: (rows=3330)
Project
fieldNames: [CA_ZIP]
- projection: [SUBSTR(CA_ZIP, 1, 5)]
+ projection: [CA_ZIP]
est: (rows=33300)
HashJoin
predicate: =(CA_ADDRESS_SK,
C_CURRENT_ADDR_SK)
diff --git a/modules/sql-engine/src/test/resources/tpcds/plan/q99.plan
b/modules/sql-engine/src/test/resources/tpcds/plan/q99.plan
index a2e0190149c..2688302c3f1 100644
--- a/modules/sql-engine/src/test/resources/tpcds/plan/q99.plan
+++ b/modules/sql-engine/src/test/resources/tpcds/plan/q99.plan
@@ -9,7 +9,7 @@ Sort
est: (rows=175869)
Project
fieldNames: [EXPR$0, SM_TYPE, CC_NAME, $f3, $f4, $f5, $f6, $f7]
- projection: [SUBSTR(W_WAREHOUSE_NAME, 1, 20), SM_TYPE, CC_NAME,
CASE(<=(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK), 30), 1, 0),
CASE(AND(>(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK), 30), <=(-(CS_SHIP_DATE_SK,
CS_SOLD_DATE_SK), 60)), 1, 0), CASE(AND(>(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK),
60), <=(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK), 90)), 1, 0),
CASE(AND(>(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK), 90), <=(-(CS_SHIP_DATE_SK,
CS_SOLD_DATE_SK), 120)), 1, 0), CASE(>(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK),
[...]
+ projection: [SUBSTR(W_WAREHOUSE_NAME, 1, 20), SM_TYPE, CC_NAME,
CASE(<=(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK), 30), 1, 0),
CASE(SEARCH(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK), Sarg[(30..60]]), 1, 0),
CASE(SEARCH(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK), Sarg[(60..90]]), 1, 0),
CASE(SEARCH(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK), Sarg[(90..120]]), 1, 0),
CASE(>(-(CS_SHIP_DATE_SK, CS_SOLD_DATE_SK), 120), 1, 0)]
est: (rows=360387)
HashJoin
predicate: =(CS_WAREHOUSE_SK, W_WAREHOUSE_SK)
diff --git a/modules/sql-engine/src/test/resources/tpch/plan/q22.plan
b/modules/sql-engine/src/test/resources/tpch/plan/q22.plan
index 68dece05424..a5e44808e5a 100644
--- a/modules/sql-engine/src/test/resources/tpch/plan/q22.plan
+++ b/modules/sql-engine/src/test/resources/tpch/plan/q22.plan
@@ -31,7 +31,7 @@ Sort
est: (rows=150000)
TableScan
table: PUBLIC.CUSTOMER
- predicate: OR(=(SUBSTR(C_PHONE, 1, 2), _UTF-8'13'),
=(SUBSTR(C_PHONE, 1, 2), _UTF-8'31'), =(SUBSTR(C_PHONE, 1, 2), _UTF-8'23'),
=(SUBSTR(C_PHONE, 1, 2), _UTF-8'29'), =(SUBSTR(C_PHONE, 1, 2), _UTF-8'30'),
=(SUBSTR(C_PHONE, 1, 2), _UTF-8'18'), =(SUBSTR(C_PHONE, 1, 2), _UTF-8'17'))
+ predicate: SEARCH(SUBSTR(C_PHONE, 1, 2),
Sarg[_UTF-8'13':VARCHAR(15) CHARACTER SET "UTF-8", _UTF-8'17':VARCHAR(15)
CHARACTER SET "UTF-8", _UTF-8'18':VARCHAR(15) CHARACTER SET "UTF-8",
_UTF-8'23':VARCHAR(15) CHARACTER SET "UTF-8", _UTF-8'29':VARCHAR(15) CHARACTER
SET "UTF-8", _UTF-8'30':VARCHAR(15) CHARACTER SET "UTF-8",
_UTF-8'31':VARCHAR(15) CHARACTER SET "UTF-8"]:VARCHAR(15) CHARACTER SET "UTF-8")
fieldNames: [C_CUSTKEY, C_PHONE, C_ACCTBAL]
est: (rows=150000)
Project
@@ -59,7 +59,7 @@ Sort
est: (rows=1)
TableScan
table: PUBLIC.CUSTOMER
- predicate: AND(>(C_ACCTBAL, 0.00),
OR(=(SUBSTR(C_PHONE, 1, 2), _UTF-8'13'), =(SUBSTR(C_PHONE, 1, 2), _UTF-8'31'),
=(SUBSTR(C_PHONE, 1, 2), _UTF-8'23'), =(SUBSTR(C_PHONE, 1, 2), _UTF-8'29'),
=(SUBSTR(C_PHONE, 1, 2), _UTF-8'30'), =(SUBSTR(C_PHONE, 1, 2), _UTF-8'18'),
=(SUBSTR(C_PHONE, 1, 2), _UTF-8'17')))
+ predicate: AND(>(C_ACCTBAL, 0.00),
SEARCH(SUBSTR(C_PHONE, 1, 2), Sarg[_UTF-8'13':VARCHAR(15) CHARACTER SET
"UTF-8", _UTF-8'17':VARCHAR(15) CHARACTER SET "UTF-8", _UTF-8'18':VARCHAR(15)
CHARACTER SET "UTF-8", _UTF-8'23':VARCHAR(15) CHARACTER SET "UTF-8",
_UTF-8'29':VARCHAR(15) CHARACTER SET "UTF-8", _UTF-8'30':VARCHAR(15) CHARACTER
SET "UTF-8", _UTF-8'31':VARCHAR(15) CHARACTER SET "UTF-8"]:VARCHAR(15)
CHARACTER SET "UTF-8"))
fieldNames: [C_ACCTBAL]
est: (rows=75000)
ReduceHashAggregate