@@ -999,4 +999,203 @@ public static Frameworks.ConfigBuilder config() {
999999 + " LogicalTableScan(table=[[scott, DEPT]])\n " ;
10001000 assertThat (decorrelatedNoRules , hasTree (planDecorrelatedNoRules ));
10011001 }
1002+
1003+ @ Test void testDecorrelateCorrelatedOrderByLimitToRowNumber () {
1004+ final FrameworkConfig frameworkConfig = config ().build ();
1005+ final RelBuilder builder = RelBuilder .create (frameworkConfig );
1006+ final RelOptCluster cluster = builder .getCluster ();
1007+ final Planner planner = Frameworks .getPlanner (frameworkConfig );
1008+ final String sql = ""
1009+ + "SELECT dname FROM dept WHERE 2000 > (\n "
1010+ + "SELECT emp.sal FROM emp where dept.deptno = emp.deptno\n "
1011+ + "ORDER BY year(hiredate), emp.sal limit 1)" ;
1012+ final RelNode originalRel ;
1013+ try {
1014+ final SqlNode parse = planner .parse (sql );
1015+ final SqlNode validate = planner .validate (parse );
1016+ originalRel = planner .rel (validate ).rel ;
1017+ } catch (Exception e ) {
1018+ throw TestUtil .rethrow (e );
1019+ }
1020+
1021+ final HepProgram hepProgram = HepProgram .builder ()
1022+ .addRuleCollection (
1023+ ImmutableList .of (
1024+ // SubQuery program rules
1025+ CoreRules .FILTER_SUB_QUERY_TO_CORRELATE ,
1026+ CoreRules .PROJECT_SUB_QUERY_TO_CORRELATE ,
1027+ CoreRules .JOIN_SUB_QUERY_TO_CORRELATE ))
1028+ .build ();
1029+ final Program program =
1030+ Programs .of (hepProgram , true ,
1031+ requireNonNull (cluster .getMetadataProvider ()));
1032+ final RelNode before =
1033+ program .run (cluster .getPlanner (), originalRel , cluster .traitSet (),
1034+ Collections .emptyList (), Collections .emptyList ());
1035+ final String planBefore = ""
1036+ + "LogicalProject(DNAME=[$1])\n "
1037+ + " LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2])\n "
1038+ + " LogicalFilter(condition=[>(2000.00, CAST($3):DECIMAL(12, 2))])\n "
1039+ + " LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{0}])\n "
1040+ + " LogicalTableScan(table=[[scott, DEPT]])\n "
1041+ + " LogicalProject(SAL=[$0])\n "
1042+ + " LogicalSort(sort0=[$1], sort1=[$0], dir0=[ASC], dir1=[ASC], fetch=[1])\n "
1043+ + " LogicalProject(SAL=[$5], EXPR$1=[EXTRACT(FLAG(YEAR), $4)])\n "
1044+ + " LogicalFilter(condition=[=($cor0.DEPTNO, $7)])\n "
1045+ + " LogicalTableScan(table=[[scott, EMP]])\n " ;
1046+ assertThat (before , hasTree (planBefore ));
1047+
1048+ // Decorrelate without any rules, just "purely" decorrelation algorithm on RelDecorrelator
1049+ final RelNode after =
1050+ RelDecorrelator .decorrelateQuery (before , builder , RuleSets .ofList (Collections .emptyList ()),
1051+ RuleSets .ofList (Collections .emptyList ()));
1052+ // Verify plan
1053+ final String planAfter = ""
1054+ + "LogicalProject(DNAME=[$1])\n "
1055+ + " LogicalJoin(condition=[=($0, $4)], joinType=[inner])\n "
1056+ + " LogicalTableScan(table=[[scott, DEPT]])\n "
1057+ + " LogicalFilter(condition=[>(2000.00, CAST($0):DECIMAL(12, 2))])\n "
1058+ + " LogicalProject(SAL=[$0], DEPTNO=[$2])\n "
1059+ + " LogicalFilter(condition=[<=($3, 1)])\n "
1060+ + " LogicalProject(SAL=[$5], EXPR$1=[EXTRACT(FLAG(YEAR), $4)], DEPTNO=[$7], rn=[ROW_NUMBER() OVER (PARTITION BY $7 ORDER BY EXTRACT(FLAG(YEAR), $4) NULLS LAST, $5 NULLS LAST)])\n "
1061+ + " LogicalFilter(condition=[IS NOT NULL($7)])\n "
1062+ + " LogicalTableScan(table=[[scott, EMP]])\n " ;
1063+ assertThat (after , hasTree (planAfter ));
1064+ }
1065+
1066+ @ Test void testDecorrelateCorrelatedOrderByLimitToRowNumber2 () {
1067+ final FrameworkConfig frameworkConfig = config ().build ();
1068+ final RelBuilder builder = RelBuilder .create (frameworkConfig );
1069+ final RelOptCluster cluster = builder .getCluster ();
1070+ final Planner planner = Frameworks .getPlanner (frameworkConfig );
1071+ final String sql = ""
1072+ + "SELECT *\n "
1073+ + "FROM dept d\n "
1074+ + "WHERE d.deptno IN (\n "
1075+ + " SELECT e.deptno\n "
1076+ + " FROM emp e\n "
1077+ + " WHERE d.deptno = e.deptno\n "
1078+ + " LIMIT 10\n "
1079+ + " OFFSET 2\n "
1080+ + ")\n "
1081+ + "LIMIT 2\n "
1082+ + "OFFSET 1" ;
1083+ final RelNode originalRel ;
1084+ try {
1085+ final SqlNode parse = planner .parse (sql );
1086+ final SqlNode validate = planner .validate (parse );
1087+ originalRel = planner .rel (validate ).rel ;
1088+ } catch (Exception e ) {
1089+ throw TestUtil .rethrow (e );
1090+ }
1091+
1092+ final HepProgram hepProgram = HepProgram .builder ()
1093+ .addRuleCollection (
1094+ ImmutableList .of (
1095+ // SubQuery program rules
1096+ CoreRules .FILTER_SUB_QUERY_TO_CORRELATE ,
1097+ CoreRules .PROJECT_SUB_QUERY_TO_CORRELATE ,
1098+ CoreRules .JOIN_SUB_QUERY_TO_CORRELATE ))
1099+ .build ();
1100+ final Program program =
1101+ Programs .of (hepProgram , true ,
1102+ requireNonNull (cluster .getMetadataProvider ()));
1103+ final RelNode before =
1104+ program .run (cluster .getPlanner (), originalRel , cluster .traitSet (),
1105+ Collections .emptyList (), Collections .emptyList ());
1106+ final String planBefore = ""
1107+ + "LogicalSort(offset=[1], fetch=[2])\n "
1108+ + " LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2])\n "
1109+ + " LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2])\n "
1110+ + " LogicalFilter(condition=[=($0, $3)])\n "
1111+ + " LogicalCorrelate(correlation=[$cor0], joinType=[inner], requiredColumns=[{0}])\n "
1112+ + " LogicalTableScan(table=[[scott, DEPT]])\n "
1113+ + " LogicalAggregate(group=[{0}])\n "
1114+ + " LogicalSort(offset=[2], fetch=[10])\n "
1115+ + " LogicalProject(DEPTNO=[$7])\n "
1116+ + " LogicalFilter(condition=[=($cor0.DEPTNO, $7)])\n "
1117+ + " LogicalTableScan(table=[[scott, EMP]])\n " ;
1118+ assertThat (before , hasTree (planBefore ));
1119+
1120+ // Decorrelate without any rules, just "purely" decorrelation algorithm on RelDecorrelator
1121+ final RelNode after =
1122+ RelDecorrelator .decorrelateQuery (before , builder , RuleSets .ofList (Collections .emptyList ()),
1123+ RuleSets .ofList (Collections .emptyList ()));
1124+ // Verify plan
1125+ final String planAfter = ""
1126+ + "LogicalSort(offset=[1], fetch=[2])\n "
1127+ + " LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2])\n "
1128+ + " LogicalJoin(condition=[=($0, $4)], joinType=[inner])\n "
1129+ + " LogicalTableScan(table=[[scott, DEPT]])\n "
1130+ + " LogicalFilter(condition=[=($1, $0)])\n "
1131+ + " LogicalAggregate(group=[{0, 1}])\n "
1132+ + " LogicalProject(DEPTNO=[$0], DEPTNO1=[$1])\n "
1133+ + " LogicalFilter(condition=[AND(>($2, 2), <=($2, +(2, 10)))])\n "
1134+ + " LogicalProject(DEPTNO=[$7], DEPTNO1=[$7], rn=[ROW_NUMBER() OVER (PARTITION BY $7)])\n "
1135+ + " LogicalFilter(condition=[IS NOT NULL($7)])\n "
1136+ + " LogicalTableScan(table=[[scott, EMP]])\n " ;
1137+ assertThat (after , hasTree (planAfter ));
1138+ }
1139+
1140+ @ Test void testDecorrelateCorrelatedOrderByLimitToRowNumber3 () {
1141+ final FrameworkConfig frameworkConfig = config ().build ();
1142+ final RelBuilder builder = RelBuilder .create (frameworkConfig );
1143+ final RelOptCluster cluster = builder .getCluster ();
1144+ final Planner planner = Frameworks .getPlanner (frameworkConfig );
1145+ final String sql = ""
1146+ + "SELECT deptno FROM dept WHERE 1000.00 >\n "
1147+ + "(SELECT sal FROM emp WHERE dept.deptno = emp.deptno\n "
1148+ + "order by emp.sal limit 1 offset 10)" ;
1149+ final RelNode originalRel ;
1150+ try {
1151+ final SqlNode parse = planner .parse (sql );
1152+ final SqlNode validate = planner .validate (parse );
1153+ originalRel = planner .rel (validate ).rel ;
1154+ } catch (Exception e ) {
1155+ throw TestUtil .rethrow (e );
1156+ }
1157+
1158+ final HepProgram hepProgram = HepProgram .builder ()
1159+ .addRuleCollection (
1160+ ImmutableList .of (
1161+ // SubQuery program rules
1162+ CoreRules .FILTER_SUB_QUERY_TO_CORRELATE ,
1163+ CoreRules .PROJECT_SUB_QUERY_TO_CORRELATE ,
1164+ CoreRules .JOIN_SUB_QUERY_TO_CORRELATE ))
1165+ .build ();
1166+ final Program program =
1167+ Programs .of (hepProgram , true ,
1168+ requireNonNull (cluster .getMetadataProvider ()));
1169+ final RelNode before =
1170+ program .run (cluster .getPlanner (), originalRel , cluster .traitSet (),
1171+ Collections .emptyList (), Collections .emptyList ());
1172+ final String planBefore = ""
1173+ + "LogicalProject(DEPTNO=[$0])\n "
1174+ + " LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2])\n "
1175+ + " LogicalFilter(condition=[>(1000.00, $3)])\n "
1176+ + " LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{0}])\n "
1177+ + " LogicalTableScan(table=[[scott, DEPT]])\n "
1178+ + " LogicalSort(sort0=[$0], dir0=[ASC], offset=[10], fetch=[1])\n "
1179+ + " LogicalProject(SAL=[$5])\n "
1180+ + " LogicalFilter(condition=[=($cor0.DEPTNO, $7)])\n "
1181+ + " LogicalTableScan(table=[[scott, EMP]])\n " ;
1182+ assertThat (before , hasTree (planBefore ));
1183+
1184+ // Decorrelate without any rules, just "purely" decorrelation algorithm on RelDecorrelator
1185+ final RelNode after =
1186+ RelDecorrelator .decorrelateQuery (before , builder , RuleSets .ofList (Collections .emptyList ()),
1187+ RuleSets .ofList (Collections .emptyList ()));
1188+ // Verify plan
1189+ final String planAfter = ""
1190+ + "LogicalProject(DEPTNO=[$0])\n "
1191+ + " LogicalProject(DEPTNO=[$0], DNAME=[$1], LOC=[$2], SAL=[$3], DEPTNO0=[$4], rn=[CAST($5):BIGINT])\n "
1192+ + " LogicalJoin(condition=[=($0, $4)], joinType=[inner])\n "
1193+ + " LogicalTableScan(table=[[scott, DEPT]])\n "
1194+ + " LogicalFilter(condition=[>(1000.00, $0)])\n "
1195+ + " LogicalFilter(condition=[AND(>($2, 10), <=($2, +(10, 1)))])\n "
1196+ + " LogicalProject(SAL=[$5], DEPTNO=[$7], rn=[ROW_NUMBER() OVER (PARTITION BY $7 ORDER BY $5 NULLS LAST)])\n "
1197+ + " LogicalFilter(condition=[IS NOT NULL($7)])\n "
1198+ + " LogicalTableScan(table=[[scott, EMP]])\n " ;
1199+ assertThat (after , hasTree (planAfter ));
1200+ }
10021201}
0 commit comments