Skip to content

Commit 2d28ce3

Browse files
ehdsmihaibudiu
authored andcommitted
[CALCITE-7825] RelMdTableReferences does not account for tables in RexSubQuery expressions or Correlate
1 parent 7478530 commit 2d28ce3

4 files changed

Lines changed: 309 additions & 60 deletions

File tree

‎core/src/main/java/org/apache/calcite/rel/metadata/RelMdTableReferences.java‎

Lines changed: 113 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,40 @@
2020
import org.apache.calcite.rel.RelNode;
2121
import org.apache.calcite.rel.core.Aggregate;
2222
import org.apache.calcite.rel.core.Calc;
23+
import org.apache.calcite.rel.core.Collect;
24+
import org.apache.calcite.rel.core.Combine;
25+
import org.apache.calcite.rel.core.Correlate;
2326
import org.apache.calcite.rel.core.Exchange;
2427
import org.apache.calcite.rel.core.Filter;
2528
import org.apache.calcite.rel.core.Join;
29+
import org.apache.calcite.rel.core.Match;
2630
import org.apache.calcite.rel.core.Project;
31+
import org.apache.calcite.rel.core.RepeatUnion;
2732
import org.apache.calcite.rel.core.Sample;
2833
import org.apache.calcite.rel.core.SetOp;
34+
import org.apache.calcite.rel.core.Snapshot;
2935
import org.apache.calcite.rel.core.Sort;
36+
import org.apache.calcite.rel.core.Spool;
3037
import org.apache.calcite.rel.core.TableFunctionScan;
3138
import org.apache.calcite.rel.core.TableModify;
3239
import org.apache.calcite.rel.core.TableScan;
40+
import org.apache.calcite.rel.core.Uncollect;
41+
import org.apache.calcite.rel.core.Values;
3342
import org.apache.calcite.rel.core.Window;
43+
import org.apache.calcite.rex.RexNode;
44+
import org.apache.calcite.rex.RexSubQuery;
3445
import org.apache.calcite.rex.RexTableInputRef.RelTableRef;
46+
import org.apache.calcite.rex.RexUtil;
3547
import org.apache.calcite.util.Util;
3648

3749
import com.google.common.collect.HashMultimap;
50+
import com.google.common.collect.ImmutableList;
3851
import com.google.common.collect.ImmutableSet;
3952
import com.google.common.collect.Multimap;
4053

4154
import org.checkerframework.checker.nullness.qual.Nullable;
4255

56+
import java.util.ArrayList;
4357
import java.util.Collection;
4458
import java.util.HashMap;
4559
import java.util.HashSet;
@@ -101,6 +115,11 @@ public Set<RelTableRef> getTableReferences(TableScan rel, RelMetadataQuery mq) {
101115
return ImmutableSet.of(RelTableRef.of(rel.getTable(), 0));
102116
}
103117

118+
/** Table references from Values. */
119+
public Set<RelTableRef> getTableReferences(Values rel, RelMetadataQuery mq) {
120+
return ImmutableSet.of();
121+
}
122+
104123
/**
105124
* Table references from Aggregate.
106125
*/
@@ -112,45 +131,23 @@ public Set<RelTableRef> getTableReferences(TableScan rel, RelMetadataQuery mq) {
112131
* Table references from Join.
113132
*/
114133
public @Nullable Set<RelTableRef> getTableReferences(Join rel, RelMetadataQuery mq) {
115-
final RelNode leftInput = rel.getLeft();
116-
final RelNode rightInput = rel.getRight();
117-
final Set<RelTableRef> result = new HashSet<>();
134+
return getTableReferences(ImmutableList.of(rel.getLeft(), rel.getRight()),
135+
ImmutableList.of(rel.getCondition()), mq);
136+
}
118137

119-
// Gather table references, left input references remain unchanged
120-
final Multimap<List<String>, RelTableRef> leftQualifiedNamesToRefs = HashMultimap.create();
121-
final Set<RelTableRef> leftTableRefs = mq.getTableReferences(leftInput);
122-
if (leftTableRefs == null) {
123-
// We could not infer the table refs from left input
124-
return null;
125-
}
126-
for (RelTableRef leftRef : leftTableRefs) {
127-
assert !result.contains(leftRef);
128-
result.add(leftRef);
129-
leftQualifiedNamesToRefs.put(leftRef.getQualifiedName(), leftRef);
130-
}
138+
/** Table references from both inputs of Correlate. */
139+
public @Nullable Set<RelTableRef> getTableReferences(Correlate rel, RelMetadataQuery mq) {
140+
return getTableReferences(rel.getInputs(), ImmutableList.of(), mq);
141+
}
131142

132-
// Gather table references, right input references might need to be
133-
// updated if there are table names clashes with left input
134-
final Set<RelTableRef> rightTableRefs = mq.getTableReferences(rightInput);
135-
if (rightTableRefs == null) {
136-
// We could not infer the table refs from right input
137-
return null;
138-
}
139-
for (RelTableRef rightRef : rightTableRefs) {
140-
int shift = 0;
141-
Collection<RelTableRef> lRefs =
142-
leftQualifiedNamesToRefs.get(rightRef.getQualifiedName());
143-
if (lRefs != null) {
144-
shift = lRefs.size();
145-
}
146-
RelTableRef shiftTableRef =
147-
RelTableRef.of(rightRef.getTable(), shift + rightRef.getEntityNumber());
148-
assert !result.contains(shiftTableRef);
149-
result.add(shiftTableRef);
150-
}
143+
/** Table references from RepeatUnion. */
144+
public @Nullable Set<RelTableRef> getTableReferences(RepeatUnion rel, RelMetadataQuery mq) {
145+
return getTableReferences(rel.getInputs(), ImmutableList.of(), mq);
146+
}
151147

152-
// Return result
153-
return result;
148+
/** Table references from Combine. */
149+
public @Nullable Set<RelTableRef> getTableReferences(Combine rel, RelMetadataQuery mq) {
150+
return getTableReferences(rel.getInputs(), ImmutableList.of(), mq);
154151
}
155152

156153
/**
@@ -160,31 +157,38 @@ public Set<RelTableRef> getTableReferences(TableScan rel, RelMetadataQuery mq) {
160157
* references.
161158
*/
162159
public @Nullable Set<RelTableRef> getTableReferences(SetOp rel, RelMetadataQuery mq) {
163-
return getTableReferences(rel.getInputs(), mq);
160+
return getTableReferences(rel.getInputs(), ImmutableList.of(), mq);
164161
}
165162

166163
/**
167-
* Table references from the relational inputs of a TableFunctionScan.
164+
* Table references from TableFunctionScan.
168165
*
169-
* <p>Returns an empty set if there are no inputs, and {@code null} if the table
170-
* references of any input cannot be determined. Tables accessed internally
171-
* by the table function are not included.
166+
* <p>Returns an empty set when its inputs and call reference no tables.
172167
*/
173168
public @Nullable Set<RelTableRef> getTableReferences(TableFunctionScan rel,
174169
RelMetadataQuery mq) {
175-
return getTableReferences(rel.getInputs(), mq);
170+
return getTableReferences(rel.getInputs(), ImmutableList.of(rel.getCall()), mq);
176171
}
177172

178-
/** Returns the union of the table references of {@code inputs}, assigning
179-
* distinct entity numbers to repeated references to the same table, or {@code null}
180-
* if the references of any input cannot be determined. */
173+
/** Returns the union of the table references of {@code inputs} and expression
174+
* sub-queries, assigning distinct entity numbers to repeated references to
175+
* the same table, or {@code null} if the references of any input or sub-query
176+
* cannot be determined. */
181177
private static @Nullable Set<RelTableRef> getTableReferences(
182-
List<RelNode> inputs, RelMetadataQuery mq) {
178+
List<RelNode> inputs, List<? extends RexNode> expressions, RelMetadataQuery mq) {
179+
final List<RelNode> rels = new ArrayList<>(inputs);
180+
final RexUtil.SubQueryCollector collector = new RexUtil.SubQueryCollector(true);
181+
for (RexNode expression : expressions) {
182+
expression.accept(collector);
183+
}
184+
for (RexSubQuery subQuery : collector.getSubQueries()) {
185+
rels.add(subQuery.rel);
186+
}
183187
final Set<RelTableRef> result = new HashSet<>();
184188

185189
// Infer column origin expressions for given references
186190
final Multimap<List<String>, RelTableRef> qualifiedNamesToRefs = HashMultimap.create();
187-
for (RelNode input : inputs) {
191+
for (RelNode input : rels) {
188192
final Map<RelTableRef, RelTableRef> currentTablesMapping = new HashMap<>();
189193
final Set<RelTableRef> inputTableRefs = mq.getTableReferences(input);
190194
if (inputTableRefs == null) {
@@ -218,35 +222,45 @@ public Set<RelTableRef> getTableReferences(TableScan rel, RelMetadataQuery mq) {
218222
* Table references from Project.
219223
*/
220224
public @Nullable Set<RelTableRef> getTableReferences(Project rel, final RelMetadataQuery mq) {
221-
return mq.getTableReferences(rel.getInput());
225+
return getTableReferences(ImmutableList.of(rel.getInput()), rel.getProjects(), mq);
222226
}
223227

224228
/**
225229
* Table references from Filter.
226230
*/
227231
public @Nullable Set<RelTableRef> getTableReferences(Filter rel, RelMetadataQuery mq) {
228-
return mq.getTableReferences(rel.getInput());
232+
return getTableReferences(ImmutableList.of(rel.getInput()),
233+
ImmutableList.of(rel.getCondition()), mq);
229234
}
230235

231236
/**
232237
* Table references from Calc.
233238
*/
234239
public @Nullable Set<RelTableRef> getTableReferences(Calc rel, RelMetadataQuery mq) {
235-
return mq.getTableReferences(rel.getInput());
240+
return getTableReferences(ImmutableList.of(rel.getInput()), rel.getProgram().getExprList(), mq);
236241
}
237242

238243
/**
239244
* Table references from Sort.
240245
*/
241246
public @Nullable Set<RelTableRef> getTableReferences(Sort rel, RelMetadataQuery mq) {
242-
return mq.getTableReferences(rel.getInput());
247+
final ImmutableList.Builder<RexNode> expressions = ImmutableList.builder();
248+
if (rel.offset != null) {
249+
expressions.add(rel.offset);
250+
}
251+
if (rel.fetch != null) {
252+
expressions.add(rel.fetch);
253+
}
254+
return getTableReferences(ImmutableList.of(rel.getInput()), expressions.build(), mq);
243255
}
244256

245257
/**
246258
* Table references from TableModify.
247259
*/
248260
public @Nullable Set<RelTableRef> getTableReferences(TableModify rel, RelMetadataQuery mq) {
249-
return mq.getTableReferences(rel.getInput());
261+
final List<RexNode> expressions = rel.getSourceExpressionList();
262+
return getTableReferences(ImmutableList.of(rel.getInput()),
263+
expressions == null ? ImmutableList.of() : expressions, mq);
250264
}
251265

252266
/**
@@ -260,7 +274,19 @@ public Set<RelTableRef> getTableReferences(TableScan rel, RelMetadataQuery mq) {
260274
* Table references from Window.
261275
*/
262276
public @Nullable Set<RelTableRef> getTableReferences(Window rel, RelMetadataQuery mq) {
263-
return mq.getTableReferences(rel.getInput());
277+
final ImmutableList.Builder<RexNode> expressions = ImmutableList.builder();
278+
for (Window.Group group : rel.groups) {
279+
expressions.addAll(group.aggCalls);
280+
final @Nullable RexNode lowerOffset = group.lowerBound.getOffset();
281+
if (lowerOffset != null) {
282+
expressions.add(lowerOffset);
283+
}
284+
final @Nullable RexNode upperOffset = group.upperBound.getOffset();
285+
if (upperOffset != null) {
286+
expressions.add(upperOffset);
287+
}
288+
}
289+
return getTableReferences(ImmutableList.of(rel.getInput()), expressions.build(), mq);
264290
}
265291

266292
/**
@@ -270,4 +296,38 @@ public Set<RelTableRef> getTableReferences(TableScan rel, RelMetadataQuery mq) {
270296
return mq.getTableReferences(rel.getInput());
271297
}
272298

299+
/** Table references from Snapshot. */
300+
public @Nullable Set<RelTableRef> getTableReferences(Snapshot rel, RelMetadataQuery mq) {
301+
return getTableReferences(ImmutableList.of(rel.getInput()),
302+
ImmutableList.of(rel.getPeriod()), mq);
303+
}
304+
305+
/** Table references from Match. */
306+
public @Nullable Set<RelTableRef> getTableReferences(Match rel, RelMetadataQuery mq) {
307+
final ImmutableList.Builder<RexNode> expressions = ImmutableList.builder();
308+
expressions.add(rel.getPattern(), rel.getAfter());
309+
expressions.addAll(rel.getMeasures().values());
310+
expressions.addAll(rel.getPatternDefinitions().values());
311+
final @Nullable RexNode interval = rel.getInterval();
312+
if (interval != null) {
313+
expressions.add(interval);
314+
}
315+
return getTableReferences(ImmutableList.of(rel.getInput()), expressions.build(), mq);
316+
}
317+
318+
/** Table references from Uncollect. */
319+
public @Nullable Set<RelTableRef> getTableReferences(Uncollect rel, RelMetadataQuery mq) {
320+
return mq.getTableReferences(rel.getInput());
321+
}
322+
323+
/** Table references from Collect. */
324+
public @Nullable Set<RelTableRef> getTableReferences(Collect rel, RelMetadataQuery mq) {
325+
return mq.getTableReferences(rel.getInput());
326+
}
327+
328+
/** Table references from Spool. */
329+
public @Nullable Set<RelTableRef> getTableReferences(Spool rel, RelMetadataQuery mq) {
330+
return mq.getTableReferences(rel.getInput());
331+
}
332+
273333
}

‎core/src/main/java/org/apache/calcite/rex/RexUtil.java‎

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3397,22 +3397,40 @@ public FixNullabilityShuttle(RexBuilder rexBuilder,
33973397
}
33983398
}
33993399

3400-
/** Visitor that collects all the top level SubQueries {@link RexSubQuery}
3401-
* in a projection list of a given {@link Project}.*/
3400+
/** Visitor that collects {@link RexSubQuery} expressions. */
34023401
public static class SubQueryCollector extends RexVisitorImpl<Void> {
34033402
private final List<RexSubQuery> subQueries;
3404-
private SubQueryCollector() {
3405-
super(true);
3403+
3404+
/** Creates a collector.
3405+
*
3406+
* @param deep Whether to visit expression operands; relational expressions
3407+
* inside sub-queries are never visited
3408+
*/
3409+
public SubQueryCollector(boolean deep) {
3410+
super(deep);
34063411
this.subQueries = new ArrayList<>();
34073412
}
34083413

34093414
@Override public Void visitSubQuery(RexSubQuery subQuery) {
34103415
subQueries.add(subQuery);
3411-
return null;
3416+
return super.visitSubQuery(subQuery);
3417+
}
3418+
3419+
/** Returns an immutable snapshot of the sub-queries collected so far,
3420+
* in visitation order. */
3421+
public List<RexSubQuery> getSubQueries() {
3422+
return ImmutableList.copyOf(subQueries);
34123423
}
34133424

3414-
public static List<RexSubQuery> collect(Project project) {
3415-
SubQueryCollector subQueryCollector = new SubQueryCollector();
3425+
/** Collects {@link RexSubQuery} expressions in the projection list
3426+
* of a given {@link Project}.
3427+
*
3428+
* @param project Project whose expressions are visited
3429+
* @param deep Whether to recursively visit expression operands; if false,
3430+
* collects only top-level {@link RexSubQuery} expressions in the projection list
3431+
*/
3432+
public static List<RexSubQuery> collect(Project project, boolean deep) {
3433+
SubQueryCollector subQueryCollector = new SubQueryCollector(deep);
34163434
for (RexNode node : project.getProjects()) {
34173435
node.accept(subQueryCollector);
34183436
}

0 commit comments

Comments
 (0)