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

ppa 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 a4642da0d3  IGNITE-17709 Sql. Table hints support (#1101)
a4642da0d3 is described below

commit a4642da0d3678167a3efc083dd95e7e980ee44fd
Author: Pavel Pereslegin <[email protected]>
AuthorDate: Fri Sep 23 18:31:39 2022 +0300

     IGNITE-17709 Sql. Table hints support (#1101)
---
 .../internal/sql/engine/rel/IgniteTableScan.java   | 22 ++++++--
 .../engine/rel/logical/IgniteLogicalTableScan.java | 14 ++++-
 .../sql/engine/rule/LogicalScanConverterRule.java  |  4 +-
 .../engine/rule/logical/FilterScanMergeRule.java   |  2 +-
 .../engine/rule/logical/LogicalOrToUnionRule.java  |  1 +
 .../engine/rule/logical/ProjectScanMergeRule.java  |  1 +
 .../internal/sql/engine/schema/IgniteTable.java    |  6 ++-
 .../sql/engine/schema/IgniteTableImpl.java         |  4 +-
 .../sql/engine/schema/InternalIgniteTable.java     |  6 ++-
 .../sql/engine/planner/AbstractPlannerTest.java    | 62 ++++++++++++++++++----
 .../internal/sql/engine/planner/PlannerTest.java   | 32 +++++++++++
 11 files changed, 130 insertions(+), 24 deletions(-)

diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
index 89273a7d41..3bd54d2f77 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/IgniteTableScan.java
@@ -25,6 +25,7 @@ import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelWriter;
+import org.apache.calcite.rel.hint.RelHint;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.jetbrains.annotations.Nullable;
@@ -63,7 +64,7 @@ public class IgniteTableScan extends 
ProjectableFilterableTableScan implements S
             RelTraitSet traits,
             RelOptTable tbl
     ) {
-        this(cluster, traits, tbl, null, null, null);
+        this(cluster, traits, tbl, List.of(), null, null, null);
     }
 
     /**
@@ -72,6 +73,7 @@ public class IgniteTableScan extends 
ProjectableFilterableTableScan implements S
      * @param cluster         Cluster that this relational expression belongs 
to.
      * @param traits          Traits of this relational expression.
      * @param tbl             Table definition.
+     * @param hints           Table hints.
      * @param proj            Projects.
      * @param cond            Filters.
      * @param requiredColumns Participating columns.
@@ -80,18 +82,21 @@ public class IgniteTableScan extends 
ProjectableFilterableTableScan implements S
             RelOptCluster cluster,
             RelTraitSet traits,
             RelOptTable tbl,
+            List<RelHint> hints,
             @Nullable List<RexNode> proj,
             @Nullable RexNode cond,
             @Nullable ImmutableBitSet requiredColumns
     ) {
-        this(-1L, cluster, traits, tbl, proj, cond, requiredColumns);
+        this(-1L, cluster, traits, hints, tbl, proj, cond, requiredColumns);
     }
 
     /**
      * Creates a TableScan.
      *
+     * @param sourceId        Source id.
      * @param cluster         Cluster that this relational expression belongs 
to.
      * @param traits          Traits of this relational expression.
+     * @param hints           Table hints.
      * @param tbl             Table definition.
      * @param proj            Projects.
      * @param cond            Filters.
@@ -101,12 +106,13 @@ public class IgniteTableScan extends 
ProjectableFilterableTableScan implements S
             long sourceId,
             RelOptCluster cluster,
             RelTraitSet traits,
+            List<RelHint> hints,
             RelOptTable tbl,
             @Nullable List<RexNode> proj,
             @Nullable RexNode cond,
             @Nullable ImmutableBitSet requiredColumns
     ) {
-        super(cluster, traits, List.of(), tbl, proj, cond, requiredColumns);
+        super(cluster, traits, hints, tbl, proj, cond, requiredColumns);
         this.sourceId = sourceId;
     }
 
@@ -134,12 +140,18 @@ public class IgniteTableScan extends 
ProjectableFilterableTableScan implements S
     /** {@inheritDoc} */
     @Override
     public IgniteRel clone(long sourceId) {
-        return new IgniteTableScan(sourceId, getCluster(), getTraitSet(), 
getTable(), projects, condition, requiredColumns);
+        return new IgniteTableScan(sourceId, getCluster(), getTraitSet(), 
getHints(), getTable(), projects, condition, requiredColumns);
     }
 
     /** {@inheritDoc} */
     @Override
     public IgniteRel clone(RelOptCluster cluster, List<IgniteRel> inputs) {
-        return new IgniteTableScan(sourceId, cluster, getTraitSet(), 
getTable(), projects, condition, requiredColumns);
+        return new IgniteTableScan(sourceId, cluster, getTraitSet(), 
getHints(), getTable(), projects, condition, requiredColumns);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IgniteTableScan withHints(List<RelHint> hintList) {
+        return new IgniteTableScan(sourceId, getCluster(), getTraitSet(), 
hintList, getTable(), projects, condition, requiredColumns);
     }
 }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
index 31c75d199d..32d76a1264 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rel/logical/IgniteLogicalTableScan.java
@@ -21,6 +21,7 @@ import java.util.List;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.hint.RelHint;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.util.ImmutableBitSet;
 import 
org.apache.ignite.internal.sql.engine.rel.ProjectableFilterableTableScan;
@@ -35,12 +36,13 @@ public class IgniteLogicalTableScan extends 
ProjectableFilterableTableScan {
     public static IgniteLogicalTableScan create(
             RelOptCluster cluster,
             RelTraitSet traits,
+            List<RelHint> hints,
             RelOptTable tbl,
             @Nullable List<RexNode> proj,
             @Nullable RexNode cond,
             @Nullable ImmutableBitSet requiredColumns
     ) {
-        return new IgniteLogicalTableScan(cluster, traits, tbl, proj, cond, 
requiredColumns);
+        return new IgniteLogicalTableScan(cluster, traits, hints, tbl, proj, 
cond, requiredColumns);
     }
 
     /**
@@ -48,6 +50,7 @@ public class IgniteLogicalTableScan extends 
ProjectableFilterableTableScan {
      *
      * @param cluster         Cluster that this relational expression belongs 
to.
      * @param traits          Traits of this relational expression.
+     * @param hints           Table hints.
      * @param tbl             Table definition.
      * @param proj            Projects.
      * @param cond            Filters.
@@ -56,11 +59,18 @@ public class IgniteLogicalTableScan extends 
ProjectableFilterableTableScan {
     private IgniteLogicalTableScan(
             RelOptCluster cluster,
             RelTraitSet traits,
+            List<RelHint> hints,
             RelOptTable tbl,
             @Nullable List<RexNode> proj,
             @Nullable RexNode cond,
             @Nullable ImmutableBitSet requiredColumns
     ) {
-        super(cluster, traits, List.of(), tbl, proj, cond, requiredColumns);
+        super(cluster, traits, hints, tbl, proj, cond, requiredColumns);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IgniteLogicalTableScan withHints(List<RelHint> hintList) {
+        return new IgniteLogicalTableScan(getCluster(), getTraitSet(), 
hintList, getTable(), projects, condition, requiredColumns);
     }
 }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/LogicalScanConverterRule.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/LogicalScanConverterRule.java
index 0c3ef47344..98bb3fb39d 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/LogicalScanConverterRule.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/LogicalScanConverterRule.java
@@ -145,8 +145,8 @@ public abstract class LogicalScanConverterRule<T extends 
ProjectableFilterableTa
                             .replace(distribution)
                             .replace(corrIds.isEmpty() ? 
CorrelationTrait.UNCORRELATED : CorrelationTrait.correlations(corrIds));
 
-                    return new IgniteTableScan(rel.getCluster(), traits,
-                        rel.getTable(), rel.projects(), rel.condition(), 
rel.requiredColumns());
+                    return new IgniteTableScan(rel.getCluster(), traits, 
rel.getTable(), rel.getHints(),
+                        rel.projects(), rel.condition(), 
rel.requiredColumns());
                 }
             };
 
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/FilterScanMergeRule.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/FilterScanMergeRule.java
index 33622f2809..db2b6fc523 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/FilterScanMergeRule.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/FilterScanMergeRule.java
@@ -127,7 +127,7 @@ public abstract class FilterScanMergeRule<T extends 
ProjectableFilterableTableSc
                 RelTraitSet traits,
                 RexNode cond
         ) {
-            return IgniteLogicalTableScan.create(cluster, traits, 
scan.getTable(), scan.projects(),
+            return IgniteLogicalTableScan.create(cluster, traits, 
scan.getHints(), scan.getTable(), scan.projects(),
                     cond, scan.requiredColumns());
         }
     }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/LogicalOrToUnionRule.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/LogicalOrToUnionRule.java
index 32746beeed..745fe4d774 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/LogicalOrToUnionRule.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/LogicalOrToUnionRule.java
@@ -88,6 +88,7 @@ public class LogicalOrToUnionRule extends 
RelRule<LogicalOrToUnionRule.Config> {
         relBldr.push(IgniteLogicalTableScan.create(
                 scan.getCluster(),
                 trait,
+                scan.getHints(),
                 scan.getTable(),
                 scan.projects(),
                 condition,
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/ProjectScanMergeRule.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/ProjectScanMergeRule.java
index 3b925468da..081d9280fa 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/ProjectScanMergeRule.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rule/logical/ProjectScanMergeRule.java
@@ -170,6 +170,7 @@ public abstract class ProjectScanMergeRule<T extends 
ProjectableFilterableTableS
             return IgniteLogicalTableScan.create(
                     cluster,
                     traits,
+                    scan.getHints(),
                     scan.getTable(),
                     projections,
                     cond,
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTable.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTable.java
index 77de799b7d..378076462f 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTable.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTable.java
@@ -24,6 +24,7 @@ import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.RelCollation;
 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.schema.Schema;
@@ -78,7 +79,7 @@ public interface IgniteTable extends TranslatableTable, 
Wrapper {
     /** {@inheritDoc} */
     @Override
     default TableScan toRel(RelOptTable.ToRelContext context, RelOptTable 
relOptTable) {
-        return toRel(context.getCluster(), relOptTable);
+        return toRel(context.getCluster(), relOptTable, 
context.getTableHints());
     }
 
     /**
@@ -86,9 +87,10 @@ public interface IgniteTable extends TranslatableTable, 
Wrapper {
      *
      * @param cluster   Custer.
      * @param relOptTbl Table.
+     * @param hints     Hints.
      * @return Table relational expression.
      */
-    TableScan toRel(RelOptCluster cluster, RelOptTable relOptTbl);
+    TableScan toRel(RelOptCluster cluster, RelOptTable relOptTbl, 
List<RelHint> hints);
 
     /**
      * Returns table distribution.
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTableImpl.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTableImpl.java
index 69dbebaa30..ace5b069e3 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTableImpl.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/IgniteTableImpl.java
@@ -36,6 +36,7 @@ import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelReferentialConstraint;
 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.rex.RexNode;
@@ -173,6 +174,7 @@ public class IgniteTableImpl extends AbstractTable 
implements InternalIgniteTabl
     public IgniteLogicalTableScan toRel(
             RelOptCluster cluster,
             RelOptTable relOptTbl,
+            List<RelHint> hints,
             @Nullable List<RexNode> proj,
             @Nullable RexNode cond,
             @Nullable ImmutableBitSet requiredColumns
@@ -180,7 +182,7 @@ public class IgniteTableImpl extends AbstractTable 
implements InternalIgniteTabl
         RelTraitSet traitSet = cluster.traitSetOf(distribution())
                 .replace(RewindabilityTrait.REWINDABLE);
 
-        return IgniteLogicalTableScan.create(cluster, traitSet, relOptTbl, 
proj, cond, requiredColumns);
+        return IgniteLogicalTableScan.create(cluster, traitSet, hints, 
relOptTbl, proj, cond, requiredColumns);
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/InternalIgniteTable.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/InternalIgniteTable.java
index 1b88673e94..66236c19aa 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/InternalIgniteTable.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/schema/InternalIgniteTable.java
@@ -22,6 +22,7 @@ import java.util.Map;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.core.TableModify;
+import org.apache.calcite.rel.hint.RelHint;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.ignite.internal.schema.BinaryRow;
@@ -40,8 +41,8 @@ import org.jetbrains.annotations.Nullable;
 public interface InternalIgniteTable extends IgniteTable {
     /** {@inheritDoc} */
     @Override
-    default IgniteLogicalTableScan toRel(RelOptCluster cluster, RelOptTable 
relOptTbl) {
-        return toRel(cluster, relOptTbl, null, null, null);
+    default IgniteLogicalTableScan toRel(RelOptCluster cluster, RelOptTable 
relOptTbl, List<RelHint> hints) {
+        return toRel(cluster, relOptTbl, hints, null, null, null);
     }
 
     /**
@@ -62,6 +63,7 @@ public interface InternalIgniteTable extends IgniteTable {
     IgniteLogicalTableScan toRel(
             RelOptCluster cluster,
             RelOptTable relOptTbl,
+            List<RelHint> hints,
             @Nullable List<RexNode> proj,
             @Nullable RexNode cond,
             @Nullable ImmutableBitSet requiredColumns
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 e05d425d5e..cd4f3a3625 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
@@ -29,6 +29,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
+import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -57,6 +58,9 @@ import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelReferentialConstraint;
 import org.apache.calcite.rel.RelVisitor;
 import org.apache.calcite.rel.core.TableModify.Operation;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rel.hint.HintStrategyTable;
+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;
@@ -73,6 +77,7 @@ import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql2rel.InitializerContext;
+import org.apache.calcite.sql2rel.SqlToRelConverter;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Util;
 import org.apache.ignite.internal.index.ColumnCollation;
@@ -223,12 +228,17 @@ public abstract class AbstractPlannerTest extends 
IgniteAbstractTest {
      * Create planner context for specified query.
      */
     protected PlanningContext plannerCtx(String sql, IgniteSchema 
publicSchema, String... disabledRules) {
-        return plannerCtx(sql, Collections.singleton(publicSchema), 
disabledRules);
+        return plannerCtx(sql, Collections.singleton(publicSchema), null, 
disabledRules);
     }
 
-    protected PlanningContext plannerCtx(String sql, Collection<IgniteSchema> 
schemas, String... disabledRules) {
+    protected PlanningContext plannerCtx(
+            String sql,
+            Collection<IgniteSchema> schemas,
+            HintStrategyTable hintStrategies,
+            String... disabledRules
+    ) {
         PlanningContext ctx = PlanningContext.builder()
-                .parentContext(baseQueryContext(schemas))
+                .parentContext(baseQueryContext(schemas, hintStrategies))
                 .query(sql)
                 .build();
 
@@ -241,7 +251,7 @@ public abstract class AbstractPlannerTest extends 
IgniteAbstractTest {
         return ctx;
     }
 
-    protected BaseQueryContext baseQueryContext(Collection<IgniteSchema> 
schemas) {
+    protected BaseQueryContext baseQueryContext(Collection<IgniteSchema> 
schemas, @Nullable HintStrategyTable hintStrategies) {
         SchemaPlus rootSchema = createRootSchema(false);
         SchemaPlus dfltSchema = null;
 
@@ -253,10 +263,17 @@ public abstract class AbstractPlannerTest extends 
IgniteAbstractTest {
             }
         }
 
+        SqlToRelConverter.Config relConvCfg = 
FRAMEWORK_CONFIG.getSqlToRelConverterConfig();
+
+        if (hintStrategies != null) {
+            relConvCfg = relConvCfg.withHintStrategyTable(hintStrategies);
+        }
+
         return BaseQueryContext.builder()
                 .frameworkConfig(
                         newConfigBuilder(FRAMEWORK_CONFIG)
                                 .defaultSchema(dfltSchema)
+                                .sqlToRelConverterConfig(relConvCfg)
                                 .build()
                 )
                 .logger(log)
@@ -297,11 +314,16 @@ public abstract class AbstractPlannerTest extends 
IgniteAbstractTest {
      * Optimize the specified query and build query physical plan for a test.
      */
     protected IgniteRel physicalPlan(String sql, IgniteSchema publicSchema, 
String... disabledRules) throws Exception {
-        return physicalPlan(sql, plannerCtx(sql, publicSchema, disabledRules));
+        return physicalPlan(sql, Collections.singleton(publicSchema), null, 
disabledRules);
     }
 
-    protected IgniteRel physicalPlan(String sql, Collection<IgniteSchema> 
schemas, String... disabledRules) throws Exception {
-        return physicalPlan(plannerCtx(sql, schemas, disabledRules));
+    protected IgniteRel physicalPlan(
+            String sql,
+            Collection<IgniteSchema> schemas,
+            HintStrategyTable hintStrategies,
+            String... disabledRules
+    ) throws Exception {
+        return physicalPlan(plannerCtx(sql, schemas, hintStrategies, 
disabledRules));
     }
 
     protected IgniteRel physicalPlan(PlanningContext ctx) throws Exception {
@@ -471,7 +493,17 @@ public abstract class AbstractPlannerTest extends 
IgniteAbstractTest {
             Predicate<T> predicate,
             String... disabledRules
     ) throws Exception {
-        IgniteRel plan = physicalPlan(sql, schemas, disabledRules);
+        assertPlan(sql, schemas, predicate, null, disabledRules);
+    }
+
+    protected <T extends RelNode> void assertPlan(
+            String sql,
+            Collection<IgniteSchema> schemas,
+            Predicate<T> predicate,
+            HintStrategyTable hintStrategies,
+            String... disabledRules
+    ) throws Exception {
+        IgniteRel plan = physicalPlan(sql, schemas, hintStrategies, 
disabledRules);
 
         checkSplitAndSerialization(plan, schemas);
 
@@ -650,6 +682,9 @@ public abstract class AbstractPlannerTest extends 
IgniteAbstractTest {
             clearTraits(expected);
             clearTraits(deserialized);
 
+            // Hints are not serializable.
+            clearHints(expected);
+
             if (!expected.deepEquals(deserialized)) {
                 assertTrue(
                         expected.deepEquals(deserialized),
@@ -690,6 +725,14 @@ public abstract class AbstractPlannerTest extends 
IgniteAbstractTest {
         rel.getInputs().forEach(this::clearTraits);
     }
 
+    protected void clearHints(RelNode rel) {
+        if (rel instanceof TableScan) {
+            IgniteTestUtils.setFieldValue(rel, TableScan.class, "hints", 
ImmutableList.of());
+        }
+
+        rel.getInputs().forEach(this::clearHints);
+    }
+
     /** Test table. */
     public abstract static class TestTable implements InternalIgniteTable {
         private final String name;
@@ -745,11 +788,12 @@ public abstract class AbstractPlannerTest extends 
IgniteAbstractTest {
         public IgniteLogicalTableScan toRel(
                 RelOptCluster cluster,
                 RelOptTable relOptTbl,
+                List<RelHint> hints,
                 @Nullable List<RexNode> proj,
                 @Nullable RexNode cond,
                 @Nullable ImmutableBitSet requiredColumns
         ) {
-            return IgniteLogicalTableScan.create(cluster, cluster.traitSet(), 
relOptTbl, proj, cond, requiredColumns);
+            return IgniteLogicalTableScan.create(cluster, cluster.traitSet(), 
hints, relOptTbl, proj, cond, requiredColumns);
         }
 
         /** {@inheritDoc} */
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTest.java
index 09b28b89ba..ad8ad61353 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/PlannerTest.java
@@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -35,10 +36,13 @@ import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.RelVisitor;
+import org.apache.calcite.rel.core.TableScan;
+import org.apache.calcite.rel.hint.HintStrategyTable;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.util.ImmutableIntList;
+import org.apache.calcite.util.Util;
 import org.apache.ignite.internal.sql.engine.metadata.ColocationGroup;
 import org.apache.ignite.internal.sql.engine.metadata.cost.IgniteCostFactory;
 import org.apache.ignite.internal.sql.engine.prepare.IgnitePlanner;
@@ -860,6 +864,34 @@ public class PlannerTest extends AbstractPlannerTest {
         assertPlan(sql, publicSchema, (k) -> true);
     }
 
+    @Test
+    public void checkTableHintsHandling() throws Exception {
+        IgniteSchema publicSchema = createSchema(
+                createTable("PERSON", IgniteDistributions.affinity(0, 
"ignored", "ignored"),
+                        "PK", Integer.class, "ORG_ID", Integer.class
+                ),
+                createTable("COMPANY", IgniteDistributions.affinity(0, 
"ignored", "ignored"),
+                        "PK", Integer.class, "ID", Integer.class
+                )
+        );
+
+        String sql = "SELECT * FROM person /*+ use_index(ORG_ID), extra */ t1 
JOIN company /*+ use_index(ID) */ t2 ON t1.org_id = t2.id";
+
+        HintStrategyTable hintStrategies = HintStrategyTable.builder()
+                .hintStrategy("use_index", (hint, rel) -> true)
+                .hintStrategy("extra", (hint, rel) -> true)
+                .build();
+
+        Predicate<RelNode> hintCheck = 
nodeOrAnyChild(isInstanceOf(TableScan.class)
+                .and(t -> 
"PERSON".equals(Util.last(t.getTable().getQualifiedName())))
+                .and(t -> t.getHints().size() == 2)
+        ).and(nodeOrAnyChild(isInstanceOf(TableScan.class)
+                .and(t -> 
"COMPANY".equals(Util.last(t.getTable().getQualifiedName())))
+                .and(t -> t.getHints().size() == 1)));
+
+        assertPlan(sql, Collections.singleton(publicSchema), hintCheck, 
hintStrategies);
+    }
+
     /**
      * IntermediateMapping.
      * TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859

Reply via email to