Skip to content

Commit 4f4341c

Browse files
committed
[CALCITE-7442] Correlated variable has wrong index inside subquery
1 parent bbd083f commit 4f4341c

3 files changed

Lines changed: 262 additions & 12 deletions

File tree

core/src/main/java/org/apache/calcite/plan/RelOptUtil.java

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2957,7 +2957,8 @@ public static boolean classifyFilters(
29572957
joinFields,
29582958
nTotalFields,
29592959
leftFields,
2960-
filter);
2960+
filter,
2961+
joinRel.getInput(0));
29612962

29622963
leftFilters.add(shiftedFilter);
29632964
}
@@ -2975,7 +2976,8 @@ public static boolean classifyFilters(
29752976
joinFields,
29762977
nTotalFields,
29772978
rightFields,
2978-
filter);
2979+
filter,
2980+
joinRel.getInput(1));
29792981
rightFilters.add(shiftedFilter);
29802982
}
29812983
filtersToRemove.add(filter);
@@ -3079,7 +3081,8 @@ public static boolean classifyFilters(
30793081
joinFields,
30803082
nTotalFields,
30813083
leftFields,
3082-
filter);
3084+
filter,
3085+
joinRel.getInput(0));
30833086

30843087
leftFilters.add(shiftedFilter);
30853088
}
@@ -3105,7 +3108,8 @@ public static boolean classifyFilters(
31053108
joinFields,
31063109
nTotalFields,
31073110
rightFields,
3108-
filter);
3111+
filter,
3112+
joinRel.getInput(1));
31093113
rightFilters.add(shiftedFilter);
31103114
}
31113115
filtersToRemove.add(filter);
@@ -3140,7 +3144,8 @@ private static RexNode shiftFilter(
31403144
List<RelDataTypeField> joinFields,
31413145
int nTotalFields,
31423146
List<RelDataTypeField> rightFields,
3143-
RexNode filter) {
3147+
RexNode filter,
3148+
RelNode child) {
31443149
int[] adjustments = new int[nTotalFields];
31453150
for (int i = start; i < end; i++) {
31463151
adjustments[i] = offset;
@@ -3150,7 +3155,9 @@ private static RexNode shiftFilter(
31503155
rexBuilder,
31513156
joinFields,
31523157
rightFields,
3153-
adjustments));
3158+
adjustments,
3159+
offset,
3160+
child));
31543161
}
31553162

31563163
/**
@@ -4752,6 +4759,17 @@ public ImmutableBitSet build() {
47524759
}
47534760
return super.visitCall(call);
47544761
}
4762+
4763+
@Override public Void visitSubQuery(RexSubQuery subQuery) {
4764+
final Set<CorrelationId> variablesSet = RelOptUtil.getVariablesUsed(subQuery.rel);
4765+
for (CorrelationId id : variablesSet) {
4766+
ImmutableBitSet requiredColumns = RelOptUtil.correlationColumns(id, subQuery.rel);
4767+
for (int index : requiredColumns) {
4768+
bitBuilder.set(index);
4769+
}
4770+
}
4771+
return super.visitSubQuery(subQuery);
4772+
}
47554773
}
47564774

47574775
/**
@@ -4766,6 +4784,8 @@ public static class RexInputConverter extends RexShuttle {
47664784
private final @Nullable List<RelDataTypeField> rightDestFields;
47674785
private final int nLeftDestFields;
47684786
private final int[] adjustments;
4787+
private final int offset;
4788+
private final @Nullable RelNode correlateVariableChild;
47694789

47704790
/**
47714791
* Creates a RexInputConverter.
@@ -4784,14 +4804,23 @@ public static class RexInputConverter extends RexShuttle {
47844804
* @param rightDestFields in the case where the destination is a join,
47854805
* these are the fields from the right join input
47864806
* @param adjustments the amount to adjust each field by
4807+
* @param offset the amount to shift field accesses by when
4808+
* rewriting correlated subqueries
4809+
* @param correlateVariableChild the child relation providing the
4810+
* correlated variable; if non-null, subqueries
4811+
* referencing a correlation variable will have
4812+
* their field accesses shifted by {@code offset}
4813+
* relative to this child
47874814
*/
47884815
private RexInputConverter(
47894816
RexBuilder rexBuilder,
47904817
@Nullable List<RelDataTypeField> srcFields,
47914818
@Nullable List<RelDataTypeField> destFields,
47924819
@Nullable List<RelDataTypeField> leftDestFields,
47934820
@Nullable List<RelDataTypeField> rightDestFields,
4794-
int[] adjustments) {
4821+
int[] adjustments,
4822+
int offset,
4823+
@Nullable RelNode correlateVariableChild) {
47954824
this.rexBuilder = rexBuilder;
47964825
this.srcFields = srcFields;
47974826
this.destFields = destFields;
@@ -4804,6 +4833,8 @@ private RexInputConverter(
48044833
assert destFields == null;
48054834
nLeftDestFields = leftDestFields.size();
48064835
}
4836+
this.offset = offset;
4837+
this.correlateVariableChild = correlateVariableChild;
48074838
}
48084839

48094840
public RexInputConverter(
@@ -4818,22 +4849,61 @@ public RexInputConverter(
48184849
null,
48194850
leftDestFields,
48204851
rightDestFields,
4821-
adjustments);
4852+
adjustments,
4853+
0,
4854+
null);
48224855
}
48234856

48244857
public RexInputConverter(
48254858
RexBuilder rexBuilder,
48264859
@Nullable List<RelDataTypeField> srcFields,
48274860
@Nullable List<RelDataTypeField> destFields,
48284861
int[] adjustments) {
4829-
this(rexBuilder, srcFields, destFields, null, null, adjustments);
4862+
this(rexBuilder, srcFields, destFields, null, null, adjustments, 0, null);
48304863
}
48314864

48324865
public RexInputConverter(
48334866
RexBuilder rexBuilder,
48344867
@Nullable List<RelDataTypeField> srcFields,
48354868
int[] adjustments) {
4836-
this(rexBuilder, srcFields, null, null, null, adjustments);
4869+
this(rexBuilder, srcFields, null, null, null, adjustments, 0, null);
4870+
}
4871+
4872+
public RexInputConverter(
4873+
RexBuilder rexBuilder,
4874+
@Nullable List<RelDataTypeField> srcFields,
4875+
@Nullable List<RelDataTypeField> destFields,
4876+
int[] adjustments,
4877+
int offset,
4878+
RelNode child) {
4879+
this(rexBuilder, srcFields, destFields, null, null, adjustments, offset, child);
4880+
}
4881+
4882+
@Override public RexNode visitSubQuery(RexSubQuery subQuery) {
4883+
boolean[] update = {false};
4884+
List<RexNode> clonedOperands = visitList(subQuery.operands, update);
4885+
if (update[0]) {
4886+
subQuery = subQuery.clone(subQuery.getType(), clonedOperands);
4887+
}
4888+
final Set<CorrelationId> variablesSet =
4889+
RelOptUtil.getVariablesUsed(subQuery.rel);
4890+
if (!variablesSet.isEmpty() && correlateVariableChild != null) {
4891+
for (CorrelationId id : variablesSet) {
4892+
RelNode newSubQueryRel =
4893+
subQuery.rel.accept(new RelHomogeneousShuttle() {
4894+
@Override public RelNode visit(RelNode other) {
4895+
RelNode node =
4896+
RexUtil.shiftFieldAccess(rexBuilder, other, id,
4897+
correlateVariableChild, offset);
4898+
return super.visit(node);
4899+
}
4900+
});
4901+
if (newSubQueryRel != subQuery.rel) {
4902+
subQuery = subQuery.clone(newSubQueryRel);
4903+
}
4904+
}
4905+
}
4906+
return subQuery;
48374907
}
48384908

48394909
@Override public RexNode visitInputRef(RexInputRef var) {

core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.apache.calcite.plan.RelOptUtil;
2121
import org.apache.calcite.plan.RelRule;
2222
import org.apache.calcite.rel.RelNode;
23+
import org.apache.calcite.rel.core.CorrelationId;
2324
import org.apache.calcite.rel.core.Filter;
2425
import org.apache.calcite.rel.core.Join;
2526
import org.apache.calcite.rel.core.JoinRelType;
@@ -29,7 +30,9 @@
2930
import org.apache.calcite.rex.RexCall;
3031
import org.apache.calcite.rex.RexInputRef;
3132
import org.apache.calcite.rex.RexNode;
33+
import org.apache.calcite.rex.RexSubQuery;
3234
import org.apache.calcite.rex.RexUtil;
35+
import org.apache.calcite.rex.RexVisitorImpl;
3336
import org.apache.calcite.sql.SqlKind;
3437
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
3538
import org.apache.calcite.tools.RelBuilder;
@@ -198,14 +201,35 @@ protected void perform(RelOptRuleCall call, @Nullable Filter filter,
198201
return;
199202
}
200203

204+
Set<CorrelationId> leftVariablesSet = new LinkedHashSet<>();
205+
Set<CorrelationId> rightVariablesSet = new LinkedHashSet<>();
206+
207+
for (RexNode condition : leftFilters) {
208+
condition.accept(new RexVisitorImpl<Void>(true) {
209+
@Override public Void visitSubQuery(RexSubQuery subQuery) {
210+
leftVariablesSet.addAll(RelOptUtil.getVariablesUsed(subQuery.rel));
211+
return super.visitSubQuery(subQuery);
212+
}
213+
});
214+
}
215+
216+
for (RexNode condition : rightFilters) {
217+
condition.accept(new RexVisitorImpl<Void>(true) {
218+
@Override public Void visitSubQuery(RexSubQuery subQuery) {
219+
rightVariablesSet.addAll(RelOptUtil.getVariablesUsed(subQuery.rel));
220+
return super.visitSubQuery(subQuery);
221+
}
222+
});
223+
}
224+
201225
// create Filters on top of the children if any filters were
202226
// pushed to them
203227
final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
204228
final RelBuilder relBuilder = call.builder();
205229
final RelNode leftRel =
206-
relBuilder.push(join.getLeft()).filter(leftFilters).build();
230+
relBuilder.push(join.getLeft()).filter(leftVariablesSet, leftFilters).build();
207231
final RelNode rightRel =
208-
relBuilder.push(join.getRight()).filter(rightFilters).build();
232+
relBuilder.push(join.getRight()).filter(rightVariablesSet, rightFilters).build();
209233

210234
// create the new join node referencing the new children and
211235
// containing its new join filters (if there are any)

0 commit comments

Comments
 (0)