@@ -84,6 +84,78 @@ public static Frameworks.ConfigBuilder config() {
8484 assertThat (after , hasTree (planAfter ));
8585 }
8686
87+ /** Test case for <a href="https://issues.apache.org/jira/projects/CALCITE/issues/CALCITE-7646">[CALCITE-7646]
88+ * CorrelateProjectExtractor does not handle nested field accesses cor0.field0.field1</a>. */
89+ @ Test void testNestedCorrelationFieldAccessInFilter () {
90+ final RelBuilder builder = RelBuilder .create (config ().build ());
91+ final Holder <@ Nullable RexCorrelVariable > v = Holder .empty ();
92+ RelNode before = builder .scan ("EMP" )
93+ .project (
94+ builder .alias (
95+ builder .call (SqlStdOperatorTable .ROW ,
96+ builder .field ("EMPNO" ), builder .field ("DEPTNO" )), "R" ))
97+ .variable (v ::set )
98+ .scan ("DEPT" )
99+ .filter (
100+ builder .equals (builder .field (0 ),
101+ builder .getRexBuilder ().makeFieldAccess (builder .field (v .get (), "R" ), 1 )))
102+ .correlate (JoinRelType .LEFT , v .get ().id , builder .field (2 , 0 , "R" ))
103+ .build ();
104+
105+ final String planBefore = ""
106+ + "LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{0}])\n "
107+ + " LogicalProject(R=[ROW($0, $7)])\n "
108+ + " LogicalTableScan(table=[[scott, EMP]])\n "
109+ + " LogicalFilter(condition=[=($0, $cor0.R.EXPR$1)])\n "
110+ + " LogicalTableScan(table=[[scott, DEPT]])\n " ;
111+ assertThat (before , hasTree (planBefore ));
112+
113+ RelNode after = before .accept (new CorrelateProjectExtractor (RelFactories .LOGICAL_BUILDER ));
114+ final String planAfter = ""
115+ + "LogicalProject(R=[$0], DEPTNO=[$2], DNAME=[$3], LOC=[$4])\n "
116+ + " LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{1}])\n "
117+ + " LogicalProject(R=[ROW($0, $7)], $f1=[ROW($0, $7).EXPR$1])\n "
118+ + " LogicalTableScan(table=[[scott, EMP]])\n "
119+ + " LogicalFilter(condition=[=($0, $cor0.$f1)])\n "
120+ + " LogicalTableScan(table=[[scott, DEPT]])\n " ;
121+ assertThat (after , hasTree (planAfter ));
122+ }
123+
124+ /** Tests that a constant call operand, such as {@code POWER(2, 3)}, does
125+ * not prevent extracting the enclosing correlated call. */
126+ @ Test void testCorrelationCallWithConstantCallOperandInFilter () {
127+ final RelBuilder builder = RelBuilder .create (config ().build ());
128+ final Holder <@ Nullable RexCorrelVariable > v = Holder .empty ();
129+ RelNode before = builder .scan ("EMP" )
130+ .variable (v ::set )
131+ .scan ("DEPT" )
132+ .filter (
133+ builder .equals (builder .field (0 ),
134+ builder .call (SqlStdOperatorTable .PLUS ,
135+ builder .call (SqlStdOperatorTable .POWER ,
136+ builder .literal (2 ), builder .literal (3 )),
137+ builder .field (v .get (), "DEPTNO" ))))
138+ .correlate (JoinRelType .LEFT , v .get ().id , builder .field (2 , 0 , "DEPTNO" ))
139+ .build ();
140+
141+ final String planBefore = ""
142+ + "LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{7}])\n "
143+ + " LogicalTableScan(table=[[scott, EMP]])\n "
144+ + " LogicalFilter(condition=[=($0, +(POWER(2, 3), $cor0.DEPTNO))])\n "
145+ + " LogicalTableScan(table=[[scott, DEPT]])\n " ;
146+ assertThat (before , hasTree (planBefore ));
147+
148+ RelNode after = before .accept (new CorrelateProjectExtractor (RelFactories .LOGICAL_BUILDER ));
149+ final String planAfter = ""
150+ + "LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], DEPTNO0=[$9], DNAME=[$10], LOC=[$11])\n "
151+ + " LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{8}])\n "
152+ + " LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], $f8=[+(POWER(2, 3), $7)])\n "
153+ + " LogicalTableScan(table=[[scott, EMP]])\n "
154+ + " LogicalFilter(condition=[=($0, $cor0.$f8)])\n "
155+ + " LogicalTableScan(table=[[scott, DEPT]])\n " ;
156+ assertThat (after , hasTree (planAfter ));
157+ }
158+
87159 @ Test void testDoubleCorrelationCallOverVariableInFilters () {
88160 final RelBuilder builder = RelBuilder .create (config ().build ());
89161 final Holder <@ Nullable RexCorrelVariable > v = Holder .empty ();
0 commit comments