You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by li...@apache.org on 2022/03/04 13:24:18 UTC
[calcite] 14/41: [CALCITE-4967] Support SQL hints for temporal table join
This is an automated email from the ASF dual-hosted git repository.
liyafan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git
commit 9d02d458e3113915858d928b5fbccc7636c0644d
Author: Jing Zhang <be...@gmail.com>
AuthorDate: Wed Dec 29 16:11:10 2021 +0800
[CALCITE-4967] Support SQL hints for temporal table join
close apache/calcite#2664
---
.../adapter/enumerable/EnumerableCorrelate.java | 2 +-
.../org/apache/calcite/adapter/jdbc/JdbcRules.java | 2 +-
.../org/apache/calcite/rel/core/Correlate.java | 24 ++++++++-
.../org/apache/calcite/rel/core/RelFactories.java | 12 +++--
.../apache/calcite/rel/hint/HintPredicates.java | 5 ++
.../calcite/rel/hint/NodeTypeHintPredicate.java | 8 ++-
.../calcite/rel/logical/LogicalCorrelate.java | 41 ++++++++++++--
.../apache/calcite/rel/mutable/MutableRels.java | 5 +-
.../calcite/rel/rules/JoinToCorrelateRule.java | 1 +
.../sql2rel/RelStructuredTypeFlattener.java | 1 +
.../apache/calcite/sql2rel/SqlToRelConverter.java | 2 +-
.../java/org/apache/calcite/tools/RelBuilder.java | 4 +-
.../org/apache/calcite/test/RelBuilderTest.java | 30 +++++++++++
.../org/apache/calcite/test/RelOptRulesTest.java | 3 +-
.../apache/calcite/test/SqlHintsConverterTest.java | 62 +++++++++++++++++++++-
.../org/apache/calcite/test/SqlToRelTestBase.java | 11 +++-
.../apache/calcite/test/SqlHintsConverterTest.xml | 26 +++++++++
17 files changed, 218 insertions(+), 21 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelate.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelate.java
index 6f88372..efb0267 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelate.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCorrelate.java
@@ -52,7 +52,7 @@ public class EnumerableCorrelate extends Correlate
RelNode left, RelNode right,
CorrelationId correlationId,
ImmutableBitSet requiredColumns, JoinRelType joinType) {
- super(cluster, traits, left, right, correlationId, requiredColumns,
+ super(cluster, traits, ImmutableList.of(), left, right, correlationId, requiredColumns,
joinType);
}
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
index 5b9f8b7..37fb747 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
@@ -127,7 +127,7 @@ public class JdbcRules {
};
static final RelFactories.CorrelateFactory CORRELATE_FACTORY =
- (left, right, correlationId, requiredColumns, joinType) -> {
+ (left, right, hints, correlationId, requiredColumns, joinType) -> {
throw new UnsupportedOperationException("JdbcCorrelate");
};
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Correlate.java b/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
index d7d3602..f5194a1 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
@@ -25,6 +25,8 @@ import org.apache.calcite.rel.BiRel;
import org.apache.calcite.rel.RelInput;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelWriter;
+import org.apache.calcite.rel.hint.Hintable;
+import org.apache.calcite.rel.hint.RelHint;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.sql.validate.SqlValidatorUtil;
@@ -68,12 +70,13 @@ import static java.util.Objects.requireNonNull;
*
* @see CorrelationId
*/
-public abstract class Correlate extends BiRel {
+public abstract class Correlate extends BiRel implements Hintable {
//~ Instance fields --------------------------------------------------------
protected final CorrelationId correlationId;
protected final ImmutableBitSet requiredColumns;
protected final JoinRelType joinType;
+ protected final ImmutableList<RelHint> hints;
//~ Constructors -----------------------------------------------------------
@@ -91,6 +94,7 @@ public abstract class Correlate extends BiRel {
protected Correlate(
RelOptCluster cluster,
RelTraitSet traitSet,
+ List<RelHint> hints,
RelNode left,
RelNode right,
CorrelationId correlationId,
@@ -101,9 +105,23 @@ public abstract class Correlate extends BiRel {
this.joinType = requireNonNull(joinType, "joinType");
this.correlationId = requireNonNull(correlationId, "correlationId");
this.requiredColumns = requireNonNull(requiredColumns, "requiredColumns");
+ this.hints = ImmutableList.copyOf(hints);
assert isValid(Litmus.THROW, null);
}
+ @Deprecated // to be removed before 2.0
+ protected Correlate(
+ RelOptCluster cluster,
+ RelTraitSet traitSet,
+ RelNode left,
+ RelNode right,
+ CorrelationId correlationId,
+ ImmutableBitSet requiredColumns,
+ JoinRelType joinType) {
+ this(cluster, traitSet, ImmutableList.of(), left, right,
+ correlationId, requiredColumns, joinType);
+ }
+
/**
* Creates a Correlate by parsing serialized output.
*
@@ -235,4 +253,8 @@ public abstract class Correlate extends BiRel {
rowCount /* generate results */ + leftRowCount /* scan left results */,
0, 0).plus(rescanCost);
}
+
+ @Override public ImmutableList<RelHint> getHints() {
+ return hints;
+ }
}
diff --git a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
index d6ab518..0998c99 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java
@@ -392,16 +392,18 @@ public class RelFactories {
* <p>The result is typically a {@link Correlate}.
*/
public interface CorrelateFactory {
+
/**
* Creates a correlate.
*
* @param left Left input
* @param right Right input
+ * @param hints Hints
* @param correlationId Variable name for the row of left input
* @param requiredColumns Required columns
* @param joinType Join type
*/
- RelNode createCorrelate(RelNode left, RelNode right,
+ RelNode createCorrelate(RelNode left, RelNode right, List<RelHint> hints,
CorrelationId correlationId, ImmutableBitSet requiredColumns,
JoinRelType joinType);
}
@@ -411,10 +413,10 @@ public class RelFactories {
* {@link org.apache.calcite.rel.logical.LogicalCorrelate}.
*/
private static class CorrelateFactoryImpl implements CorrelateFactory {
- @Override public RelNode createCorrelate(RelNode left, RelNode right,
- CorrelationId correlationId, ImmutableBitSet requiredColumns,
- JoinRelType joinType) {
- return LogicalCorrelate.create(left, right, correlationId,
+
+ @Override public RelNode createCorrelate(RelNode left, RelNode right, List<RelHint> hints,
+ CorrelationId correlationId, ImmutableBitSet requiredColumns, JoinRelType joinType) {
+ return LogicalCorrelate.create(left, right, hints, correlationId,
requiredColumns, joinType);
}
}
diff --git a/core/src/main/java/org/apache/calcite/rel/hint/HintPredicates.java b/core/src/main/java/org/apache/calcite/rel/hint/HintPredicates.java
index 266ccf4..97e6bf3 100644
--- a/core/src/main/java/org/apache/calcite/rel/hint/HintPredicates.java
+++ b/core/src/main/java/org/apache/calcite/rel/hint/HintPredicates.java
@@ -50,6 +50,11 @@ public abstract class HintPredicates {
public static final HintPredicate CALC =
new NodeTypeHintPredicate(NodeTypeHintPredicate.NodeType.CALC);
+ /** A hint predicate that indicates a hint can only be used to
+ * {@link org.apache.calcite.rel.core.Correlate} nodes. */
+ public static final HintPredicate CORRELATE =
+ new NodeTypeHintPredicate(NodeTypeHintPredicate.NodeType.CORRELATE);
+
/**
* Returns a composed hint predicate that represents a short-circuiting logical
* AND of an array of hint predicates {@code hintPredicates}. When evaluating the composed
diff --git a/core/src/main/java/org/apache/calcite/rel/hint/NodeTypeHintPredicate.java b/core/src/main/java/org/apache/calcite/rel/hint/NodeTypeHintPredicate.java
index 02cccc5..cdcd7ba 100644
--- a/core/src/main/java/org/apache/calcite/rel/hint/NodeTypeHintPredicate.java
+++ b/core/src/main/java/org/apache/calcite/rel/hint/NodeTypeHintPredicate.java
@@ -19,6 +19,7 @@ package org.apache.calcite.rel.hint;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.Calc;
+import org.apache.calcite.rel.core.Correlate;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.TableScan;
@@ -63,7 +64,12 @@ public class NodeTypeHintPredicate implements HintPredicate {
/**
* The hint would be propagated to the Calc nodes.
*/
- CALC(Calc.class);
+ CALC(Calc.class),
+
+ /**
+ * The hint would be propagated to the Correlate nodes.
+ */
+ CORRELATE(Correlate.class);
/** Relational expression clazz that the hint can apply to. */
@SuppressWarnings("ImmutableEnumChecker")
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
index d73ce12..2929f03 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
@@ -25,8 +25,13 @@ import org.apache.calcite.rel.RelShuttle;
import org.apache.calcite.rel.core.Correlate;
import org.apache.calcite.rel.core.CorrelationId;
import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.hint.RelHint;
import org.apache.calcite.util.ImmutableBitSet;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
import static java.util.Objects.requireNonNull;
/**
@@ -58,6 +63,7 @@ public final class LogicalCorrelate extends Correlate {
public LogicalCorrelate(
RelOptCluster cluster,
RelTraitSet traitSet,
+ List<RelHint> hints,
RelNode left,
RelNode right,
CorrelationId correlationId,
@@ -66,6 +72,7 @@ public final class LogicalCorrelate extends Correlate {
super(
cluster,
traitSet,
+ hints,
left,
right,
correlationId,
@@ -73,11 +80,25 @@ public final class LogicalCorrelate extends Correlate {
joinType);
}
+ @Deprecated // to be removed before 2.0
+ public LogicalCorrelate(
+ RelOptCluster cluster,
+ RelTraitSet traitSet,
+ RelNode left,
+ RelNode right,
+ CorrelationId correlationId,
+ ImmutableBitSet requiredColumns,
+ JoinRelType joinType) {
+ this(cluster, traitSet, ImmutableList.of(), left, right,
+ correlationId, requiredColumns, joinType);
+ }
+
/**
* Creates a LogicalCorrelate by parsing serialized output.
*/
public LogicalCorrelate(RelInput input) {
- this(input.getCluster(), input.getTraitSet(), input.getInputs().get(0),
+ this(input.getCluster(), input.getTraitSet(), ImmutableList.of(),
+ input.getInputs().get(0),
input.getInputs().get(1),
new CorrelationId(
(Integer) requireNonNull(input.get("correlation"), "correlation")),
@@ -86,26 +107,38 @@ public final class LogicalCorrelate extends Correlate {
}
/** Creates a LogicalCorrelate. */
- public static LogicalCorrelate create(RelNode left, RelNode right,
+ public static LogicalCorrelate create(RelNode left, RelNode right, List<RelHint> hints,
CorrelationId correlationId, ImmutableBitSet requiredColumns,
JoinRelType joinType) {
final RelOptCluster cluster = left.getCluster();
final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
- return new LogicalCorrelate(cluster, traitSet, left, right, correlationId,
+ return new LogicalCorrelate(cluster, traitSet, hints, left, right, correlationId,
requiredColumns, joinType);
}
+ @Deprecated // to be removed before 2.0
+ public static LogicalCorrelate create(RelNode left, RelNode right,
+ CorrelationId correlationId, ImmutableBitSet requiredColumns,
+ JoinRelType joinType) {
+ return create(left, right, ImmutableList.of(), correlationId, requiredColumns, joinType);
+ }
+
//~ Methods ----------------------------------------------------------------
@Override public LogicalCorrelate copy(RelTraitSet traitSet,
RelNode left, RelNode right, CorrelationId correlationId,
ImmutableBitSet requiredColumns, JoinRelType joinType) {
assert traitSet.containsIfApplicable(Convention.NONE);
- return new LogicalCorrelate(getCluster(), traitSet, left, right,
+ return new LogicalCorrelate(getCluster(), traitSet, hints, left, right,
correlationId, requiredColumns, joinType);
}
@Override public RelNode accept(RelShuttle shuttle) {
return shuttle.visit(this);
}
+
+ @Override public RelNode withHints(List<RelHint> hintList) {
+ return new LogicalCorrelate(getCluster(), traitSet, hintList, left, right,
+ correlationId, requiredColumns, joinType);
+ }
}
diff --git a/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java b/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
index ab8902e..708e881 100644
--- a/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
+++ b/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
@@ -60,6 +60,8 @@ import org.apache.calcite.util.mapping.Mapping;
import org.apache.calcite.util.mapping.MappingType;
import org.apache.calcite.util.mapping.Mappings;
+import com.google.common.collect.ImmutableList;
+
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.AbstractList;
@@ -297,7 +299,8 @@ public abstract class MutableRels {
case CORRELATE:
final MutableCorrelate correlate = (MutableCorrelate) node;
return LogicalCorrelate.create(fromMutable(correlate.getLeft(), relBuilder),
- fromMutable(correlate.getRight(), relBuilder), correlate.correlationId,
+ fromMutable(correlate.getRight(), relBuilder),
+ ImmutableList.of(), correlate.correlationId,
correlate.requiredColumns, correlate.joinType);
case UNION:
final MutableUnion union = (MutableUnion) node;
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
index 154a200..296433e 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
@@ -124,6 +124,7 @@ public class JoinToCorrelateRule
RelNode newRel =
LogicalCorrelate.create(left,
relBuilder.build(),
+ join.getHints(),
correlationId,
requiredColumns.build(),
join.getJoinType());
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
index 2ad5955..f4bf28a 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
@@ -482,6 +482,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor {
LogicalCorrelate newRel =
LogicalCorrelate.create(getNewForOldRel(rel.getLeft()),
getNewForOldRel(rel.getRight()),
+ rel.getHints(),
rel.getCorrelationId(),
newPos.build(),
rel.getJoinType());
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 355614a..e6e79c7 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -2756,7 +2756,7 @@ public class SqlToRelConverter {
.union(p.requiredColumns);
}
- return LogicalCorrelate.create(leftRel, innerRel,
+ return LogicalCorrelate.create(leftRel, innerRel, ImmutableList.of(),
p.id, requiredCols, joinType);
}
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index 7d4b408..9c178c0 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -2791,7 +2791,7 @@ public class RelBuilder {
}
final ImmutableBitSet requiredColumns = RelOptUtil.correlationColumns(id, right.rel);
join =
- struct.correlateFactory.createCorrelate(left.rel, right.rel, id,
+ struct.correlateFactory.createCorrelate(left.rel, right.rel, ImmutableList.of(), id,
requiredColumns, joinType);
} else {
RelNode join0 =
@@ -2836,7 +2836,7 @@ public class RelBuilder {
Frame left = stack.pop();
final RelNode correlate =
- struct.correlateFactory.createCorrelate(left.rel, right.rel,
+ struct.correlateFactory.createCorrelate(left.rel, right.rel, ImmutableList.of(),
correlationId, ImmutableBitSet.of(requiredOrdinals), joinType);
final ImmutableList.Builder<Field> fields = ImmutableList.builder();
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 9f08de9..6887198 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -4403,6 +4403,10 @@ public class RelBuilderTest {
final RelHint noHashJoinHint = RelHint.builder("NO_HASH_JOIN")
.inheritPath(0)
.build();
+ final RelHint hashJoinHint = RelHint.builder("USE_HASH_JOIN")
+ .hintOption("orders")
+ .hintOption("products_temporal")
+ .build();
final RelBuilder builder = RelBuilder.create(config().build());
// Equivalent SQL:
// SELECT *
@@ -4440,6 +4444,32 @@ public class RelBuilderTest {
.hints(noHashJoinHint)
.build();
assertThat(root2, hasHints("[[NO_HASH_JOIN inheritPath:[0]]]"));
+
+ // Equivalent SQL:
+ // SELECT *
+ // FROM orders
+ // JOIN products_temporal FOR SYSTEM_TIME AS OF orders.rowtime
+ // ON orders.product = products_temporal.id
+ RelNode left = builder.scan("orders").build();
+ RelNode right = builder.scan("products_temporal").build();
+ RexNode period = builder.getRexBuilder().makeFieldAccess(
+ builder.getRexBuilder().makeCorrel(left.getRowType(), new CorrelationId(0)),
+ 0);
+ RelNode root3 =
+ builder
+ .push(left)
+ .push(right)
+ .snapshot(period)
+ .correlate(
+ JoinRelType.INNER,
+ new CorrelationId(0),
+ builder.field(2, 0, "ROWTIME"),
+ builder.field(2, 0, "ID"),
+ builder.field(2, 0, "PRODUCT"))
+ .hints(hashJoinHint)
+ .build();
+ assertThat(root3,
+ hasHints("[[USE_HASH_JOIN inheritPath:[] options:[orders, products_temporal]]]"));
}
@Test void testHintsOnEmptyStack() {
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 864cb95..46e1ab2 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -1743,7 +1743,7 @@ class RelOptRulesTest extends RelOptTestBase {
.project(b.field(0),
b.getRexBuilder().makeFieldAccess(rexCorrel, 0)).build();
LogicalCorrelate correlate = new LogicalCorrelate(left.getCluster(),
- left.getTraitSet(), left, right, correlationId,
+ left.getTraitSet(), ImmutableList.of(), left, right, correlationId,
ImmutableBitSet.of(0), type);
b.push(correlate);
@@ -4061,6 +4061,7 @@ class RelOptRulesTest extends RelOptTestBase {
CustomCorrelate customCorrelate = new CustomCorrelate(
logicalCorrelate.getCluster(),
logicalCorrelate.getTraitSet(),
+ logicalCorrelate.getHints(),
logicalCorrelate.getLeft(),
logicalCorrelate.getRight(),
logicalCorrelate.getCorrelationId(),
diff --git a/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java
index 9084efa..c2c7783 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java
@@ -39,8 +39,10 @@ import org.apache.calcite.rel.RelVisitor;
import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.Calc;
+import org.apache.calcite.rel.core.Filter;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.JoinInfo;
+import org.apache.calcite.rel.core.Snapshot;
import org.apache.calcite.rel.core.TableScan;
import org.apache.calcite.rel.hint.HintPredicate;
import org.apache.calcite.rel.hint.HintPredicates;
@@ -49,6 +51,7 @@ import org.apache.calcite.rel.hint.HintStrategyTable;
import org.apache.calcite.rel.hint.Hintable;
import org.apache.calcite.rel.hint.RelHint;
import org.apache.calcite.rel.logical.LogicalAggregate;
+import org.apache.calcite.rel.logical.LogicalCorrelate;
import org.apache.calcite.rel.logical.LogicalJoin;
import org.apache.calcite.rel.logical.LogicalProject;
import org.apache.calcite.rel.rules.CoreRules;
@@ -75,8 +78,10 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsIn.in;
@@ -145,6 +150,19 @@ class SqlHintsConverterTest extends SqlToRelTestBase {
sql(sql).ok();
}
+ @Test void testCorrelateHints() {
+ final String sql = "select /*+ use_hash_join (orders, products_temporal) */ stream *\n"
+ + "from orders join products_temporal for system_time as of orders.rowtime\n"
+ + "on orders.productid = products_temporal.productid and orders.orderId is not null";
+ sql(sql).ok();
+ }
+
+ @Test void testCrossCorrelateHints() {
+ final String sql = "select /*+ use_hash_join (orders, products_temporal) */ stream *\n"
+ + "from orders, products_temporal for system_time as of orders.rowtime";
+ sql(sql).ok();
+ }
+
@Test void testHintsInSubQueryWithDecorrelation() {
final String sql = "select /*+ resource(parallelism='3'), AGG_STRATEGY(TWO_PHASE) */\n"
+ "sum(e1.empno) from emp e1, dept d1\n"
@@ -693,6 +711,13 @@ class SqlHintsConverterTest extends SqlToRelTestBase {
}
return super.visit(aggregate);
}
+
+ @Override public RelNode visit(LogicalCorrelate correlate) {
+ if (correlate.getHints().size() > 0) {
+ this.hintsCollect.add("Correlate:" + correlate.getHints().toString());
+ }
+ return super.visit(correlate);
+ }
}
}
@@ -771,7 +796,9 @@ class SqlHintsConverterTest extends SqlToRelTestBase {
+ "allowed options: [ONE_PHASE, TWO_PHASE]",
hint.hintName)).build())
.hintStrategy("use_hash_join",
- HintPredicates.and(HintPredicates.JOIN, joinWithFixedTableName()))
+ HintPredicates.or(
+ HintPredicates.and(HintPredicates.CORRELATE, temporalJoinWithFixedTableName()),
+ HintPredicates.and(HintPredicates.JOIN, joinWithFixedTableName())))
.hintStrategy("use_merge_join",
HintStrategy.builder(
HintPredicates.and(HintPredicates.JOIN, joinWithFixedTableName()))
@@ -779,6 +806,39 @@ class SqlHintsConverterTest extends SqlToRelTestBase {
.build();
}
+ /** Returns a {@link HintPredicate} for temporal join with specified table references. */
+ private static HintPredicate temporalJoinWithFixedTableName() {
+ return (hint, rel) -> {
+ if (!(rel instanceof LogicalCorrelate)) {
+ return false;
+ }
+ LogicalCorrelate correlate = (LogicalCorrelate) rel;
+ Predicate<RelNode> isScan = r -> r instanceof TableScan;
+ if (!(isScan.test(correlate.getLeft()))) {
+ return false;
+ }
+ RelNode rightInput = correlate.getRight();
+ Predicate<RelNode> isSnapshotOnScan = r -> r instanceof Snapshot
+ && isScan.test(((Snapshot) r).getInput());
+ RelNode rightScan;
+ if (isSnapshotOnScan.test(rightInput)) {
+ rightScan = ((Snapshot) rightInput).getInput();
+ } else if (rightInput instanceof Filter
+ && isSnapshotOnScan.test(((Filter) rightInput).getInput())) {
+ rightScan = ((Snapshot) ((Filter) rightInput).getInput()).getInput();
+ } else {
+ // right child of correlate must be a snapshot on table scan directly or a Filter which
+ // input is snapshot on table scan
+ return false;
+ }
+ final List<String> tableNames = hint.listOptions;
+ final List<String> inputTables = Stream.of(correlate.getLeft(), rightScan)
+ .map(scan -> Util.last(scan.getTable().getQualifiedName()))
+ .collect(Collectors.toList());
+ return equalsStringList(inputTables, tableNames);
+ };
+ }
+
/** Returns a {@link HintPredicate} for join with specified table references. */
private static HintPredicate joinWithFixedTableName() {
return (hint, rel) -> {
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
index 5f9a0ad..4feeb39 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -41,6 +41,7 @@ import org.apache.calcite.rel.core.Correlate;
import org.apache.calcite.rel.core.CorrelationId;
import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rel.hint.RelHint;
import org.apache.calcite.rel.logical.LogicalTableScan;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -1078,23 +1079,29 @@ public abstract class SqlToRelTestBase {
public CustomCorrelate(
RelOptCluster cluster,
RelTraitSet traits,
+ List<RelHint> hints,
RelNode left,
RelNode right,
CorrelationId correlationId,
ImmutableBitSet requiredColumns,
JoinRelType joinType) {
- super(cluster, traits, left, right, correlationId, requiredColumns, joinType);
+ super(cluster, traits, hints, left, right, correlationId, requiredColumns, joinType);
}
@Override public Correlate copy(RelTraitSet traitSet,
RelNode left, RelNode right, CorrelationId correlationId,
ImmutableBitSet requiredColumns, JoinRelType joinType) {
- return new CustomCorrelate(getCluster(), traitSet, left, right,
+ return new CustomCorrelate(getCluster(), traitSet, hints, left, right,
correlationId, requiredColumns, joinType);
}
@Override public RelNode accept(RelShuttle shuttle) {
return shuttle.visit(this);
}
+
+ @Override public RelNode withHints(List<RelHint> hintList) {
+ return new CustomCorrelate(getCluster(), traitSet, hintList, left, right,
+ correlationId, requiredColumns, joinType);
+ }
}
}
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlHintsConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlHintsConverterTest.xml
index 4bb56c2..dbed18a 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlHintsConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlHintsConverterTest.xml
@@ -33,6 +33,32 @@ Project:[[RESOURCE inheritPath:[0, 0, 0, 0] options:{MEM=1024}]]
]]>
</Resource>
</TestCase>
+ <TestCase name="testCorrelateHints">
+ <Resource name="sql">
+ <![CDATA[select /*+ use_hash_join (orders, products_temporal) */ stream *
+from orders join products_temporal for system_time as of orders.rowtime
+on orders.productid = products_temporal.productid and orders.orderId is not null]]>
+ </Resource>
+ <Resource name="hints">
+ <![CDATA[
+Project:[[USE_HASH_JOIN inheritPath:[] options:[ORDERS, PRODUCTS_TEMPORAL]]]
+Correlate:[[USE_HASH_JOIN inheritPath:[0] options:[ORDERS, PRODUCTS_TEMPORAL]]]
+]]>
+ </Resource>
+ </TestCase>
+
+ <TestCase name="testCrossCorrelateHints">
+ <Resource name="sql">
+ <![CDATA[select /*+ use_hash_join (orders, products_temporal) */ stream *
+from orders, products_temporal for system_time as of orders.rowtime]]>
+ </Resource>
+ <Resource name="hints">
+ <![CDATA[
+Project:[[USE_HASH_JOIN inheritPath:[] options:[ORDERS, PRODUCTS_TEMPORAL]]]
+Correlate:[[USE_HASH_JOIN inheritPath:[0] options:[ORDERS, PRODUCTS_TEMPORAL]]]
+]]>
+ </Resource>
+ </TestCase>
<TestCase name="testFourLevelNestedQueryHint">
<Resource name="sql">
<![CDATA[select /*+ index(idx1), no_hash_join */ * from emp /*+ index(empno) */