1515import org .apache .calcite .rex .RexSubQuery ;
1616import org .apache .calcite .rex .RexUtil .SubQueryCollector ;
1717
18- /** Resolve correlated variable and get Depth map for RexFieldAccess */
19- // See OuterReferenceResolver.md for explanation how the Depth map is computed.
18+ /**
19+ * Resolve correlated variables and compute a depth map for {@link RexFieldAccess}.
20+ *
21+ * <p>Traverses a {@link RelNode} tree and:
22+ *
23+ * <ul>
24+ * <li>Tracks nesting depth of {@link CorrelationId}s across filters, projects, subqueries, and
25+ * correlates
26+ * <li>Computes "steps out" for each {@link RexFieldAccess} referencing a {@link
27+ * RexCorrelVariable}
28+ * </ul>
29+ *
30+ * See OuterReferenceResolver.md for details on how the depth map is computed.
31+ */
2032public class OuterReferenceResolver extends RelNodeVisitor <RelNode , RuntimeException > {
2133
2234 private final Map <CorrelationId , Integer > nestedDepth ;
2335 private final Map <RexFieldAccess , Integer > fieldAccessDepthMap ;
2436
2537 private final RexVisitor rexVisitor = new RexVisitor (this );
2638
39+ /** Creates a new resolver with empty depth tracking maps. */
2740 public OuterReferenceResolver () {
2841 nestedDepth = new HashMap <>();
2942 fieldAccessDepthMap = new IdentityHashMap <>();
3043 }
3144
45+ /**
46+ * Returns the number of "steps out" (nesting depth) for a given {@link RexFieldAccess}.
47+ *
48+ * @param fieldAccess the field access referencing a {@link RexCorrelVariable}
49+ * @return the number of outer scopes between the access and its correlation source, or {@code
50+ * null} if not tracked
51+ */
3252 public int getStepsOut (RexFieldAccess fieldAccess ) {
3353 return fieldAccessDepthMap .get (fieldAccess );
3454 }
3555
56+ /**
57+ * Applies the resolver to a {@link RelNode} tree, computing the depth map.
58+ *
59+ * @param r the root relational node
60+ * @return the same node after traversal
61+ * @throws RuntimeException if the visitor encounters an unrecoverable condition
62+ */
3663 public RelNode apply (RelNode r ) {
3764 return reverseAccept (r );
3865 }
3966
67+ /**
68+ * Returns the computed map from {@link RexFieldAccess} to depth (steps out).
69+ *
70+ * @return map of field access to depth
71+ */
4072 public Map <RexFieldAccess , Integer > getFieldAccessDepthMap () {
4173 return fieldAccessDepthMap ;
4274 }
4375
76+ /**
77+ * Visits a {@link Filter}, registering any correlation variables and visiting its condition.
78+ *
79+ * @param filter the filter node
80+ * @return the result of {@link RelNodeVisitor#visit(Filter)}
81+ * @throws RuntimeException if traversal fails
82+ */
4483 @ Override
4584 public RelNode visit (Filter filter ) throws RuntimeException {
4685 for (CorrelationId id : filter .getVariablesSet ()) {
@@ -50,6 +89,16 @@ public RelNode visit(Filter filter) throws RuntimeException {
5089 return super .visit (filter );
5190 }
5291
92+ /**
93+ * Visits a {@link Correlate}, handling correlation depth for both sides.
94+ *
95+ * <p>Special case: the right side is a correlated subquery in the rel tree (not a REX), so we
96+ * manually adjust depth before/after visiting it.
97+ *
98+ * @param correlate the correlate (correlated join) node
99+ * @return the correlate node
100+ * @throws RuntimeException if traversal fails
101+ */
53102 @ Override
54103 public RelNode visit (Correlate correlate ) throws RuntimeException {
55104 for (CorrelationId id : correlate .getVariablesSet ()) {
@@ -70,6 +119,13 @@ public RelNode visit(Correlate correlate) throws RuntimeException {
70119 return correlate ;
71120 }
72121
122+ /**
123+ * Visits a generic {@link RelNode}, applying traversal to all inputs.
124+ *
125+ * @param other the node to visit
126+ * @return the node
127+ * @throws RuntimeException if traversal fails
128+ */
73129 @ Override
74130 public RelNode visitOther (RelNode other ) throws RuntimeException {
75131 for (RelNode child : other .getInputs ()) {
@@ -78,6 +134,14 @@ public RelNode visitOther(RelNode other) throws RuntimeException {
78134 return other ;
79135 }
80136
137+ /**
138+ * Visits a {@link Project}, registering correlation variables and visiting any subqueries within
139+ * its expressions.
140+ *
141+ * @param project the project node
142+ * @return the result of {@link RelNodeVisitor#visit(Project)}
143+ * @throws RuntimeException if traversal fails
144+ */
81145 @ Override
82146 public RelNode visit (Project project ) throws RuntimeException {
83147 for (CorrelationId id : project .getVariablesSet ()) {
@@ -91,13 +155,25 @@ public RelNode visit(Project project) throws RuntimeException {
91155 return super .visit (project );
92156 }
93157
158+ /** Rex visitor used to track correlation depth within expressions and subqueries. */
94159 private static class RexVisitor extends RexShuttle {
95160 final OuterReferenceResolver referenceResolver ;
96161
162+ /**
163+ * Creates a new Rex visitor bound to the given reference resolver.
164+ *
165+ * @param referenceResolver the parent resolver maintaining depth maps
166+ */
97167 RexVisitor (OuterReferenceResolver referenceResolver ) {
98168 this .referenceResolver = referenceResolver ;
99169 }
100170
171+ /**
172+ * Increments correlation depth when entering a subquery and decrements when exiting.
173+ *
174+ * @param subQuery the subquery expression
175+ * @return the same subquery
176+ */
101177 @ Override
102178 public RexNode visitSubQuery (RexSubQuery subQuery ) {
103179 referenceResolver .nestedDepth .replaceAll ((k , v ) -> v + 1 );
@@ -108,6 +184,12 @@ public RexNode visitSubQuery(RexSubQuery subQuery) {
108184 return subQuery ;
109185 }
110186
187+ /**
188+ * Records depth for {@link RexFieldAccess} referencing a {@link RexCorrelVariable}.
189+ *
190+ * @param fieldAccess the field access expression
191+ * @return the same field access
192+ */
111193 @ Override
112194 public RexNode visitFieldAccess (RexFieldAccess fieldAccess ) {
113195 if (fieldAccess .getReferenceExpr () instanceof RexCorrelVariable ) {
0 commit comments