@@ -1213,6 +1213,116 @@ private CalciteAssert.AssertThat with() {
12131213 assertThat (after , hasTree (planAfter ));
12141214 }
12151215
1216+ /** Test case for <a href="https://issues.apache.org/jira/browse/CALCITE-7324">[CALCITE-7324]
1217+ * NullPointerException from RelDecorrelator with multiple subqueries
1218+ * where one has a complex correlated condition</a>. */
1219+ @ Test public void test7324 ()
1220+ throws SqlParseException , ValidationException , RelConversionException {
1221+ SchemaPlus rootSchema = Frameworks .createRootSchema (true );
1222+ TpchSchema tpchSchema = new TpchSchema (1.0 , 0 , 1 , false );
1223+ rootSchema .add ("TPCH" , tpchSchema );
1224+ FrameworkConfig config = Frameworks .newConfigBuilder ()
1225+ .defaultSchema (rootSchema )
1226+ .build ();
1227+ final RelBuilder builder = RelBuilder .create (config );
1228+ final RelOptCluster cluster = builder .getCluster ();
1229+
1230+ Planner planner = Frameworks .getPlanner (config );
1231+
1232+ String sql = ""
1233+ + "select\n " +
1234+ " (select count(*) from tpch.PART where p_partkey = PARTSUPP.ps_partkey),\n " +
1235+ " (select count(*) from tpch.SUPPLIER\n " +
1236+ "where s_suppkey = case when s_acctbal > 0 then PARTSUPP.ps_partkey + 1 else 1234 end)\n " +
1237+ "from tpch.PARTSUPP" ;
1238+
1239+ SqlNode parsed = planner .parse (sql );
1240+ SqlNode validated = planner .validate (parsed );
1241+ RelRoot root = planner .rel (validated );
1242+ final RelNode originalRel = root .rel ;
1243+
1244+ final HepProgram hepProgram = HepProgram .builder ()
1245+ .addRuleCollection (
1246+ ImmutableList .of (
1247+ // SubQuery program rules
1248+ CoreRules .FILTER_SUB_QUERY_TO_CORRELATE ,
1249+ CoreRules .PROJECT_SUB_QUERY_TO_CORRELATE ,
1250+ CoreRules .JOIN_SUB_QUERY_TO_CORRELATE ))
1251+ .build ();
1252+ final Program program =
1253+ Programs .of (hepProgram , true ,
1254+ requireNonNull (cluster .getMetadataProvider ()));
1255+ final RelNode before =
1256+ program .run (cluster .getPlanner (), originalRel , cluster .traitSet (),
1257+ Collections .emptyList (), Collections .emptyList ());
1258+ final String planBefore = ""
1259+ + "LogicalProject(EXPR$0=[$5], EXPR$1=[$6])\n "
1260+ + " LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{0}])\n "
1261+ + " LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{0}])\n "
1262+ + " LogicalTableScan(table=[[TPCH, PARTSUPP]])\n "
1263+ + " LogicalAggregate(group=[{}], EXPR$0=[COUNT()])\n "
1264+ + " LogicalFilter(condition=[=($0, $cor0.PS_PARTKEY)])\n "
1265+ + " LogicalTableScan(table=[[TPCH, PART]])\n "
1266+ + " LogicalAggregate(group=[{}], EXPR$0=[COUNT()])\n "
1267+ + " LogicalFilter(condition=[=(CAST($0):BIGINT, CASE(>(CAST($5):DOUBLE, CAST(0):DOUBLE NOT NULL), +($cor0.PS_PARTKEY, 1), 1234:BIGINT))])\n "
1268+ + " LogicalTableScan(table=[[TPCH, SUPPLIER]])\n " ;
1269+ assertThat (before , hasTree (planBefore ));
1270+
1271+ // Decorrelate without any rules, just "purely" decorrelation algorithm on RelDecorrelator
1272+ final RelNode after =
1273+ RelDecorrelator .decorrelateQuery (before , builder ,
1274+ RuleSets .ofList (Collections .emptyList ()),
1275+ RuleSets .ofList (Collections .emptyList ()));
1276+ final String planAfter = ""
1277+ + "LogicalProject(EXPR$0=[$5], EXPR$1=[$8])\n "
1278+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($6, $7)], joinType=[left])\n "
1279+ + " LogicalProject(PS_PARTKEY=[$0], PS_SUPPKEY=[$1], PS_AVAILQTY=[$2], PS_SUPPLYCOST=[$3], PS_COMMENT=[$4], EXPR$0=[$6], $f6=[+($0, 1)])\n "
1280+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $5)], joinType=[left])\n "
1281+ + " LogicalTableScan(table=[[TPCH, PARTSUPP]])\n "
1282+ + " LogicalProject(P_PARTKEY=[$0], EXPR$0=[CASE(IS NOT NULL($2), $2, 0)])\n "
1283+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)], joinType=[left])\n "
1284+ + " LogicalAggregate(group=[{0}])\n "
1285+ + " LogicalProject(PS_PARTKEY=[$0])\n "
1286+ + " LogicalTableScan(table=[[TPCH, PARTSUPP]])\n "
1287+ + " LogicalAggregate(group=[{0}], EXPR$0=[COUNT()])\n "
1288+ + " LogicalProject(P_PARTKEY=[$0])\n "
1289+ + " LogicalFilter(condition=[IS NOT NULL($0)])\n "
1290+ + " LogicalTableScan(table=[[TPCH, PART]])\n "
1291+ + " LogicalProject($f6=[$0], EXPR$0=[CASE(IS NOT NULL($2), $2, 0)])\n "
1292+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)], joinType=[left])\n "
1293+ + " LogicalAggregate(group=[{0}])\n "
1294+ + " LogicalProject($f6=[+($0, 1)])\n "
1295+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $5)], joinType=[left])\n "
1296+ + " LogicalTableScan(table=[[TPCH, PARTSUPP]])\n "
1297+ + " LogicalProject(P_PARTKEY=[$0], EXPR$0=[CASE(IS NOT NULL($2), $2, 0)])\n "
1298+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)], joinType=[left])\n "
1299+ + " LogicalAggregate(group=[{0}])\n "
1300+ + " LogicalProject(PS_PARTKEY=[$0])\n "
1301+ + " LogicalTableScan(table=[[TPCH, PARTSUPP]])\n "
1302+ + " LogicalAggregate(group=[{0}], EXPR$0=[COUNT()])\n "
1303+ + " LogicalProject(P_PARTKEY=[$0])\n "
1304+ + " LogicalFilter(condition=[IS NOT NULL($0)])\n "
1305+ + " LogicalTableScan(table=[[TPCH, PART]])\n "
1306+ + " LogicalAggregate(group=[{0}], EXPR$0=[COUNT()])\n "
1307+ + " LogicalProject($f6=[$7])\n "
1308+ + " LogicalJoin(condition=[=(CAST($0):BIGINT, CASE(>(CAST($5):DOUBLE, 0.0E0), $7, 1234:BIGINT))], joinType=[inner])\n "
1309+ + " LogicalTableScan(table=[[TPCH, SUPPLIER]])\n "
1310+ + " LogicalAggregate(group=[{0}])\n "
1311+ + " LogicalProject($f6=[+($0, 1)])\n "
1312+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $5)], joinType=[left])\n "
1313+ + " LogicalTableScan(table=[[TPCH, PARTSUPP]])\n "
1314+ + " LogicalProject(P_PARTKEY=[$0], EXPR$0=[CASE(IS NOT NULL($2), $2, 0)])\n "
1315+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)], joinType=[left])\n "
1316+ + " LogicalAggregate(group=[{0}])\n "
1317+ + " LogicalProject(PS_PARTKEY=[$0])\n "
1318+ + " LogicalTableScan(table=[[TPCH, PARTSUPP]])\n "
1319+ + " LogicalAggregate(group=[{0}], EXPR$0=[COUNT()])\n "
1320+ + " LogicalProject(P_PARTKEY=[$0])\n "
1321+ + " LogicalFilter(condition=[IS NOT NULL($0)])\n "
1322+ + " LogicalTableScan(table=[[TPCH, PART]])\n " ;
1323+ assertThat (after , hasTree (planAfter ));
1324+ }
1325+
12161326 private void checkQuery (int i ) {
12171327 query (i ).runs ();
12181328 }
0 commit comments