diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteScalarFunction.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteScalarFunction.java index 8c43f5a8620eb..09f377e3560bc 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteScalarFunction.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/IgniteScalarFunction.java @@ -26,28 +26,41 @@ * Implementation of {@link ScalarFunction} for Ignite user defined functions. */ public class IgniteScalarFunction extends IgniteReflectiveFunctionBase implements ScalarFunction { + /** */ + private final boolean deterministic; + /** * Private constructor. */ - private IgniteScalarFunction(Method method, CallImplementor implementor) { + private IgniteScalarFunction(Method method, CallImplementor implementor, boolean deterministic) { super(method, implementor); + + this.deterministic = deterministic; } /** * Creates {@link ScalarFunction} from given method. * * @param method Method that is used to implement the function. + * @param deterministic Is function deterministic. * @return Created {@link ScalarFunction}. */ - public static ScalarFunction create(Method method) { + public static ScalarFunction create(Method method, boolean deterministic) { CallImplementor implementor = RexImpTable.createImplementor( new ReflectiveCallNotNullImplementor(method), NullPolicy.NONE, false); - return new IgniteScalarFunction(method, implementor); + return new IgniteScalarFunction(method, implementor, deterministic); } /** {@inheritDoc} */ @Override public RelDataType getReturnType(RelDataTypeFactory typeFactory) { return typeFactory.createJavaType(method.getReturnType()); } + + /** + * @return Deterministic flag. + */ + public boolean isDeterministic() { + return deterministic; + } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexExecutorImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexExecutorImpl.java index 3fe6d8c37b09f..eb1297bcc592d 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexExecutorImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/RexExecutorImpl.java @@ -19,7 +19,6 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.List; - import com.google.common.collect.ImmutableList; import org.apache.calcite.DataContext; import org.apache.calcite.adapter.java.JavaTypeFactory; @@ -35,14 +34,19 @@ import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rex.RexBuilder; +import org.apache.calcite.rex.RexCall; import org.apache.calcite.rex.RexExecutable; import org.apache.calcite.rex.RexExecutor; import org.apache.calcite.rex.RexNode; import org.apache.calcite.rex.RexProgram; import org.apache.calcite.rex.RexProgramBuilder; +import org.apache.calcite.rex.RexVisitor; +import org.apache.calcite.rex.RexVisitorImpl; import org.apache.calcite.sql.validate.SqlConformance; import org.apache.calcite.sql.validate.SqlConformanceEnum; +import org.apache.calcite.sql.validate.SqlUserDefinedFunction; import org.apache.calcite.util.BuiltInMethod; +import org.apache.calcite.util.ControlFlowException; import org.apache.calcite.util.Util; import org.apache.ignite.internal.processors.query.calcite.type.IgniteCustomType; @@ -133,12 +137,34 @@ public static RexExecutable getExecutable(RexBuilder rexBuilder, List e * Do constant reduction using generated code. */ @Override public void reduce(RexBuilder rexBuilder, List constExps, List reducedValues) { + RexVisitor nonDeterministicUdfFinder = new RexVisitorImpl(true) { + @Override public Void visitCall(RexCall call) { + if (call.getOperator() instanceof SqlUserDefinedFunction) { + SqlUserDefinedFunction udfFunc = (SqlUserDefinedFunction)call.getOperator(); + + if (udfFunc.getFunction() instanceof IgniteScalarFunction + && !((IgniteScalarFunction)udfFunc.getFunction()).isDeterministic()) + throw Util.FoundOne.NULL; // Don't reduce non-deterministic UDF functions. + } + + return super.visitCall(call); + } + }; + for (RexNode node : constExps) { // Do not simplify custom types, since we can't convert it to literal of this type. if (node.getType() instanceof IgniteCustomType) { reducedValues.addAll(constExps); return; } + + try { + node.accept(nonDeterministicUdfFinder); + } + catch (ControlFlowException foundNonDeterministic) { + reducedValues.addAll(constExps); + return; + } } final String code = compile(rexBuilder, constExps, (list, index, storageType) -> { diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerHelper.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerHelper.java index 289a7b9b47348..1cef9ab4ce633 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerHelper.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerHelper.java @@ -127,10 +127,10 @@ public static IgniteRel optimize(SqlNode sqlNode, IgnitePlanner planner, IgniteL rel = planner.extractConjunctionOverDisjunctionCommonPart(rel); - rel = planner.trimUnusedFields(root.withRel(rel)).rel; - rel = planner.transform(PlannerPhase.HEP_FILTER_PUSH_DOWN, rel.getTraitSet(), rel); + rel = planner.trimUnusedFields(root.withRel(rel)).rel; + // The following pushed down project can erase top-level hints. We store them to reassign hints for join nodes. // Clear the inherit pathes to consider the hints as not propogated ones. List topHints = HintUtils.allRelHints(rel).stream().map(h -> h.inheritPath.isEmpty() diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerPhase.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerPhase.java index 0ff9ae9510bf8..b8333a541663f 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerPhase.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/PlannerPhase.java @@ -108,6 +108,7 @@ public enum PlannerPhase { @Override public RuleSet getRules(PlanningContext ctx) { return ctx.rules( RuleSets.ofList( + CoreRules.FILTER_REDUCE_EXPRESSIONS, FilterScanMergeRule.TABLE_SCAN_SKIP_CORRELATED, CoreRules.FILTER_MERGE, diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/AbstractIndexScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/AbstractIndexScan.java index 40efc54172ef1..c5041d4c773b0 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/AbstractIndexScan.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/AbstractIndexScan.java @@ -27,6 +27,7 @@ import org.apache.calcite.rel.RelInput; import org.apache.calcite.rel.RelWriter; import org.apache.calcite.rel.metadata.RelMetadataQuery; +import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexNode; import org.apache.calcite.rex.RexUtil; @@ -67,12 +68,13 @@ protected AbstractIndexScan( RelTraitSet traitSet, RelOptTable table, String idxName, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable List searchBounds, @Nullable ImmutableBitSet reqColumns ) { - super(cluster, traitSet, Collections.emptyList(), table, proj, cond, reqColumns); + super(cluster, traitSet, Collections.emptyList(), table, rowType, proj, cond, reqColumns); this.idxName = idxName; this.searchBounds = searchBounds; diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexScan.java index 066e1b9d37c41..a7397ffcedbeb 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexScan.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteIndexScan.java @@ -24,6 +24,7 @@ import org.apache.calcite.rel.RelCollation; import org.apache.calcite.rel.RelInput; import org.apache.calcite.rel.RelWriter; +import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.ImmutableBitSet; import org.apache.ignite.internal.processors.query.calcite.prepare.bounds.SearchBounds; @@ -64,6 +65,7 @@ public IgniteIndexScan(RelInput input) { * @param traits Traits of this relational expression * @param tbl Table definition. * @param idxName Index name. + * @param rowType Row type. * @param proj Projects. * @param cond Filters. * @param requiredCols Participating columns. @@ -74,13 +76,14 @@ public IgniteIndexScan( RelTraitSet traits, RelOptTable tbl, String idxName, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable List searchBounds, @Nullable ImmutableBitSet requiredCols, RelCollation collation ) { - this(-1L, cluster, traits, tbl, idxName, proj, cond, searchBounds, requiredCols, collation); + this(-1L, cluster, traits, tbl, idxName, rowType, proj, cond, searchBounds, requiredCols, collation); } /** @@ -89,6 +92,7 @@ public IgniteIndexScan( * @param traits Traits of this relational expression * @param tbl Table definition. * @param idxName Index name. + * @param rowType Row type. * @param proj Projects. * @param cond Filters. * @param requiredCols Participating colunms. @@ -100,13 +104,14 @@ private IgniteIndexScan( RelTraitSet traits, RelOptTable tbl, String idxName, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable List searchBounds, @Nullable ImmutableBitSet requiredCols, RelCollation collation ) { - super(cluster, traits, tbl, idxName, proj, cond, searchBounds, requiredCols); + super(cluster, traits, tbl, idxName, rowType, proj, cond, searchBounds, requiredCols); this.sourceId = sourceId; this.collation = collation; @@ -132,13 +137,13 @@ private IgniteIndexScan( /** {@inheritDoc} */ @Override public IgniteRel clone(long sourceId) { return new IgniteIndexScan(sourceId, getCluster(), getTraitSet(), getTable(), - idxName, projects, condition, searchBounds, requiredColumns, collation); + idxName, rowType, projects, condition, searchBounds, requiredColumns, collation); } /** {@inheritDoc} */ @Override public IgniteRel clone(RelOptCluster cluster, List inputs) { return new IgniteIndexScan(sourceId, cluster, getTraitSet(), getTable(), - idxName, projects, condition, searchBounds, requiredColumns, collation); + idxName, rowType, projects, condition, searchBounds, requiredColumns, collation); } /** {@inheritDoc} */ diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteTableScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteTableScan.java index 6291a5433b661..c35b415f1974e 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteTableScan.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/IgniteTableScan.java @@ -24,6 +24,7 @@ import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.RelInput; import org.apache.calcite.rel.RelWriter; +import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.ImmutableBitSet; import org.jetbrains.annotations.Nullable; @@ -63,7 +64,7 @@ public IgniteTableScan( RelTraitSet traits, RelOptTable tbl ) { - this(cluster, traits, tbl, null, null, null); + this(cluster, traits, tbl, null, null, null, null); } /** @@ -71,6 +72,7 @@ public IgniteTableScan( * @param cluster Cluster that this relational expression belongs to * @param traits Traits of this relational expression * @param tbl Table definition. + * @param rowType Row type. * @param proj Projects. * @param cond Filters. * @param requiredColunms Participating colunms. @@ -79,11 +81,12 @@ public IgniteTableScan( RelOptCluster cluster, RelTraitSet traits, RelOptTable tbl, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable ImmutableBitSet requiredColunms ) { - this(-1L, cluster, traits, tbl, proj, cond, requiredColunms); + this(-1L, cluster, traits, tbl, rowType, proj, cond, requiredColunms); } /** @@ -91,6 +94,7 @@ public IgniteTableScan( * @param cluster Cluster that this relational expression belongs to * @param traits Traits of this relational expression * @param tbl Table definition. + * @param rowType Row type. * @param proj Projects. * @param cond Filters. * @param requiredColunms Participating colunms. @@ -100,11 +104,12 @@ private IgniteTableScan( RelOptCluster cluster, RelTraitSet traits, RelOptTable tbl, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable ImmutableBitSet requiredColunms ) { - super(cluster, traits, ImmutableList.of(), tbl, proj, cond, requiredColunms); + super(cluster, traits, ImmutableList.of(), tbl, rowType, proj, cond, requiredColunms); this.sourceId = sourceId; } @@ -126,11 +131,13 @@ private IgniteTableScan( /** {@inheritDoc} */ @Override public IgniteRel clone(long sourceId) { - return new IgniteTableScan(sourceId, getCluster(), getTraitSet(), getTable(), projects, condition, requiredColumns); + return new IgniteTableScan(sourceId, getCluster(), getTraitSet(), getTable(), rowType, projects, condition, + requiredColumns); } /** {@inheritDoc} */ @Override public IgniteRel clone(RelOptCluster cluster, List inputs) { - return new IgniteTableScan(sourceId, cluster, getTraitSet(), getTable(), projects, condition, requiredColumns); + return new IgniteTableScan(sourceId, cluster, getTraitSet(), getTable(), rowType, projects, condition, + requiredColumns); } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/ProjectableFilterableTableScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/ProjectableFilterableTableScan.java index 9c41fdd9e3db4..bef05a9b5e3a1 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/ProjectableFilterableTableScan.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/ProjectableFilterableTableScan.java @@ -75,12 +75,16 @@ protected ProjectableFilterableTableScan( RelTraitSet traitSet, List hints, RelOptTable table, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable ImmutableBitSet reqColumns ) { super(cluster, traitSet, hints, table); + assert proj == null || rowType != null : "rowType should be provided if project != null"; + + this.rowType = rowType; projects = proj; condition = cond; requiredColumns = reqColumns; @@ -90,6 +94,7 @@ protected ProjectableFilterableTableScan( protected ProjectableFilterableTableScan(RelInput input) { super(input); condition = input.getExpression("filters"); + rowType = input.get("rowType") == null ? null : input.getRowType("rowType"); projects = input.get("projects") == null ? null : input.getExpressionList("projects"); requiredColumns = input.get("requiredColumns") == null ? null : input.getBitSet("requiredColumns"); } @@ -129,6 +134,7 @@ protected RelWriter explainTerms0(RelWriter pw) { } return pw + .itemIf("rowType", rowType, projects != null) // Intentional project check here. .itemIf("projects", projects, projects != null) .itemIf("requiredColumns", requiredColumns, requiredColumns != null); } @@ -151,10 +157,9 @@ protected RelWriter explainTerms0(RelWriter pw) { /** {@inheritDoc} */ @Override public RelDataType deriveRowType() { - if (projects != null) - return RexUtil.createStructType(Commons.typeFactory(getCluster()), projects); - else - return table.unwrap(IgniteTable.class).getRowType(Commons.typeFactory(getCluster()), requiredColumns); + assert projects == null : "For merged projects rowType should be provided explicetely"; + + return table.unwrap(IgniteTable.class).getRowType(Commons.typeFactory(getCluster()), requiredColumns); } /** */ diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalIndexScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalIndexScan.java index 2602c21ded6d3..c0cfa088e6f39 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalIndexScan.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalIndexScan.java @@ -21,6 +21,7 @@ import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.plan.RelTraitSet; +import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.ImmutableBitSet; import org.apache.ignite.internal.processors.query.calcite.prepare.bounds.SearchBounds; @@ -37,6 +38,7 @@ public static IgniteLogicalIndexScan create( RelTraitSet traits, RelOptTable table, String idxName, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable ImmutableBitSet requiredColumns @@ -51,6 +53,7 @@ public static IgniteLogicalIndexScan create( traits, table, idxName, + rowType, proj, cond, searchBounds, @@ -63,6 +66,7 @@ public static IgniteLogicalIndexScan create( * @param traits Traits of this relational expression * @param tbl Table definition. * @param idxName Index name. + * @param rowType Row type. * @param proj Projects. * @param cond Filters. * @param searchBounds Index search bounds. @@ -73,11 +77,12 @@ private IgniteLogicalIndexScan( RelTraitSet traits, RelOptTable tbl, String idxName, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable List searchBounds, @Nullable ImmutableBitSet requiredCols ) { - super(cluster, traits, tbl, idxName, proj, cond, searchBounds, requiredCols); + super(cluster, traits, tbl, idxName, rowType, proj, cond, searchBounds, requiredCols); } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalTableScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalTableScan.java index caa08a90aef58..1cbd7544bf553 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalTableScan.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rel/logical/IgniteLogicalTableScan.java @@ -24,6 +24,7 @@ import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.hint.RelHint; +import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.ImmutableBitSet; import org.apache.ignite.internal.processors.query.calcite.rel.ProjectableFilterableTableScan; @@ -37,12 +38,13 @@ public static IgniteLogicalTableScan create( RelTraitSet traits, RelOptTable tbl, @Nullable List hints, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable ImmutableBitSet requiredColumns ) { - return new IgniteLogicalTableScan(cluster, traits, tbl, hints == null ? ImmutableList.of() : hints, proj, cond, - requiredColumns); + return new IgniteLogicalTableScan(cluster, traits, tbl, hints == null ? ImmutableList.of() : hints, + rowType, proj, cond, requiredColumns); } /** @@ -51,6 +53,7 @@ public static IgniteLogicalTableScan create( * @param traits Traits of this relational expression. * @param tbl Table definition. * @param hints Hints. + * @param rowType Row type. * @param proj Projects. * @param cond Filters. * @param requiredColunms Participating colunms. @@ -60,16 +63,17 @@ private IgniteLogicalTableScan( RelTraitSet traits, RelOptTable tbl, List hints, + @Nullable RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable ImmutableBitSet requiredColunms ) { - super(cluster, traits, hints, tbl, proj, cond, requiredColunms); + super(cluster, traits, hints, tbl, rowType, proj, cond, requiredColunms); } /** {@inheritDoc} */ @Override public IgniteLogicalTableScan withHints(List hints) { - return new IgniteLogicalTableScan(getCluster(), getTraitSet(), getTable(), hints, projects(), condition(), - requiredColumns()); + return new IgniteLogicalTableScan(getCluster(), getTraitSet(), getTable(), hints, + rowType, projects(), condition(), requiredColumns()); } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/LogicalScanConverterRule.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/LogicalScanConverterRule.java index 3d3f98c91864a..3496ff37ed993 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/LogicalScanConverterRule.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/LogicalScanConverterRule.java @@ -111,6 +111,7 @@ public abstract class LogicalScanConverterRule proj = scan.projects(); RexNode condition = scan.condition(); ImmutableBitSet requiredCols = scan.requiredColumns(); @@ -83,7 +85,7 @@ private static boolean preMatch(IgniteLogicalTableScan scan) { return; List indexes = igniteTable.indexes().values().stream() - .map(idx -> idx.toRel(cluster, optTable, proj, condition, requiredCols)) + .map(idx -> idx.toRel(cluster, optTable, rowType, proj, condition, requiredCols)) .collect(Collectors.toList()); assert !indexes.isEmpty(); diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/FilterScanMergeRule.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/FilterScanMergeRule.java index f1c2ca78d3ef1..1b886792e5da3 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/FilterScanMergeRule.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/FilterScanMergeRule.java @@ -158,7 +158,7 @@ private FilterIndexScanMergeRule(FilterScanMergeRule.Config cfg) { return null; } - return IgniteLogicalIndexScan.create(cluster, traits, scan.getTable(), scan.indexName(), + return IgniteLogicalIndexScan.create(cluster, traits, scan.getTable(), scan.indexName(), scan.getRowType(), scan.projects(), cond, scan.requiredColumns()); } } @@ -177,8 +177,8 @@ private FilterTableScanMergeRule(FilterScanMergeRule.Config cfg) { RelTraitSet traits, RexNode cond ) { - return IgniteLogicalTableScan.create(cluster, traits, scan.getTable(), scan.getHints(), scan.projects(), - cond, scan.requiredColumns()); + return IgniteLogicalTableScan.create(cluster, traits, scan.getTable(), scan.getHints(), scan.getRowType(), + scan.projects(), cond, scan.requiredColumns()); } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/LogicalOrToUnionRule.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/LogicalOrToUnionRule.java index 78315018970c3..73901351c9641 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/LogicalOrToUnionRule.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/LogicalOrToUnionRule.java @@ -165,6 +165,7 @@ private void buildInput(RelBuilder relBldr, RelNode input, RexNode condition) { trait, scan.getTable(), scan.getHints(), + scan.getRowType(), scan.projects(), condition, scan.requiredColumns() diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/ProjectScanMergeRule.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/ProjectScanMergeRule.java index 739e17f868ac3..5a1ecc832179d 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/ProjectScanMergeRule.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/logical/ProjectScanMergeRule.java @@ -24,6 +24,7 @@ import org.apache.calcite.plan.RelRule; import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.logical.LogicalProject; +import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLocalRef; import org.apache.calcite.rex.RexNode; @@ -58,6 +59,7 @@ public abstract class ProjectScanMergeRule projections, RexNode cond, ImmutableBitSet requiredColumns @@ -140,7 +142,7 @@ private ProjectScanMergeRule(Config config) { if (RexUtils.isIdentity(projects, tbl.getRowType(typeFactory, requiredColumns), true)) projects = null; - T res = createNode(cluster, scan, traits, projects, cond, requiredColumns); + T res = createNode(cluster, scan, traits, relProject.getRowType(), projects, cond, requiredColumns); if (res == null) return; @@ -167,6 +169,7 @@ private ProjectTableScanMergeRule(ProjectScanMergeRule.Config config) { RelOptCluster cluster, IgniteLogicalTableScan scan, RelTraitSet traits, + RelDataType rowType, List projections, RexNode cond, ImmutableBitSet requiredColumns @@ -176,6 +179,7 @@ private ProjectTableScanMergeRule(ProjectScanMergeRule.Config config) { traits, scan.getTable(), scan.getHints(), + rowType, projections, cond, requiredColumns @@ -199,6 +203,7 @@ private ProjectIndexScanMergeRule(ProjectScanMergeRule.Config config) { RelOptCluster cluster, IgniteLogicalIndexScan scan, RelTraitSet traits, + RelDataType rowType, List projections, RexNode cond, ImmutableBitSet requiredColumns @@ -214,6 +219,7 @@ private ProjectIndexScanMergeRule(ProjectScanMergeRule.Config config) { traits, scan.getTable(), scan.indexName(), + rowType, projections, cond, requiredColumns ); diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheIndexImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheIndexImpl.java index c09544f96fa95..3806436eb8731 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheIndexImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheIndexImpl.java @@ -21,7 +21,6 @@ import java.util.List; import java.util.UUID; import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelCollation; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexNode; @@ -42,7 +41,6 @@ import org.apache.ignite.internal.processors.query.calcite.exec.exp.RangeIterable; import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup; import org.apache.ignite.internal.processors.query.calcite.prepare.bounds.SearchBounds; -import org.apache.ignite.internal.processors.query.calcite.rel.logical.IgniteLogicalIndexScan; import org.apache.ignite.internal.processors.query.calcite.util.Commons; import org.apache.ignite.internal.processors.query.calcite.util.RexUtils; import org.jetbrains.annotations.Nullable; @@ -91,17 +89,6 @@ public Index queryIndex() { return idx; } - /** {@inheritDoc} */ - @Override public IgniteLogicalIndexScan toRel( - RelOptCluster cluster, - RelOptTable relOptTbl, - @Nullable List proj, - @Nullable RexNode cond, - @Nullable ImmutableBitSet requiredColumns - ) { - return IgniteLogicalIndexScan.create(cluster, cluster.traitSet(), relOptTbl, idxName, proj, cond, requiredColumns); - } - /** */ @Override public Iterable scan( ExecutionContext execCtx, diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheTableImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheTableImpl.java index bc74437c3d492..2f06b6666605c 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheTableImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/CacheTableImpl.java @@ -18,16 +18,11 @@ package org.apache.ignite.internal.processors.query.calcite.schema; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptTable; -import org.apache.calcite.rel.hint.RelHint; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; -import org.apache.calcite.rex.RexNode; import org.apache.calcite.schema.Statistic; import org.apache.calcite.schema.impl.AbstractTable; import org.apache.calcite.util.ImmutableBitSet; @@ -37,7 +32,6 @@ import org.apache.ignite.internal.processors.query.calcite.exec.TableScan; import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup; import org.apache.ignite.internal.processors.query.calcite.prepare.MappingQueryContext; -import org.apache.ignite.internal.processors.query.calcite.rel.logical.IgniteLogicalTableScan; import org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistribution; import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory; import org.apache.ignite.internal.processors.query.stat.ObjectStatisticsImpl; @@ -95,18 +89,6 @@ public CacheTableImpl(GridKernalContext ctx, CacheTableDescriptor desc) { return desc; } - /** {@inheritDoc} */ - @Override public IgniteLogicalTableScan toRel( - RelOptCluster cluster, - RelOptTable relOptTbl, - @Nullable List proj, - @Nullable RexNode cond, - @Nullable ImmutableBitSet requiredColumns, - @Nullable List hints - ) { - return IgniteLogicalTableScan.create(cluster, cluster.traitSet(), relOptTbl, hints, proj, cond, requiredColumns); - } - /** {@inheritDoc} */ @Override public Iterable scan( ExecutionContext execCtx, diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteIndex.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteIndex.java index 903d4eddf5d61..07d48624acb8d 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteIndex.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteIndex.java @@ -20,6 +20,7 @@ import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelCollation; +import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.ImmutableBitSet; import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext; @@ -47,18 +48,23 @@ public interface IgniteIndex { * * @param cluster Custer. * @param relOptTbl Table. + * @param rowType Row type. * @param proj List of required projections. * @param cond Conditions to filter rows. * @param requiredColumns Set of columns to extract from original row. * @return Table relational expression. */ - public IgniteLogicalIndexScan toRel( + public default IgniteLogicalIndexScan toRel( RelOptCluster cluster, RelOptTable relOptTbl, + RelDataType rowType, @Nullable List proj, @Nullable RexNode cond, @Nullable ImmutableBitSet requiredColumns - ); + ) { + return IgniteLogicalIndexScan.create(cluster, cluster.traitSet(), relOptTbl, name(), + rowType, proj, cond, requiredColumns); + } /** * Converts condition to index find predicate. diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteTable.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteTable.java index df52e419997d8..e88bcaf220490 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteTable.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/IgniteTable.java @@ -16,15 +16,11 @@ */ package org.apache.ignite.internal.processors.query.calcite.schema; -import java.util.List; import java.util.Map; -import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.core.TableScan; -import org.apache.calcite.rel.hint.RelHint; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; -import org.apache.calcite.rex.RexNode; import org.apache.calcite.schema.TranslatableTable; import org.apache.calcite.util.ImmutableBitSet; import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext; @@ -58,29 +54,10 @@ public interface IgniteTable extends TranslatableTable { /** {@inheritDoc} */ @Override default TableScan toRel(RelOptTable.ToRelContext ctx, RelOptTable relOptTable) { - return toRel(ctx.getCluster(), relOptTable, null, null, null, ctx.getTableHints()); + return IgniteLogicalTableScan.create(ctx.getCluster(), ctx.getCluster().traitSet(), relOptTable, + ctx.getTableHints(), null, null, null, null); } - /** - * Converts table into relational expression. - * - * @param cluster Custer. - * @param relOptTbl Table. - * @param proj List of required projections. - * @param cond Conditions to filter rows. - * @param requiredColumns Set of columns to extract from original row. - * @param hints Table hints. - * @return Table relational expression. - */ - IgniteLogicalTableScan toRel( - RelOptCluster cluster, - RelOptTable relOptTbl, - @Nullable List proj, - @Nullable RexNode cond, - @Nullable ImmutableBitSet requiredColumns, - @Nullable List hints - ); - /** * Creates rows iterator over the table. * diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SchemaHolderImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SchemaHolderImpl.java index d5c2f4746cc83..b9eae82520f24 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SchemaHolderImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SchemaHolderImpl.java @@ -365,7 +365,9 @@ private static Object affinityIdentity(CacheConfiguration ccfg) { IgniteSchema schema = igniteSchemas.computeIfAbsent(schemaName, IgniteSchema::new); - schema.addFunction(name.toUpperCase(), IgniteScalarFunction.create(method)); + // Can't change deterministic flag on SqlUserDefinedFunction, at least store this flag in wrapped function + // to process it in Ignite-controlled code. + schema.addFunction(name.toUpperCase(), IgniteScalarFunction.create(method, deterministic)); rebuild(); } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SystemViewIndexImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SystemViewIndexImpl.java index 1a8abd64aea44..b26aac325b339 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SystemViewIndexImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SystemViewIndexImpl.java @@ -19,7 +19,6 @@ import java.util.Collections; import java.util.List; import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelCollation; import org.apache.calcite.rel.RelCollations; import org.apache.calcite.rel.type.RelDataType; @@ -31,7 +30,6 @@ import org.apache.ignite.internal.processors.query.calcite.exec.exp.RangeIterable; import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup; import org.apache.ignite.internal.processors.query.calcite.prepare.bounds.SearchBounds; -import org.apache.ignite.internal.processors.query.calcite.rel.logical.IgniteLogicalIndexScan; import org.apache.ignite.internal.processors.query.calcite.util.RexUtils; import org.jetbrains.annotations.Nullable; @@ -66,18 +64,6 @@ public SystemViewIndexImpl(SystemViewTableImpl tbl) { return tbl; } - /** {@inheritDoc} */ - @Override public IgniteLogicalIndexScan toRel( - RelOptCluster cluster, - RelOptTable relOptTbl, - @Nullable List proj, - @Nullable RexNode cond, - @Nullable ImmutableBitSet requiredColumns - ) { - return IgniteLogicalIndexScan.create(cluster, cluster.traitSet(), relOptTbl, idxName, proj, cond, - requiredColumns); - } - /** */ @Override public Iterable scan( ExecutionContext execCtx, diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SystemViewTableImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SystemViewTableImpl.java index 4333a9832ad8d..92ed57c41eba5 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SystemViewTableImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/schema/SystemViewTableImpl.java @@ -21,13 +21,9 @@ import java.util.List; import java.util.Map; import com.google.common.collect.ImmutableList; -import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelCollation; -import org.apache.calcite.rel.hint.RelHint; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; -import org.apache.calcite.rex.RexNode; import org.apache.calcite.schema.Statistic; import org.apache.calcite.schema.impl.AbstractTable; import org.apache.calcite.util.ImmutableBitSet; @@ -35,7 +31,6 @@ import org.apache.ignite.internal.processors.query.calcite.exec.SystemViewScan; import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup; import org.apache.ignite.internal.processors.query.calcite.prepare.MappingQueryContext; -import org.apache.ignite.internal.processors.query.calcite.rel.logical.IgniteLogicalTableScan; import org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistribution; import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory; import org.jetbrains.annotations.Nullable; @@ -87,18 +82,6 @@ public SystemViewTableImpl(SystemViewTableDescriptorImpl desc) { return desc; } - /** {@inheritDoc} */ - @Override public IgniteLogicalTableScan toRel( - RelOptCluster cluster, - RelOptTable relOptTbl, - @Nullable List proj, - @Nullable RexNode cond, - @Nullable ImmutableBitSet requiredColumns, - @Nullable List hints - ) { - return IgniteLogicalTableScan.create(cluster, cluster.traitSet(), relOptTbl, hints, proj, cond, requiredColumns); - } - /** {@inheritDoc} */ @Override public Iterable scan( ExecutionContext execCtx, diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementorTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementorTest.java index 6e4419be92cd8..06a00e8622f8d 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementorTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementorTest.java @@ -250,6 +250,12 @@ public void testIndexScanRewriter() { RelDataType sqlTypeInt = rowType.getFieldList().get(2).getType(); RelDataType sqlTypeVarchar = rowType.getFieldList().get(3).getType(); + RelDataType projRowType = new RelDataTypeFactory.Builder(tf) + .add("A", sqlTypeVarchar) + .add("B", sqlTypeInt) + .add("C", sqlTypeInt) + .build(); + // Projects, filters and required columns. List project = F.asList( rexBuilder.makeLocalRef(sqlTypeVarchar, 1), @@ -308,6 +314,7 @@ public void testIndexScanRewriter() { cluster.traitSet(), qctx.catalogReader().getTable(F.asList("PUBLIC", "TBL")), "IDX", + projRowType, project, filter, RexUtils.buildSortedSearchBounds(cluster, idxCollation, filter, rowType, requiredColumns), @@ -390,6 +397,10 @@ public void testScanTableRow() { RelDataType sqlTypeInt = rowType.getFieldList().get(2).getType(); RelDataType sqlTypeVarchar = rowType.getFieldList().get(3).getType(); + RelDataType projRowType = new RelDataTypeFactory.Builder(tf) + .add("A", sqlTypeVarchar) + .build(); + List project = F.asList(rexBuilder.makeLocalRef(sqlTypeVarchar, 1)); RexNode filterOneField = rexBuilder.makeCall( @@ -411,6 +422,7 @@ public void testScanTableRow() { cluster.traitSet(), qctx.catalogReader().getTable(F.asList("PUBLIC", "TBL")), QueryUtils.PRIMARY_KEY_INDEX, + projRowType, project, filterOneField, RexUtils.buildSortedSearchBounds(cluster, idxCollation, filterOneField, rowType, requiredColumns), @@ -440,6 +452,7 @@ private IgniteIndexScan createScan( templateScan.getTraitSet().replace(collation), templateScan.getTable(), templateScan.indexName(), + templateScan.getRowType(), projects, filters, templateScan.searchBounds(), diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/AbstractBasicIntegrationTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/AbstractBasicIntegrationTest.java index 3e4534100605d..0cac27a032b3c 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/AbstractBasicIntegrationTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/AbstractBasicIntegrationTest.java @@ -20,7 +20,6 @@ import java.util.Collections; import java.util.List; import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelCollation; import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.ImmutableBitSet; @@ -42,7 +41,6 @@ import org.apache.ignite.internal.processors.query.calcite.exec.exp.RangeIterable; import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup; import org.apache.ignite.internal.processors.query.calcite.prepare.bounds.SearchBounds; -import org.apache.ignite.internal.processors.query.calcite.rel.logical.IgniteLogicalIndexScan; import org.apache.ignite.internal.processors.query.calcite.schema.IgniteIndex; import org.apache.ignite.internal.processors.query.calcite.schema.IgniteTable; import org.apache.ignite.internal.processors.query.calcite.util.Commons; @@ -308,17 +306,6 @@ public DelegatingIgniteIndex(IgniteIndex delegate) { return delegate.table(); } - /** {@inheritDoc} */ - @Override public IgniteLogicalIndexScan toRel( - RelOptCluster cluster, - RelOptTable relOptTbl, - @Nullable List proj, - @Nullable RexNode cond, - @Nullable ImmutableBitSet requiredColumns - ) { - return delegate.toRel(cluster, relOptTbl, proj, cond, requiredColumns); - } - /** {@inheritDoc} */ @Override public List toSearchBounds( RelOptCluster cluster, diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/HashSpoolIntegrationTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/HashSpoolIntegrationTest.java index 605e1175687d6..f0313935fa08d 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/HashSpoolIntegrationTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/HashSpoolIntegrationTest.java @@ -68,15 +68,17 @@ public void testNullsInSearchRowMultipleColumns() { @Test public void testHashSpoolCondition() { executeSql("CREATE TABLE t(i INTEGER) WITH " + atomicity()); - executeSql("INSERT INTO t VALUES (0), (1), (2)"); + executeSql("INSERT INTO t VALUES (0), (1), (2), (3), (4)"); - String sql = "SELECT i, (SELECT i FROM t WHERE i=t1.i AND i-1=0) FROM t AS t1"; + String sql = "SELECT i, (SELECT i FROM t WHERE i=t1.i AND i-1>0) FROM t AS t1"; assertQuery(sql) .matches(QueryChecker.containsSubPlan("IgniteHashIndexSpool")) .returns(0, null) - .returns(1, 1) - .returns(2, null) + .returns(1, null) + .returns(2, 2) + .returns(3, 3) + .returns(4, 4) .check(); } diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/tpch/TpchScale100Test.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/tpch/TpchScale100Test.java index 8578fb66c06ec..d16e37ffb1339 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/tpch/TpchScale100Test.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/tpch/TpchScale100Test.java @@ -17,24 +17,8 @@ package org.apache.ignite.internal.processors.query.calcite.integration.tpch; -import java.util.Collection; -import java.util.LinkedHashSet; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - /** */ -@RunWith(Parameterized.class) public class TpchScale100Test extends AbstractTpchTest { - /** TODO Revise after https://issues.apache.org/jira/browse/IGNITE-25129 */ - @Parameterized.Parameters(name = "queryId={0}") - public static Collection params() { - Collection res = new LinkedHashSet<>(USED_TESTS); - - res.remove(16); - - return res; - } - /** {@inheritDoc} */ @Override protected double scale() { return 1.0; diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/ProjectFilterScanMergePlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/ProjectFilterScanMergePlannerTest.java index 0c64365efb8e6..95b0b3c2700c2 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/ProjectFilterScanMergePlannerTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/ProjectFilterScanMergePlannerTest.java @@ -20,10 +20,7 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import org.apache.calcite.rel.type.RelDataType; -import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rex.RexNode; -import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.util.ImmutableBitSet; import org.apache.ignite.internal.processors.query.calcite.prepare.bounds.SearchBounds; import org.apache.ignite.internal.processors.query.calcite.rel.IgniteAggregate; @@ -31,11 +28,11 @@ import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableScan; import org.apache.ignite.internal.processors.query.calcite.schema.IgniteSchema; import org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistributions; -import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory; -import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeSystem; import org.junit.Before; import org.junit.Test; +import static org.apache.calcite.sql.type.SqlTypeName.INTEGER; + /** * Tests ProjectScanMergeRule and FilterScanMergeRule. */ @@ -48,17 +45,9 @@ public class ProjectFilterScanMergePlannerTest extends AbstractPlannerTest { @Override public void setup() { super.setup(); - publicSchema = new IgniteSchema("PUBLIC"); - - IgniteTypeFactory f = new IgniteTypeFactory(IgniteTypeSystem.INSTANCE); - - RelDataType type = new RelDataTypeFactory.Builder(f) - .add("A", f.createSqlType(SqlTypeName.INTEGER)) - .add("B", f.createSqlType(SqlTypeName.INTEGER)) - .add("C", f.createSqlType(SqlTypeName.INTEGER)) - .build(); - - createTable(publicSchema, "TBL", type, IgniteDistributions.single(), null); + publicSchema = createSchema( + createTable("TBL", IgniteDistributions.single(), "A", INTEGER, "B", INTEGER, "C", INTEGER) + ); } /** */ @@ -258,6 +247,48 @@ public void testFilterFilterMerge() throws Exception { .and(scan -> ImmutableBitSet.of(0).equals(scan.requiredColumns()))); } + /** + * Check that not correlated part of correllated filter is merged into scan and trim unused fields is applied. + */ + @Test + public void testCorrelatedFilterWithTrimMerge() throws Exception { + IgniteSchema schema = createSchema( + // Create table with random distributeion, to avoid correlated filter to scan merging. + createTable("TBL", IgniteDistributions.random(), "A", INTEGER, "B", INTEGER, "C", INTEGER) + ); + + String sql = "SELECT (SELECT a FROM tbl t2 WHERE t1.a = t2.a AND b > 1) FROM tbl AS t1"; + + assertPlan(sql, schema, hasChildThat(isInstanceOf(IgniteAggregate.class) + .and(hasChildThat(isTableScan("TBL") + .and(scan -> scan.condition() != null) + .and(scan -> ">($t1, 1)".equals(scan.condition().toString())) + .and(scan -> ImmutableBitSet.of(0, 1).equals(scan.requiredColumns()))))) + ); + } + + /** + * Check that filter with always-false condition is not merged to scan and replaced with empty values. + */ + @Test + public void testAlwaysFalseFilterNotMerged() throws Exception { + // Trimmed fields, not reduced condition. + assertPlan("SELECT a FROM tbl WHERE false", publicSchema, + nodeOrAnyChild(isTableScan("TBL")).negate()); + + // Trimmed fields, reduced condition. + assertPlan("SELECT a FROM tbl WHERE a = 1 AND a = 0", publicSchema, + nodeOrAnyChild(isTableScan("TBL")).negate()); + + // Not trimmed fields, not reduced condition. + assertPlan("SELECT * FROM tbl WHERE false", publicSchema, + nodeOrAnyChild(isTableScan("TBL")).negate()); + + // Not trimmed fields, reduced condition. + assertPlan("SELECT * FROM tbl WHERE a = 1 AND a = 0", publicSchema, + nodeOrAnyChild(isTableScan("TBL")).negate()); + } + /** */ private static List searchBoundsCondition(List searchBounds) { return searchBounds.stream().filter(Objects::nonNull).map(SearchBounds::condition).collect(Collectors.toList()); diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/RexSimplificationPlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/RexSimplificationPlannerTest.java index 840e53ae862ff..6e242bf8d1e9b 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/RexSimplificationPlannerTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/RexSimplificationPlannerTest.java @@ -17,14 +17,18 @@ package org.apache.ignite.internal.processors.query.calcite.planner; +import org.apache.calcite.linq4j.tree.Types; import org.apache.calcite.rel.core.Join; import org.apache.calcite.util.Util; +import org.apache.ignite.internal.processors.query.calcite.exec.exp.IgniteScalarFunction; +import org.apache.ignite.internal.processors.query.calcite.rel.IgniteValues; import org.apache.ignite.internal.processors.query.calcite.rel.ProjectableFilterableTableScan; import org.apache.ignite.internal.processors.query.calcite.schema.IgniteSchema; import org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistributions; import org.junit.Test; import static org.apache.calcite.sql.type.SqlTypeName.INTEGER; +import static org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistributions.single; /** * Tests for Rex simplification. @@ -193,4 +197,51 @@ public void testExtractCommonDisjunctionPart() throws Exception { .equals(s.condition().toString())) ); } + + /** */ + @Test + public void testFunctionFilterReduction() throws Exception { + IgniteSchema publicSchema = createSchema(createTable("T", single(), "ID", INTEGER)); + + // Deterministic echo. + publicSchema.addFunction("ECHO", IgniteScalarFunction.create( + Types.lookupMethod(RexSimplificationPlannerTest.class, "echo", int.class), true)); + + // Non-deterministic echo. + publicSchema.addFunction("ECHO_ND", IgniteScalarFunction.create( + Types.lookupMethod(RexSimplificationPlannerTest.class, "echo", int.class), false)); + + // Deterministic function with literal reduced (always-true). + assertPlan("SELECT * FROM t WHERE id = 0 AND echo(1) = 1", publicSchema, isTableScan("T") + .and(s -> "=($t0, 0)".equals(s.condition().toString()))); + + // Deterministic function with literal reduced (always-false). + assertPlan("SELECT * FROM t WHERE id = 0 AND echo(0) = 1", publicSchema, isInstanceOf(IgniteValues.class) + .and(v -> v.getTuples().isEmpty())); + + // Deterministic function with another deterministic function reduced. + assertPlan("SELECT * FROM t WHERE id = 0 AND echo(echo(1)) = 1", publicSchema, isTableScan("T") + .and(s -> "=($t0, 0)".equals(s.condition().toString()))); + + // Deterministic function with column not reduced. + assertPlan("SELECT * FROM t WHERE id = 0 AND echo(id) = 1", publicSchema, isTableScan("T") + .and(s -> "AND(=($t0, 0), =(ECHO($t0), 1))".equals(s.condition().toString()))); + + // Deterministic function with dynamic param not reduced. + assertPlan("SELECT * FROM t WHERE id = 0 AND echo(?::int) = ?", publicSchema, isTableScan("T") + .and(s -> "AND(=($t0, 0), =(ECHO(CAST(?0):INTEGER), ?1))".equals(s.condition().toString()))); + + // Non-deterministic function not reduced. + assertPlan("SELECT * FROM t WHERE id = 0 AND echo_nd(1) = 1", publicSchema, isTableScan("T") + .and(s -> "AND(=($t0, 0), =(ECHO_ND(1), 1))".equals(s.condition().toString()))); + + // Deterministic function with non-deterministic function not reduced. + assertPlan("SELECT * FROM t WHERE id = 0 AND echo(echo_nd(1)) = 1", publicSchema, isTableScan("T") + .and(s -> "AND(=($t0, 0), =(ECHO(ECHO_ND(1)), 1))".equals(s.condition().toString()))); + } + + /** */ + public static int echo(int val) { + return val; + } } diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/SerializationPlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/SerializationPlannerTest.java index 8e3528dfb9b87..bc2ff7e89fe40 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/SerializationPlannerTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/SerializationPlannerTest.java @@ -101,7 +101,7 @@ public void testUdfWithSchemaSerialization() throws Exception { IgniteSchema funcSchema = new IgniteSchema("FUNC"); funcSchema.addFunction("ECHO", IgniteScalarFunction.create( - Types.lookupMethod(SerializationPlannerTest.class, "echo", int.class))); + Types.lookupMethod(SerializationPlannerTest.class, "echo", int.class), false)); assertPlan("SELECT func.echo(id) FROM orders", List.of(publicSchema, funcSchema), isTableScan("ORDERS")); diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/TestTable.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/TestTable.java index a4e5ab611e87f..5f5b5979b6f56 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/TestTable.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/TestTable.java @@ -23,24 +23,20 @@ import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Supplier; import java.util.stream.Collectors; import org.apache.calcite.config.CalciteConnectionConfig; -import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelCollation; import org.apache.calcite.rel.RelFieldCollation; import org.apache.calcite.rel.core.TableModify; -import org.apache.calcite.rel.hint.RelHint; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rel.type.RelDataTypeField; import org.apache.calcite.rel.type.RelDataTypeImpl; import org.apache.calcite.rel.type.RelProtoDataType; -import org.apache.calcite.rex.RexNode; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.Statistic; import org.apache.calcite.schema.Wrapper; @@ -63,7 +59,6 @@ import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext; import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup; import org.apache.ignite.internal.processors.query.calcite.prepare.MappingQueryContext; -import org.apache.ignite.internal.processors.query.calcite.rel.logical.IgniteLogicalTableScan; import org.apache.ignite.internal.processors.query.calcite.schema.CacheIndexImpl; import org.apache.ignite.internal.processors.query.calcite.schema.CacheTableDescriptor; import org.apache.ignite.internal.processors.query.calcite.schema.ColumnDescriptor; @@ -163,18 +158,6 @@ public TestTable setStatistics(IgniteStatisticsImpl statistics) { return this; } - /** {@inheritDoc} */ - @Override public IgniteLogicalTableScan toRel( - RelOptCluster cluster, - RelOptTable relOptTbl, - @Nullable List proj, - @Nullable RexNode cond, - @Nullable ImmutableBitSet requiredColumns, - @Nullable List hints - ) { - return IgniteLogicalTableScan.create(cluster, cluster.traitSet(), relOptTbl, hints, proj, cond, requiredColumns); - } - /** {@inheritDoc} */ @Override public RelDataType getRowType(RelDataTypeFactory typeFactory, ImmutableBitSet bitSet) { RelDataType rowType = protoType.apply(typeFactory);