diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 936b17364..a4cc62dd5 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -419,6 +419,16 @@ ShouldRecursivelyPlanNonColocatedSubqueries(Query *subquery, return false; } + /* + * recursively plan noncolocated outer relations inside subquery + */ + JoinRestrictionContext *joinRestrictionContext = + context->plannerRestrictionContext->joinRestrictionContext; + if (joinRestrictionContext && joinRestrictionContext->hasOuterJoin) + { + return true; + } + /* * This check helps us in two ways: * (i) We're not targeting queries that don't include subqueries at all, @@ -583,20 +593,52 @@ RecursivelyPlanNonColocatedJoinWalker(Node *joinNode, RangeTblEntry *rte = rt_fetch(rangeTableIndex, rangeTableList); /* we're only interested in subqueries for now */ - if (rte->rtekind != RTE_SUBQUERY) + if (rte->rtekind == RTE_SUBQUERY) { - return; + /* + * If the subquery is not colocated with the anchor subquery, + * recursively plan it. + */ + Query *subquery = rte->subquery; + if (!SubqueryColocated(subquery, colocatedJoinChecker)) + { + RecursivelyPlanSubquery(subquery, recursivePlanningContext); + } + } + else if (rte->rtekind == RTE_RELATION) + { + /* + * when query tree contains only inner joins, we let logical planner handle + * it, otherwise we recursively plan the relation. + */ + JoinRestrictionContext *joinRestrictionContext = + recursivePlanningContext->plannerRestrictionContext-> + joinRestrictionContext; + if (joinRestrictionContext == NULL || + !joinRestrictionContext->hasOuterJoin) + { + return; + } + + /* + * wrap the relation into subquery just since SubqueryColocated expects + * a query as input + */ + Query *subquery = WrapRteRelationIntoSubquery(rte, NIL); + if (!SubqueryColocated(subquery, colocatedJoinChecker)) + { + ereport(DEBUG1, (errmsg("recursively planning noncolocated relation"))); + PlannerRestrictionContext *restrictionContext = + GetPlannerRestrictionContext(recursivePlanningContext); + List *requiredAttributes = + RequiredAttrNumbersForRelation(rte, restrictionContext); + + ReplaceRTERelationWithRteSubquery(rte, requiredAttributes, + recursivePlanningContext); + } } - /* - * If the subquery is not colocated with the anchor subquery, - * recursively plan it. - */ - Query *subquery = rte->subquery; - if (!SubqueryColocated(subquery, colocatedJoinChecker)) - { - RecursivelyPlanSubquery(subquery, recursivePlanningContext); - } + return; } else { diff --git a/src/test/regress/expected/cross_join.out b/src/test/regress/expected/cross_join.out index 5887a9ae3..f589e73b5 100644 --- a/src/test/regress/expected/cross_join.out +++ b/src/test/regress/expected/cross_join.out @@ -162,11 +162,23 @@ SELECT count(*) FROM users_table u1 CROSS JOIN users_ref_test_table ref2 RIGHT J -- a reference tables CROSS JOINed with a distribted table, and later JOINED with distributed tables on reference table column -- so not safe to pushdown SELECT count(*) FROM users_table u1 CROSS JOIN users_ref_test_table ref2 LEFT JOIN users_table u2 ON (ref2.id = u2.user_id); -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns + count +--------------------------------------------------------------------- + 10201 +(1 row) + SELECT count(*) FROM users_table u1 CROSS JOIN users_ref_test_table ref2 FULL JOIN users_table u2 ON (ref2.id = u2.user_id); -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns + count +--------------------------------------------------------------------- + 10201 +(1 row) + SELECT count(*) FROM users_table u1 CROSS JOIN users_ref_test_table ref2 RIGHT JOIN users_table u2 ON (ref2.id = u2.user_id); -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns + count +--------------------------------------------------------------------- + 10201 +(1 row) + -- via repartitioning, Citus can handle this query as the result of "u1 CROSS JOIN ref2" -- can be repartitioned on ref2.id Set citus.enable_repartition_joins to on; diff --git a/src/test/regress/expected/multi_insert_select.out b/src/test/regress/expected/multi_insert_select.out index 0e2db7f93..43f02fffb 100644 --- a/src/test/regress/expected/multi_insert_select.out +++ b/src/test/regress/expected/multi_insert_select.out @@ -845,7 +845,6 @@ SET client_min_messages TO WARNING; raw_events_first.user_id FROM raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.value_1; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -- same as the above with INNER JOIN INSERT INTO agg_events (user_id) SELECT @@ -867,7 +866,6 @@ DETAIL: Cartesian products are currently unsupported raw_events_first.user_id FROM raw_events_first LEFT JOIN raw_events_second ON raw_events_first.value_1 = raw_events_second.value_1; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -- same as the above with INNER JOIN -- we support this with route to coordinator SELECT coordinator_plan($Q$ @@ -903,7 +901,6 @@ FROM raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.value_1 WHERE raw_events_first.user_id = 10; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -- same as the above with INNER JOIN -- we support this with route to coordinator SELECT coordinator_plan($Q$ diff --git a/src/test/regress/expected/multi_insert_select_0.out b/src/test/regress/expected/multi_insert_select_0.out index 42eb72062..5e0f881c3 100644 --- a/src/test/regress/expected/multi_insert_select_0.out +++ b/src/test/regress/expected/multi_insert_select_0.out @@ -845,7 +845,6 @@ SET client_min_messages TO WARNING; raw_events_first.user_id FROM raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.value_1; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -- same as the above with INNER JOIN INSERT INTO agg_events (user_id) SELECT @@ -867,7 +866,6 @@ DETAIL: Cartesian products are currently unsupported raw_events_first.user_id FROM raw_events_first LEFT JOIN raw_events_second ON raw_events_first.value_1 = raw_events_second.value_1; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -- same as the above with INNER JOIN -- we support this with route to coordinator SELECT coordinator_plan($Q$ @@ -903,7 +901,6 @@ FROM raw_events_first LEFT JOIN raw_events_second ON raw_events_first.user_id = raw_events_second.value_1 WHERE raw_events_first.user_id = 10; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns -- same as the above with INNER JOIN -- we support this with route to coordinator SELECT coordinator_plan($Q$ diff --git a/src/test/regress/expected/multi_insert_select_non_pushable_queries.out b/src/test/regress/expected/multi_insert_select_non_pushable_queries.out index fc3f62385..488ceff1e 100644 --- a/src/test/regress/expected/multi_insert_select_non_pushable_queries.out +++ b/src/test/regress/expected/multi_insert_select_non_pushable_queries.out @@ -64,7 +64,6 @@ FROM ( ) t2 ON (t1.user_id = t2.user_id) GROUP BY t1.user_id, hasdone_event ) t GROUP BY user_id, hasdone_event; -ERROR: complex joins are only supported when all distributed tables are joined on their distribution columns with equal operator -- not pushable since the JOIN is not an equi join right part of the UNION -- is not joined on the partition key INSERT INTO agg_results_third (user_id, value_1_agg, value_2_agg ) @@ -104,8 +103,6 @@ FROM ( ) t2 ON (t1.user_id = t2.user_id) GROUP BY t1.user_id, hasdone_event ) t GROUP BY user_id, hasdone_event; -ERROR: the query contains a join that requires repartitioning -HINT: Set citus.enable_repartition_joins to on to enable repartitioning -- the LEFT JOIN conditon is not on the partition column (i.e., is it part_key divided by 2) -- but, we can plan the query thanks to recursive planning SET client_min_messages TO DEBUG1; @@ -234,7 +231,6 @@ GROUP BY count_pay, user_id ORDER BY count_pay; -ERROR: complex joins are only supported when all distributed tables are joined on their distribution columns with equal operator -- not pushable since the JOIN condition is not equi JOIN -- (subquery_1 JOIN subquery_2) -- but, we can plan the query thanks to recursive planning diff --git a/src/test/regress/expected/multi_outer_join.out b/src/test/regress/expected/multi_outer_join.out index 17b13773d..5e56c143b 100644 --- a/src/test/regress/expected/multi_outer_join.out +++ b/src/test/regress/expected/multi_outer_join.out @@ -276,7 +276,12 @@ SELECT count(*) FROM multi_outer_join_left a LEFT JOIN multi_outer_join_right b ON (l_nationkey = r_nationkey); -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +LOG: join order: [ "multi_outer_join_right" ] + count +--------------------------------------------------------------------- + 32 +(1 row) + -- Anti-join should return customers for which there is no row in the right table SELECT min(l_custkey), max(l_custkey) diff --git a/src/test/regress/expected/multi_outer_join_reference.out b/src/test/regress/expected/multi_outer_join_reference.out index aca91bda7..5c05820eb 100644 --- a/src/test/regress/expected/multi_outer_join_reference.out +++ b/src/test/regress/expected/multi_outer_join_reference.out @@ -274,7 +274,12 @@ SELECT count(*) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_hash b ON (l_nationkey = r_nationkey); -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +LOG: join order: [ "multi_outer_join_right_hash" ] + count +--------------------------------------------------------------------- + 52 +(1 row) + -- Anti-join should return customers for which there is no row in the right table SELECT min(l_custkey), max(l_custkey) @@ -352,7 +357,37 @@ FROM LEFT JOIN multi_outer_join_right_reference r1 ON (l1.l_custkey = r1.r_custkey) LEFT JOIN multi_outer_join_right_reference r2 ON (l1.l_custkey = r2.r_custkey) RIGHT JOIN multi_outer_join_left_hash l2 ON (r2.r_custkey = l2.l_custkey); -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +LOG: join order: [ "multi_outer_join_left_hash" ] +LOG: join order: [ "multi_outer_join_left_hash" ] + l_custkey | l_name | l_address | l_nationkey | l_phone | l_acctbal | l_mktsegment | l_comment | r_custkey | r_name | r_address | r_nationkey | r_phone | r_acctbal | r_mktsegment | r_comment | r_custkey | r_name | r_address | r_nationkey | r_phone | r_acctbal | r_mktsegment | r_comment | l_custkey | l_name | l_address | l_nationkey | l_phone | l_acctbal | l_mktsegment | l_comment +--------------------------------------------------------------------- + 11 | Customer#000000011 | PkWS 3HlXqwTuzrKg633BEi | 23 | 33-464-151-3439 | -272.60 | BUILDING | ckages. requests sleep slyly. quickly even pinto beans promise above the slyly regular pinto beans. | 11 | Customer#000000011 | PkWS 3HlXqwTuzrKg633BEi | 23 | 33-464-151-3439 | -272.60 | BUILDING | ckages. requests sleep slyly. quickly even pinto beans promise above the slyly regular pinto beans. | 11 | Customer#000000011 | PkWS 3HlXqwTuzrKg633BEi | 23 | 33-464-151-3439 | -272.60 | BUILDING | ckages. requests sleep slyly. quickly even pinto beans promise above the slyly regular pinto beans. | 11 | Customer#000000011 | PkWS 3HlXqwTuzrKg633BEi | 23 | 33-464-151-3439 | -272.60 | BUILDING | ckages. requests sleep slyly. quickly even pinto beans promise above the slyly regular pinto beans. + 12 | Customer#000000012 | 9PWKuhzT4Zr1Q | 13 | 23-791-276-1263 | 3396.49 | HOUSEHOLD | to the carefully final braids. blithely regular requests nag. ironic theodolites boost quickly along | 12 | Customer#000000012 | 9PWKuhzT4Zr1Q | 13 | 23-791-276-1263 | 3396.49 | HOUSEHOLD | to the carefully final braids. blithely regular requests nag. ironic theodolites boost quickly along | 12 | Customer#000000012 | 9PWKuhzT4Zr1Q | 13 | 23-791-276-1263 | 3396.49 | HOUSEHOLD | to the carefully final braids. blithely regular requests nag. ironic theodolites boost quickly along | 12 | Customer#000000012 | 9PWKuhzT4Zr1Q | 13 | 23-791-276-1263 | 3396.49 | HOUSEHOLD | to the carefully final braids. blithely regular requests nag. ironic theodolites boost quickly along + 13 | Customer#000000013 | nsXQu0oVjD7PM659uC3SRSp | 3 | 13-761-547-5974 | 3857.34 | BUILDING | ounts sleep carefully after the close frays. carefully bold notornis use ironic requests. blithely | 13 | Customer#000000013 | nsXQu0oVjD7PM659uC3SRSp | 3 | 13-761-547-5974 | 3857.34 | BUILDING | ounts sleep carefully after the close frays. carefully bold notornis use ironic requests. blithely | 13 | Customer#000000013 | nsXQu0oVjD7PM659uC3SRSp | 3 | 13-761-547-5974 | 3857.34 | BUILDING | ounts sleep carefully after the close frays. carefully bold notornis use ironic requests. blithely | 13 | Customer#000000013 | nsXQu0oVjD7PM659uC3SRSp | 3 | 13-761-547-5974 | 3857.34 | BUILDING | ounts sleep carefully after the close frays. carefully bold notornis use ironic requests. blithely + 14 | Customer#000000014 | KXkletMlL2JQEA | 1 | 11-845-129-3851 | 5266.30 | FURNITURE | , ironic packages across the unus | 14 | Customer#000000014 | KXkletMlL2JQEA | 1 | 11-845-129-3851 | 5266.30 | FURNITURE | , ironic packages across the unus | 14 | Customer#000000014 | KXkletMlL2JQEA | 1 | 11-845-129-3851 | 5266.30 | FURNITURE | , ironic packages across the unus | 14 | Customer#000000014 | KXkletMlL2JQEA | 1 | 11-845-129-3851 | 5266.30 | FURNITURE | , ironic packages across the unus + 15 | Customer#000000015 | YtWggXoOLdwdo7b0y,BZaGUQMLJMX1Y,EC,6Dn | 23 | 33-687-542-7601 | 2788.52 | HOUSEHOLD | platelets. regular deposits detect asymptotes. blithely unusual packages nag slyly at the fluf | 15 | Customer#000000015 | YtWggXoOLdwdo7b0y,BZaGUQMLJMX1Y,EC,6Dn | 23 | 33-687-542-7601 | 2788.52 | HOUSEHOLD | platelets. regular deposits detect asymptotes. blithely unusual packages nag slyly at the fluf | 15 | Customer#000000015 | YtWggXoOLdwdo7b0y,BZaGUQMLJMX1Y,EC,6Dn | 23 | 33-687-542-7601 | 2788.52 | HOUSEHOLD | platelets. regular deposits detect asymptotes. blithely unusual packages nag slyly at the fluf | 15 | Customer#000000015 | YtWggXoOLdwdo7b0y,BZaGUQMLJMX1Y,EC,6Dn | 23 | 33-687-542-7601 | 2788.52 | HOUSEHOLD | platelets. regular deposits detect asymptotes. blithely unusual packages nag slyly at the fluf + 21 | Customer#000000021 | XYmVpr9yAHDEn | 8 | 18-902-614-8344 | 1428.25 | MACHINERY | quickly final accounts integrate blithely furiously u | 21 | Customer#000000021 | XYmVpr9yAHDEn | 8 | 18-902-614-8344 | 1428.25 | MACHINERY | quickly final accounts integrate blithely furiously u | 21 | Customer#000000021 | XYmVpr9yAHDEn | 8 | 18-902-614-8344 | 1428.25 | MACHINERY | quickly final accounts integrate blithely furiously u | 21 | Customer#000000021 | XYmVpr9yAHDEn | 8 | 18-902-614-8344 | 1428.25 | MACHINERY | quickly final accounts integrate blithely furiously u + 22 | Customer#000000022 | QI6p41,FNs5k7RZoCCVPUTkUdYpB | 3 | 13-806-545-9701 | 591.98 | MACHINERY | s nod furiously above the furiously ironic ideas. | 22 | Customer#000000022 | QI6p41,FNs5k7RZoCCVPUTkUdYpB | 3 | 13-806-545-9701 | 591.98 | MACHINERY | s nod furiously above the furiously ironic ideas. | 22 | Customer#000000022 | QI6p41,FNs5k7RZoCCVPUTkUdYpB | 3 | 13-806-545-9701 | 591.98 | MACHINERY | s nod furiously above the furiously ironic ideas. | 22 | Customer#000000022 | QI6p41,FNs5k7RZoCCVPUTkUdYpB | 3 | 13-806-545-9701 | 591.98 | MACHINERY | s nod furiously above the furiously ironic ideas. + 23 | Customer#000000023 | OdY W13N7Be3OC5MpgfmcYss0Wn6TKT | 3 | 13-312-472-8245 | 3332.02 | HOUSEHOLD | deposits. special deposits cajole slyly. fluffily special deposits about the furiously | 23 | Customer#000000023 | OdY W13N7Be3OC5MpgfmcYss0Wn6TKT | 3 | 13-312-472-8245 | 3332.02 | HOUSEHOLD | deposits. special deposits cajole slyly. fluffily special deposits about the furiously | 23 | Customer#000000023 | OdY W13N7Be3OC5MpgfmcYss0Wn6TKT | 3 | 13-312-472-8245 | 3332.02 | HOUSEHOLD | deposits. special deposits cajole slyly. fluffily special deposits about the furiously | 23 | Customer#000000023 | OdY W13N7Be3OC5MpgfmcYss0Wn6TKT | 3 | 13-312-472-8245 | 3332.02 | HOUSEHOLD | deposits. special deposits cajole slyly. fluffily special deposits about the furiously + 24 | Customer#000000024 | HXAFgIAyjxtdqwimt13Y3OZO 4xeLe7U8PqG | 13 | 23-127-851-8031 | 9255.67 | MACHINERY | into beans. fluffily final ideas haggle fluffily | 24 | Customer#000000024 | HXAFgIAyjxtdqwimt13Y3OZO 4xeLe7U8PqG | 13 | 23-127-851-8031 | 9255.67 | MACHINERY | into beans. fluffily final ideas haggle fluffily | 24 | Customer#000000024 | HXAFgIAyjxtdqwimt13Y3OZO 4xeLe7U8PqG | 13 | 23-127-851-8031 | 9255.67 | MACHINERY | into beans. fluffily final ideas haggle fluffily | 24 | Customer#000000024 | HXAFgIAyjxtdqwimt13Y3OZO 4xeLe7U8PqG | 13 | 23-127-851-8031 | 9255.67 | MACHINERY | into beans. fluffily final ideas haggle fluffily + 25 | Customer#000000025 | Hp8GyFQgGHFYSilH5tBfe | 12 | 22-603-468-3533 | 7133.70 | FURNITURE | y. accounts sleep ruthlessly according to the regular theodolites. unusual instructions sleep. ironic, final | 25 | Customer#000000025 | Hp8GyFQgGHFYSilH5tBfe | 12 | 22-603-468-3533 | 7133.70 | FURNITURE | y. accounts sleep ruthlessly according to the regular theodolites. unusual instructions sleep. ironic, final | 25 | Customer#000000025 | Hp8GyFQgGHFYSilH5tBfe | 12 | 22-603-468-3533 | 7133.70 | FURNITURE | y. accounts sleep ruthlessly according to the regular theodolites. unusual instructions sleep. ironic, final | 25 | Customer#000000025 | Hp8GyFQgGHFYSilH5tBfe | 12 | 22-603-468-3533 | 7133.70 | FURNITURE | y. accounts sleep ruthlessly according to the regular theodolites. unusual instructions sleep. ironic, final + 26 | Customer#000000026 | 8ljrc5ZeMl7UciP | 22 | 32-363-455-4837 | 5182.05 | AUTOMOBILE | c requests use furiously ironic requests. slyly ironic dependencies us | 26 | Customer#000000026 | 8ljrc5ZeMl7UciP | 22 | 32-363-455-4837 | 5182.05 | AUTOMOBILE | c requests use furiously ironic requests. slyly ironic dependencies us | 26 | Customer#000000026 | 8ljrc5ZeMl7UciP | 22 | 32-363-455-4837 | 5182.05 | AUTOMOBILE | c requests use furiously ironic requests. slyly ironic dependencies us | 26 | Customer#000000026 | 8ljrc5ZeMl7UciP | 22 | 32-363-455-4837 | 5182.05 | AUTOMOBILE | c requests use furiously ironic requests. slyly ironic dependencies us + 27 | Customer#000000027 | IS8GIyxpBrLpMT0u7 | 3 | 13-137-193-2709 | 5679.84 | BUILDING | about the carefully ironic pinto beans. accoun | 27 | Customer#000000027 | IS8GIyxpBrLpMT0u7 | 3 | 13-137-193-2709 | 5679.84 | BUILDING | about the carefully ironic pinto beans. accoun | 27 | Customer#000000027 | IS8GIyxpBrLpMT0u7 | 3 | 13-137-193-2709 | 5679.84 | BUILDING | about the carefully ironic pinto beans. accoun | 27 | Customer#000000027 | IS8GIyxpBrLpMT0u7 | 3 | 13-137-193-2709 | 5679.84 | BUILDING | about the carefully ironic pinto beans. accoun + 28 | Customer#000000028 | iVyg0daQ,Tha8x2WPWA9m2529m | 8 | 18-774-241-1462 | 1007.18 | FURNITURE | along the regular deposits. furiously final pac | 28 | Customer#000000028 | iVyg0daQ,Tha8x2WPWA9m2529m | 8 | 18-774-241-1462 | 1007.18 | FURNITURE | along the regular deposits. furiously final pac | 28 | Customer#000000028 | iVyg0daQ,Tha8x2WPWA9m2529m | 8 | 18-774-241-1462 | 1007.18 | FURNITURE | along the regular deposits. furiously final pac | 28 | Customer#000000028 | iVyg0daQ,Tha8x2WPWA9m2529m | 8 | 18-774-241-1462 | 1007.18 | FURNITURE | along the regular deposits. furiously final pac + 29 | Customer#000000029 | sJ5adtfyAkCK63df2,vF25zyQMVYE34uh | 0 | 10-773-203-7342 | 7618.27 | FURNITURE | its after the carefully final platelets x-ray against | 29 | Customer#000000029 | sJ5adtfyAkCK63df2,vF25zyQMVYE34uh | 0 | 10-773-203-7342 | 7618.27 | FURNITURE | its after the carefully final platelets x-ray against | 29 | Customer#000000029 | sJ5adtfyAkCK63df2,vF25zyQMVYE34uh | 0 | 10-773-203-7342 | 7618.27 | FURNITURE | its after the carefully final platelets x-ray against | 29 | Customer#000000029 | sJ5adtfyAkCK63df2,vF25zyQMVYE34uh | 0 | 10-773-203-7342 | 7618.27 | FURNITURE | its after the carefully final platelets x-ray against + 30 | Customer#000000030 | nJDsELGAavU63Jl0c5NKsKfL8rIJQQkQnYL2QJY | 1 | 11-764-165-5076 | 9321.01 | BUILDING | lithely final requests. furiously unusual account | 30 | Customer#000000030 | nJDsELGAavU63Jl0c5NKsKfL8rIJQQkQnYL2QJY | 1 | 11-764-165-5076 | 9321.01 | BUILDING | lithely final requests. furiously unusual account | 30 | Customer#000000030 | nJDsELGAavU63Jl0c5NKsKfL8rIJQQkQnYL2QJY | 1 | 11-764-165-5076 | 9321.01 | BUILDING | lithely final requests. furiously unusual account | 30 | Customer#000000030 | nJDsELGAavU63Jl0c5NKsKfL8rIJQQkQnYL2QJY | 1 | 11-764-165-5076 | 9321.01 | BUILDING | lithely final requests. furiously unusual account + | | | | | | | | | | | | | | | | | | | | | | | | 10 | Customer#000000010 | 6LrEaV6KR6PLVcgl2ArL Q3rqzLzcT1 v2 | 5 | 15-741-346-9870 | 2753.54 | HOUSEHOLD | es regular deposits haggle. fur + | | | | | | | | | | | | | | | | | | | | | | | | 2 | Customer#000000002 | XSTf4,NCwDVaWNe6tEgvwfmRchLXak | 13 | 23-768-687-3665 | 121.65 | AUTOMOBILE | l accounts. blithely ironic theodolites integrate boldly: caref + | | | | | | | | | | | | | | | | | | | | | | | | 5 | Customer#000000005 | KvpyuHCplrB84WgAiGV6sYpZq7Tj | 3 | 13-750-942-6364 | 794.47 | HOUSEHOLD | n accounts will have to unwind. foxes cajole accor + | | | | | | | | | | | | | | | | | | | | | | | | 8 | Customer#000000008 | I0B10bB0AymmC, 0PrRYBCP1yGJ8xcBPmWhl5 | 17 | 27-147-574-9335 | 6819.74 | BUILDING | among the slyly regular theodolites kindle blithely courts. carefully even theodolites haggle slyly along the ide + | | | | | | | | | | | | | | | | | | | | | | | | 6 | Customer#000000006 | sKZz0CsnMD7mp4Xd0YrBvx,LREYKUWAh yVn | 20 | 30-114-968-4951 | 7638.57 | AUTOMOBILE | tions. even deposits boost according to the slyly bold packages. final accounts cajole requests. furious + | | | | | | | | | | | | | | | | | | | | | | | | 4 | Customer#000000004 | XxVSJsLAGtn | 4 | 14-128-190-5944 | 2866.83 | MACHINERY | requests. final, regular ideas sleep final accou + | | | | | | | | | | | | | | | | | | | | | | | | 1 | Customer#000000001 | IVhzIApeRb ot,c,E | 15 | 25-989-741-2988 | 711.56 | BUILDING | to the even, regular platelets. regular, ironic epitaphs nag e + | | | | | | | | | | | | | | | | | | | | | | | | 3 | Customer#000000003 | MG9kdTD2WBHm | 1 | 11-719-748-3364 | 7498.12 | AUTOMOBILE | deposits eat slyly ironic, even instructions. express foxes detect slyly. blithely even accounts abov + | | | | | | | | | | | | | | | | | | | | | | | | 9 | Customer#000000009 | xKiAFTjUsCuxfeleNqefumTrjS | 8 | 18-338-906-3675 | 8324.07 | FURNITURE | r theodolites according to the requests wake thinly excuses: pending requests haggle furiousl + | | | | | | | | | | | | | | | | | | | | | | | | 7 | Customer#000000007 | TcGe5gaZNgVePxU5kRrvXBfkasDTea | 18 | 28-190-982-9759 | 9561.95 | AUTOMOBILE | ainst the ironic, express theodolites. express, even pinto beans among the exp +(25 rows) + -- add an anti-join, this should also error out SELECT * @@ -363,7 +398,22 @@ FROM RIGHT JOIN multi_outer_join_left_hash l2 ON (r2.r_custkey = l2.l_custkey) WHERE r1.r_custkey is NULL; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +LOG: join order: [ "multi_outer_join_left_hash" ] +LOG: join order: [ "multi_outer_join_left_hash" ] + l_custkey | l_name | l_address | l_nationkey | l_phone | l_acctbal | l_mktsegment | l_comment | r_custkey | r_name | r_address | r_nationkey | r_phone | r_acctbal | r_mktsegment | r_comment | r_custkey | r_name | r_address | r_nationkey | r_phone | r_acctbal | r_mktsegment | r_comment | l_custkey | l_name | l_address | l_nationkey | l_phone | l_acctbal | l_mktsegment | l_comment +--------------------------------------------------------------------- + | | | | | | | | | | | | | | | | | | | | | | | | 10 | Customer#000000010 | 6LrEaV6KR6PLVcgl2ArL Q3rqzLzcT1 v2 | 5 | 15-741-346-9870 | 2753.54 | HOUSEHOLD | es regular deposits haggle. fur + | | | | | | | | | | | | | | | | | | | | | | | | 2 | Customer#000000002 | XSTf4,NCwDVaWNe6tEgvwfmRchLXak | 13 | 23-768-687-3665 | 121.65 | AUTOMOBILE | l accounts. blithely ironic theodolites integrate boldly: caref + | | | | | | | | | | | | | | | | | | | | | | | | 5 | Customer#000000005 | KvpyuHCplrB84WgAiGV6sYpZq7Tj | 3 | 13-750-942-6364 | 794.47 | HOUSEHOLD | n accounts will have to unwind. foxes cajole accor + | | | | | | | | | | | | | | | | | | | | | | | | 8 | Customer#000000008 | I0B10bB0AymmC, 0PrRYBCP1yGJ8xcBPmWhl5 | 17 | 27-147-574-9335 | 6819.74 | BUILDING | among the slyly regular theodolites kindle blithely courts. carefully even theodolites haggle slyly along the ide + | | | | | | | | | | | | | | | | | | | | | | | | 6 | Customer#000000006 | sKZz0CsnMD7mp4Xd0YrBvx,LREYKUWAh yVn | 20 | 30-114-968-4951 | 7638.57 | AUTOMOBILE | tions. even deposits boost according to the slyly bold packages. final accounts cajole requests. furious + | | | | | | | | | | | | | | | | | | | | | | | | 4 | Customer#000000004 | XxVSJsLAGtn | 4 | 14-128-190-5944 | 2866.83 | MACHINERY | requests. final, regular ideas sleep final accou + | | | | | | | | | | | | | | | | | | | | | | | | 1 | Customer#000000001 | IVhzIApeRb ot,c,E | 15 | 25-989-741-2988 | 711.56 | BUILDING | to the even, regular platelets. regular, ironic epitaphs nag e + | | | | | | | | | | | | | | | | | | | | | | | | 3 | Customer#000000003 | MG9kdTD2WBHm | 1 | 11-719-748-3364 | 7498.12 | AUTOMOBILE | deposits eat slyly ironic, even instructions. express foxes detect slyly. blithely even accounts abov + | | | | | | | | | | | | | | | | | | | | | | | | 9 | Customer#000000009 | xKiAFTjUsCuxfeleNqefumTrjS | 8 | 18-338-906-3675 | 8324.07 | FURNITURE | r theodolites according to the requests wake thinly excuses: pending requests haggle furiousl + | | | | | | | | | | | | | | | | | | | | | | | | 7 | Customer#000000007 | TcGe5gaZNgVePxU5kRrvXBfkasDTea | 18 | 28-190-982-9759 | 9561.95 | AUTOMOBILE | ainst the ironic, express theodolites. express, even pinto beans among the exp +(10 rows) + -- Three way join 2-1-1 (broadcast + broadcast join) should work SELECT l_custkey, r_custkey, t_custkey diff --git a/src/test/regress/expected/multi_subquery.out b/src/test/regress/expected/multi_subquery.out index f4c4ccc21..0b87baa1b 100644 --- a/src/test/regress/expected/multi_subquery.out +++ b/src/test/regress/expected/multi_subquery.out @@ -425,7 +425,15 @@ FROM events_table t1 LEFT JOIN users_table t2 ON t1.user_id > t2.user_id ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC LIMIT 5; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns + user_id | value_1 | value_2 | value_3 +--------------------------------------------------------------------- + 6 | 5 | 5 | 3 + 5 | 5 | 5 | 3 + 4 | 5 | 5 | 3 + 3 | 5 | 4 | 3 + 2 | 5 | 4 | 3 +(5 rows) + -- outer joins on reference tables with expressions should work SELECT DISTINCT ON (t1.user_id) t1.user_id, t2.value_1, t2.value_2, t2.value_3 FROM events_table t1 @@ -466,7 +474,15 @@ SELECT DISTINCT ON (t1.user_id) t1.user_id, t2.value_1, t2.value_2, t2.value_3 LEFT JOIN users_reference_table t2 ON t1.user_id = trunc(t2.user_id) ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC LIMIT 5; -ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns + user_id | value_1 | value_2 | value_3 +--------------------------------------------------------------------- + 6 | 5 | 2 | 0 + 5 | 5 | 5 | 1 + 4 | 5 | 4 | 1 + 3 | 5 | 5 | 3 + 2 | 4 | 4 | 5 +(5 rows) + -- outer joins as subqueries should work -- https://github.com/citusdata/citus/issues/2739 SELECT user_id, value_1, event_type diff --git a/src/test/regress/expected/non_colocated_outer_joins.out b/src/test/regress/expected/non_colocated_outer_joins.out new file mode 100644 index 000000000..c5bd6b7c3 --- /dev/null +++ b/src/test/regress/expected/non_colocated_outer_joins.out @@ -0,0 +1,1852 @@ +CREATE SCHEMA non_colocated_outer_joins; +SET search_path TO non_colocated_outer_joins; +CREATE TABLE test_hash1(col1 INT, col2 INT); +SELECT create_distributed_table('test_hash1', 'col1'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO test_hash1 SELECT i, i FROM generate_series(1,10) i; +CREATE TABLE test_hash2(col1 INT, col2 INT); +SELECT create_distributed_table('test_hash2', 'col2'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO test_hash2 SELECT i, i FROM generate_series(6,15) i; +CREATE TABLE test_hash3(col1 INT, col2 INT); +SELECT create_distributed_table('test_hash3', 'col1'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO test_hash3 SELECT i, i FROM generate_series(11,20) i; +SET citus.enable_repartition_joins TO ON; +SET citus.log_multi_join_order TO ON; +SET client_min_messages TO DEBUG1; +-- join order planner can handle left outer join between tables with simple join clause +-- outer table restricted on partition column whereas inner one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_hash1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +-- inner table restricted on partition column whereas outer one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col2 = t2.col2) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_hash1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col2))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +-- both tables are not restricted on partition column +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col2 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_hash1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +-- join order planner can handle right outer join between tables with simple join clause +-- outer table restricted on partition column whereas inner one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +-- inner table restricted on partition column whereas outer one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col2) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col2))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +-- both tables are not restricted on partition column +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +-- join order planner can handle full outer join between tables with simple join clause +-- left outer table restricted on partition column whereas right outer one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +-- right outer table restricted on partition column whereas left outer one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col2) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col2))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +-- both tables are not restricted on partition column +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +-- join order planner can handle queries with multi joins consisting of outer joins with simple join clause +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t1.col1) ORDER BY 1,2,3,4,5,6; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col2) ORDER BY 1,2,3,4,5,6; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col2) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col2))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col2 OPERATOR(pg_catalog.=) t2.col2))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col1) ORDER BY 1,2,3,4,5,6; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col2 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t1.col1) ORDER BY 1,2,3,4,5,6; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM ((non_colocated_outer_joins.test_hash2 t2 LEFT JOIN (SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col2) ORDER BY 1,2,3,4,5,6; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col2) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM ((non_colocated_outer_joins.test_hash2 t2 LEFT JOIN (SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col2))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col2 OPERATOR(pg_catalog.=) t2.col2))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col1) ORDER BY 1,2,3,4,5,6; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM ((non_colocated_outer_joins.test_hash2 t2 LEFT JOIN (SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col2 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t1.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN non_colocated_outer_joins.test_hash3 t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t1.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- +(0 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col2) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col2))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col2 OPERATOR(pg_catalog.=) t1.col2))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- +(0 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col2) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col2))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col2 OPERATOR(pg_catalog.=) t2.col2))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col2 OPERATOR(pg_catalog.=) t1.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- +(0 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col2 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col2 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +-- join order planner handles left outer join between tables with nonsimple join or where clause +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) WHERE (t1.col1 IS NULL or t2.col2 IS NULL) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_hash1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) WHERE ((t1.col1 IS NULL) OR (t2.col2 IS NULL)) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | +(5 rows) + +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1 and t1.col1 < 0) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_hash1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON (((t1.col1 OPERATOR(pg_catalog.=) t2.col1) AND (t1.col1 OPERATOR(pg_catalog.<) 0)))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | | + 7 | 7 | | + 8 | 8 | | + 9 | 9 | | + 10 | 10 | | +(10 rows) + +-- join order planner supports repartition join between append distributed tables +CREATE TABLE test_append1 (col1 INT, col2 INT); +SELECT create_distributed_table('test_append1', 'col1', 'append'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT master_create_empty_shard('test_append1') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 1, shardmaxvalue = 5 WHERE shardid = :new_shard_id; +SELECT master_create_empty_shard('test_append1') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 6, shardmaxvalue = 10 WHERE shardid = :new_shard_id; +INSERT INTO test_append1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10); +CREATE TABLE test_append2 (col1 INT, col2 INT); +SELECT create_distributed_table('test_append2', 'col2', 'append'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT master_create_empty_shard('test_append2') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 6, shardmaxvalue = 10 WHERE shardid = :new_shard_id; +SELECT master_create_empty_shard('test_append2') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 11, shardmaxvalue = 15 WHERE shardid = :new_shard_id; +INSERT INTO test_append2 VALUES (6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12),(13,13),(14,14),(15,15); +CREATE TABLE test_append3(col1 INT, col2 INT); +SELECT create_distributed_table('test_append3', 'col1', 'append'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT master_create_empty_shard('test_append3') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 11, shardmaxvalue = 15 WHERE shardid = :new_shard_id; +SELECT master_create_empty_shard('test_append3') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 16, shardmaxvalue = 20 WHERE shardid = :new_shard_id; +INSERT INTO test_append3 VALUES (11,11),(12,12),(13,13),(14,14),(15,15),(16,16),(17,17),(18,18),(19,19),(20,20); +-- join order planner supports repartition join between append-append distributed tables +SELECT t1.*, t2.* FROM test_append1 t1 LEFT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_append1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +SELECT t1.*, t2.* FROM test_append1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +SELECT t1.*, t2.* FROM test_append1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +SELECT t1.*, t2.*, t3.* FROM test_append1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_append3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append3" "t3" to a subquery +LOG: join order: [ "test_append3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append3 t3 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_append2 t2 LEFT JOIN test_append1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_append3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append3" "t3" to a subquery +LOG: join order: [ "test_append3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append3 t3 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM ((non_colocated_outer_joins.test_append2 t2 LEFT JOIN (SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_append1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_append3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append3" "t3" to a subquery +LOG: join order: [ "test_append3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +-- join order planner supports repartition join between append-hash distributed tables +SELECT t1.*, t2.* FROM test_append1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_append1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_hash1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +SELECT t1.*, t2.* FROM test_append1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +SELECT t1.*, t2.* FROM test_append1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_append2 t2 LEFT JOIN test_hash1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM ((non_colocated_outer_joins.test_append2 t2 LEFT JOIN (SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +-- join order planner supports repartition join between range distributed tables +CREATE TABLE test_range1(col1 INT, col2 INT); +SELECT create_distributed_table('test_range1', 'col1', 'range'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CALL public.create_range_partitioned_shards('test_range1', + '{0,6,11,16}', + '{5,10,15,20}'); +INSERT INTO test_range1 SELECT i, i FROM generate_series(1,10) i; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: Collecting INSERT ... SELECT results on coordinator +CREATE TABLE test_range2(col1 INT, col2 INT); +SELECT create_distributed_table('test_range2', 'col2', 'range'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CALL public.create_range_partitioned_shards('test_range2', + '{0,6,11,16}', + '{5,10,15,20}'); +INSERT INTO test_range2 SELECT i, i FROM generate_series(6,15) i; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: Collecting INSERT ... SELECT results on coordinator +CREATE TABLE test_range3(col1 INT, col2 INT); +SELECT create_distributed_table('test_range3', 'col1', 'range'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CALL public.create_range_partitioned_shards('test_range3', + '{0,6,11,16}', + '{5,10,15,20}'); +INSERT INTO test_range3 SELECT i, i FROM generate_series(11,20) i; +DEBUG: distributed INSERT ... SELECT can only select from distributed tables +DEBUG: Collecting INSERT ... SELECT results on coordinator +-- join order planner supports repartition join between range-range distributed tables +SELECT t1.*, t2.* FROM test_range1 t1 LEFT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_range1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +SELECT t1.*, t2.* FROM test_range1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_range1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_range1" "t1" to a subquery +LOG: join order: [ "test_range1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +SELECT t1.*, t2.* FROM test_range1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_range1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_range1" "t1" to a subquery +LOG: join order: [ "test_range1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +SELECT t1.*, t2.*, t3.* FROM test_range1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_range3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range3" "t3" to a subquery +LOG: join order: [ "test_range3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range3 t3 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_range1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_range1" "t1" to a subquery +LOG: join order: [ "test_range1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_range2 t2 LEFT JOIN test_range1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_range3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range1" "t1" to a subquery +LOG: join order: [ "test_range1" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range1 t1 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range3" "t3" to a subquery +LOG: join order: [ "test_range3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range3 t3 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM ((non_colocated_outer_joins.test_range2 t2 LEFT JOIN (SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_range1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_range3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range3" "t3" to a subquery +LOG: join order: [ "test_range3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_range1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_range1" "t1" to a subquery +LOG: join order: [ "test_range1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +-- join order planner supports repartition join between range-hash distributed tables +SELECT t1.*, t2.* FROM test_range1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_range1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_hash1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +SELECT t1.*, t2.* FROM test_range1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_range1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_range1" "t1" to a subquery +LOG: join order: [ "test_range1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +SELECT t1.*, t2.* FROM test_range1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_range1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_range1" "t1" to a subquery +LOG: join order: [ "test_range1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_range2 t2 LEFT JOIN test_hash1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM ((non_colocated_outer_joins.test_range2 t2 LEFT JOIN (SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_hash1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_hash1" "t1" to a subquery +LOG: join order: [ "test_hash1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +-- join order planner supports repartition join between range-append distributed tables +SELECT t1.*, t2.* FROM test_range1 t1 LEFT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_range1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +SELECT t1.*, t2.* FROM test_append1 t1 LEFT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_append1 t1 LEFT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 +(10 rows) + +SELECT t1.*, t2.* FROM test_range1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_range1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_range1" "t1" to a subquery +LOG: join order: [ "test_range1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +SELECT t1.*, t2.* FROM test_append1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(10 rows) + +SELECT t1.*, t2.* FROM test_range1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append2" "t2" to a subquery +LOG: join order: [ "test_append2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_range1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_range1" "t1" to a subquery +LOG: join order: [ "test_range1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +SELECT t1.*, t2.* FROM test_append1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM ((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | 6 | 6 + 7 | 7 | 7 | 7 + 8 | 8 | 8 | 8 + 9 | 9 | 9 | 9 + 10 | 10 | 10 | 10 + | | 11 | 11 + | | 12 | 12 + | | 13 | 13 + | | 14 | 14 + | | 15 | 15 +(15 rows) + +SELECT t1.*, t2.*, t3.* FROM test_append1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the right join since the outer side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 RIGHT JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_range2 t2 LEFT JOIN test_append1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM ((non_colocated_outer_joins.test_range2 t2 LEFT JOIN (SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +SELECT t1.*, t2.*, t3.* FROM test_append1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_range2" "t2" to a subquery +LOG: join order: [ "test_range2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_range2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: recursively planning left side of the full join since the other side is a recurring rel +DEBUG: recursively planning distributed relation "test_append1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: Wrapping relation "test_append1" "t1" to a subquery +LOG: join order: [ "test_append1" ] +DEBUG: generating subplan XXX_3 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_append1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 FROM (((SELECT t1_1.col1, t1_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t1_1) t1 FULL JOIN (SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) JOIN (SELECT t3_1.col1, t3_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t3_1) t3 ON ((t3.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + | | 11 | 11 | 11 | 11 + | | 12 | 12 | 12 | 12 + | | 13 | 13 | 13 | 13 + | | 14 | 14 | 14 | 14 + | | 15 | 15 | 15 | 15 +(5 rows) + +-- join order planner cannot handle semi joins +SELECT t1.* FROM test_hash1 t1 WHERE EXISTS (SELECT * FROM test_hash2 t2 WHERE t1.col1 = t2.col1) ORDER BY 1,2; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t1.* FROM test_hash1 t1 WHERE EXISTS (SELECT * FROM test_hash2 t2 WHERE t1.col2 = t2.col2) ORDER BY 1,2; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t2.* FROM test_hash2 t2 WHERE EXISTS (SELECT * FROM test_hash1 t1 WHERE t1.col1 = t2.col1) ORDER BY 1,2; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t2.* FROM test_hash2 t2 WHERE EXISTS (SELECT * FROM test_hash1 t1 WHERE t1.col2 = t2.col2) ORDER BY 1,2; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +-- join order planner cannot handle anti joins +SELECT t1.* FROM test_hash1 t1 WHERE NOT EXISTS (SELECT * FROM test_hash2 t2 WHERE t1.col1 = t2.col1) ORDER BY 1,2; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t1.* FROM test_hash1 t1 WHERE NOT EXISTS (SELECT * FROM test_hash2 t2 WHERE t1.col2 = t2.col2) ORDER BY 1,2; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t2.* FROM test_hash2 t2 WHERE NOT EXISTS (SELECT * FROM test_hash1 t1 WHERE t1.col1 = t2.col1) ORDER BY 1,2; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +SELECT t2.* FROM test_hash2 t2 WHERE NOT EXISTS (SELECT * FROM test_hash1 t1 WHERE t1.col2 = t2.col2) ORDER BY 1,2; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +-- join order planner cannot handle lateral outer joins +SELECT t1.*, tt2.* FROM test_hash1 t1 LEFT JOIN LATERAL (SELECT * FROM test_hash2 t2 WHERE t1.col1 = t2.col1) tt2 ON (t1.col1 = tt2.col1) ORDER BY 1,2,3,4; +ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns +-- join order planner cannot handle cartesian joins +SELECT tt1.*, t3.* FROM (SELECT t1.* FROM test_hash1 t1, test_hash2 t2) tt1 LEFT JOIN test_hash3 t3 ON (tt1.col1 = t3.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT NULL::integer AS "dummy-1" FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT tt1.col1, tt1.col2, t3.col1, t3.col2 FROM ((SELECT t1.col1, t1.col2 FROM non_colocated_outer_joins.test_hash1 t1, (SELECT NULL::integer AS col1, NULL::integer AS col2 FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) t2_1) t2) tt1 LEFT JOIN non_colocated_outer_joins.test_hash3 t3 ON ((tt1.col1 OPERATOR(pg_catalog.=) t3.col1))) ORDER BY tt1.col1, tt1.col2, t3.col1, t3.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 1 | 1 | | + 1 | 1 | | + 1 | 1 | | + 1 | 1 | | + 1 | 1 | | + 1 | 1 | | + 1 | 1 | | + 1 | 1 | | + 1 | 1 | | + 2 | 2 | | + 2 | 2 | | + 2 | 2 | | + 2 | 2 | | + 2 | 2 | | + 2 | 2 | | + 2 | 2 | | + 2 | 2 | | + 2 | 2 | | + 2 | 2 | | + 3 | 3 | | + 3 | 3 | | + 3 | 3 | | + 3 | 3 | | + 3 | 3 | | + 3 | 3 | | + 3 | 3 | | + 3 | 3 | | + 3 | 3 | | + 3 | 3 | | + 4 | 4 | | + 4 | 4 | | + 4 | 4 | | + 4 | 4 | | + 4 | 4 | | + 4 | 4 | | + 4 | 4 | | + 4 | 4 | | + 4 | 4 | | + 4 | 4 | | + 5 | 5 | | + 5 | 5 | | + 5 | 5 | | + 5 | 5 | | + 5 | 5 | | + 5 | 5 | | + 5 | 5 | | + 5 | 5 | | + 5 | 5 | | + 5 | 5 | | + 6 | 6 | | + 6 | 6 | | + 6 | 6 | | + 6 | 6 | | + 6 | 6 | | + 6 | 6 | | + 6 | 6 | | + 6 | 6 | | + 6 | 6 | | + 6 | 6 | | + 7 | 7 | | + 7 | 7 | | + 7 | 7 | | + 7 | 7 | | + 7 | 7 | | + 7 | 7 | | + 7 | 7 | | + 7 | 7 | | + 7 | 7 | | + 7 | 7 | | + 8 | 8 | | + 8 | 8 | | + 8 | 8 | | + 8 | 8 | | + 8 | 8 | | + 8 | 8 | | + 8 | 8 | | + 8 | 8 | | + 8 | 8 | | + 8 | 8 | | + 9 | 9 | | + 9 | 9 | | + 9 | 9 | | + 9 | 9 | | + 9 | 9 | | + 9 | 9 | | + 9 | 9 | | + 9 | 9 | | + 9 | 9 | | + 9 | 9 | | + 10 | 10 | | + 10 | 10 | | + 10 | 10 | | + 10 | 10 | | + 10 | 10 | | + 10 | 10 | | + 10 | 10 | | + 10 | 10 | | + 10 | 10 | | + 10 | 10 | | +(100 rows) + +-- join order planner cannot handle right recursive joins +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN ( test_hash2 t2 JOIN test_hash3 t3 ON t2.col2 = t3.col1) ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash2" "t2" to a subquery +LOG: join order: [ "test_hash2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT col1, col2 FROM non_colocated_outer_joins.test_hash2 t2 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "test_hash3" "t3" to a subquery +LOG: join order: [ "test_hash3" ] +DEBUG: generating subplan XXX_2 for subquery SELECT col1 FROM non_colocated_outer_joins.test_hash3 t3 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.col1, t1.col2, t2.col1, t2.col2 FROM (non_colocated_outer_joins.test_hash1 t1 LEFT JOIN ((SELECT t2_1.col1, t2_1.col2 FROM (SELECT intermediate_result.col1, intermediate_result.col2 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer, col2 integer)) t2_1) t2 JOIN (SELECT t3_1.col1, NULL::integer AS col2 FROM (SELECT intermediate_result.col1 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(col1 integer)) t3_1) t3 ON ((t2.col2 OPERATOR(pg_catalog.=) t3.col1))) ON ((t1.col1 OPERATOR(pg_catalog.=) t2.col1))) ORDER BY t1.col1, t1.col2, t2.col1, t2.col2 + col1 | col2 | col1 | col2 +--------------------------------------------------------------------- + 1 | 1 | | + 2 | 2 | | + 3 | 3 | | + 4 | 4 | | + 5 | 5 | | + 6 | 6 | | + 7 | 7 | | + 8 | 8 | | + 9 | 9 | | + 10 | 10 | | +(10 rows) + +-- sometimes join filters are pushed down and applied before join by PG +CREATE TABLE dist1 (x INT, y INT); +CREATE TABLE dist2 (x INT, y INT); +SELECT create_distributed_table('dist1','x'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_table('dist2','x'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO dist1 VALUES (1,2); +INSERT INTO dist1 VALUES (3,4); +INSERT INTO dist2 VALUES (1,2); +INSERT INTO dist2 VALUES (5,6); +-- single join condition +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x) ORDER BY 1,2,3,4; + x | y | x | y +--------------------------------------------------------------------- + 1 | 2 | 1 | 2 + 3 | 4 | | +(2 rows) + +-- single join condition and dist2.x >2 will be pushed down as it is on inner part of the join. e.g. filter out dist2.x <= 2 beforehand +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x AND dist2.x >2) ORDER BY 1,2,3,4; + x | y | x | y +--------------------------------------------------------------------- + 1 | 2 | | + 3 | 4 | | +(2 rows) + +-- single join condition and dist2.x >2 is regular filter and applied after join +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x) WHERE dist2.x >2 ORDER BY 1,2,3,4; + x | y | x | y +--------------------------------------------------------------------- +(0 rows) + +-- single join condition and dist1.x >2 will not be pushed down as it is on outer part of the join +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x AND dist1.x >2) ORDER BY 1,2,3,4; + x | y | x | y +--------------------------------------------------------------------- + 1 | 2 | | + 3 | 4 | | +(2 rows) + +-- single join condition and dist1.x >2 is regular filter and applied after join +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x) WHERE dist1.x >2 ORDER BY 1,2,3,4; + x | y | x | y +--------------------------------------------------------------------- + 3 | 4 | | +(1 row) + +--- constant false filter as join filter for left join. +-- inner table will be converted to empty result. Constant filter will be applied before join but will not be pushdowned. +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.y = dist2.y AND false) ORDER BY 1,2,3,4; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "dist2" to a subquery +LOG: join order: [ "dist2" ] +DEBUG: generating subplan XXX_1 for subquery SELECT x, y FROM non_colocated_outer_joins.dist2 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT dist1.x, dist1.y, dist2.x, dist2.y FROM (non_colocated_outer_joins.dist1 LEFT JOIN (SELECT dist2_1.x, dist2_1.y FROM (SELECT intermediate_result.x, intermediate_result.y FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(x integer, y integer)) dist2_1) dist2 ON (((dist1.y OPERATOR(pg_catalog.=) dist2.y) AND false))) ORDER BY dist1.x, dist1.y, dist2.x, dist2.y + x | y | x | y +--------------------------------------------------------------------- + 1 | 2 | | + 3 | 4 | | +(2 rows) + +--- constant false filter as base filter for left join. +-- both tables will be converted to empty result .e.g RTE_RESULT +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.y = dist2.y) WHERE false ORDER BY 1,2,3,4; + x | y | x | y +--------------------------------------------------------------------- +(0 rows) + +--- constant false filter as join filter for inner join. +-- both tables will be converted to empty result .e.g RTE_RESULT +SELECT * FROM dist1 INNER JOIN dist2 ON (dist1.y = dist2.y AND false) ORDER BY 1,2,3,4; + x | y | x | y +--------------------------------------------------------------------- +(0 rows) + +--- constant false filter as base filter for inner join. +-- both tables will be converted to empty result .e.g RTE_RESULT +SELECT * FROM dist1 INNER JOIN dist2 ON (dist1.y = dist2.y) WHERE false ORDER BY 1,2,3,4; + x | y | x | y +--------------------------------------------------------------------- +(0 rows) + +DROP SCHEMA non_colocated_outer_joins CASCADE; +DEBUG: switching to sequential query execution mode +DETAIL: A command for a distributed schema is run. To make sure subsequent commands see the schema correctly we need to make sure to use only one connection for all future commands +NOTICE: drop cascades to 11 other objects +DETAIL: drop cascades to table test_hash1 +drop cascades to table test_hash2 +drop cascades to table test_hash3 +drop cascades to table test_append1 +drop cascades to table test_append2 +drop cascades to table test_append3 +drop cascades to table test_range1 +drop cascades to table test_range2 +drop cascades to table test_range3 +drop cascades to table dist1 +drop cascades to table dist2 +RESET client_min_messages; +RESET citus.log_multi_join_order; +RESET citus.enable_repartition_joins; diff --git a/src/test/regress/expected/recurring_outer_join.out b/src/test/regress/expected/recurring_outer_join.out index 3cd7cc6dc..eeef2e8da 100644 --- a/src/test/regress/expected/recurring_outer_join.out +++ b/src/test/regress/expected/recurring_outer_join.out @@ -328,34 +328,32 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c -- full join a recurring rel. And finally, we convert lhs of the full join (t1) into -- an intermediate result too. SELECT COUNT(*) FROM dist_1 t1 FULL JOIN (dist_1 RIGHT JOIN local_1 USING(a)) t2 USING (a); -DEBUG: Wrapping relation "local_1" to a subquery -DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.local_1 WHERE true -DEBUG: recursively planning left side of the right join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: recursively planning noncolocated relation DEBUG: Wrapping relation "dist_1" to a subquery -DEBUG: generating subplan XXX_2 for subquery SELECT a FROM recurring_outer_join.dist_1 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.dist_1 WHERE true +DEBUG: Wrapping relation "local_1" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT a FROM recurring_outer_join.local_1 WHERE true DEBUG: recursively planning left side of the full join since the other side is a recurring rel DEBUG: recursively planning distributed relation "dist_1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" "t1" to a subquery DEBUG: generating subplan XXX_3 for subquery SELECT a FROM recurring_outer_join.dist_1 t1 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT t1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t1_1) t1 FULL JOIN ((SELECT dist_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) dist_1_1) dist_1 RIGHT JOIN (SELECT local_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) local_1_1) local_1 USING (a)) t2(a, b, b_1) USING (a)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT t1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t1_1) t1 FULL JOIN ((SELECT dist_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) dist_1_1) dist_1 RIGHT JOIN (SELECT local_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) local_1_1) local_1 USING (a)) t2(a, b, b_1) USING (a)) count --------------------------------------------------------------------- 43 (1 row) SELECT COUNT(*) FROM dist_1 t1 FULL JOIN (dist_1 RIGHT JOIN citus_local_1 USING(a)) t2 USING (a); -DEBUG: Wrapping relation "citus_local_1" to a subquery -DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.citus_local_1 WHERE true -DEBUG: recursively planning left side of the right join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: recursively planning noncolocated relation DEBUG: Wrapping relation "dist_1" to a subquery -DEBUG: generating subplan XXX_2 for subquery SELECT a FROM recurring_outer_join.dist_1 WHERE true +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.dist_1 WHERE true +DEBUG: Wrapping relation "citus_local_1" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT a FROM recurring_outer_join.citus_local_1 WHERE true DEBUG: recursively planning left side of the full join since the other side is a recurring rel DEBUG: recursively planning distributed relation "dist_1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" "t1" to a subquery DEBUG: generating subplan XXX_3 for subquery SELECT a FROM recurring_outer_join.dist_1 t1 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT t1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t1_1) t1 FULL JOIN ((SELECT dist_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) dist_1_1) dist_1 RIGHT JOIN (SELECT citus_local_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_1_1) citus_local_1 USING (a)) t2(a, b, b_1) USING (a)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT t1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t1_1) t1 FULL JOIN ((SELECT dist_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) dist_1_1) dist_1 RIGHT JOIN (SELECT citus_local_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) citus_local_1_1) citus_local_1 USING (a)) t2(a, b, b_1) USING (a)) count --------------------------------------------------------------------- 43 @@ -436,13 +434,17 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS c JOIN dist_1 t2 ON (t1.a = t2.a) WHERE t1.a IN (SELECT a FROM dist_1 t3); +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "dist_1" "t2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.dist_1 t2 WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT a FROM recurring_outer_join.dist_1 t3 DEBUG: Wrapping relation "local_1" to a subquery -DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.local_1 WHERE true +DEBUG: generating subplan XXX_3 for subquery SELECT a FROM recurring_outer_join.local_1 WHERE true DEBUG: recursively planning left side of the right join since the outer side is a recurring rel DEBUG: recursively planning distributed relation "dist_1" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" to a subquery -DEBUG: generating subplan XXX_2 for subquery SELECT a FROM recurring_outer_join.dist_1 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT dist_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) dist_1_1) dist_1 RIGHT JOIN (SELECT local_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) local_1_1) local_1 USING (a)) t1(a, b, b_1) JOIN recurring_outer_join.dist_1 t2 ON ((t1.a OPERATOR(pg_catalog.=) t2.a))) WHERE (t1.a OPERATOR(pg_catalog.=) ANY (SELECT t3.a FROM recurring_outer_join.dist_1 t3)) +DEBUG: generating subplan XXX_4 for subquery SELECT a FROM recurring_outer_join.dist_1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (((SELECT dist_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) dist_1_1) dist_1 RIGHT JOIN (SELECT local_1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) local_1_1) local_1 USING (a)) t1(a, b, b_1) JOIN (SELECT t2_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t2_1) t2 ON ((t1.a OPERATOR(pg_catalog.=) t2.a))) WHERE (t1.a OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer))) count --------------------------------------------------------------------- 18 @@ -668,15 +670,14 @@ LEFT JOIN dist_1 t4 ON (t4.a = t5.a AND t4.b = t5.b) WHERE t4.b IS NULL; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "dist_1" "t4" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t4 WHERE true DEBUG: recursively planning right side of the left join since the outer side is a recurring rel DEBUG: recursively planning distributed relation "dist_1" "t3" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" "t3" to a subquery -DEBUG: generating subplan XXX_1 for subquery SELECT x AS a FROM recurring_outer_join.dist_1 t3(x, y) WHERE true -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t4" since it is part of a distributed join node that is outer joined with a recurring rel -DEBUG: Wrapping relation "dist_1" "t4" to a subquery -DEBUG: generating subplan XXX_2 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t4 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((recurring_outer_join.ref_1 t1 LEFT JOIN (recurring_outer_join.ref_1 t2(a_1, b) RIGHT JOIN (SELECT t3_1.x AS a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t3_1(x)) t3(x, y) ON ((t2.a_1 OPERATOR(pg_catalog.=) t3.x))) t5(a, b, x, y) USING (a)) LEFT JOIN (SELECT t4_1.a, t4_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t4_1) t4 ON (((t4.a OPERATOR(pg_catalog.=) t5.a) AND (t4.b OPERATOR(pg_catalog.=) t5.b)))) WHERE (t4.b IS NULL) +DEBUG: generating subplan XXX_2 for subquery SELECT x AS a FROM recurring_outer_join.dist_1 t3(x, y) WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((recurring_outer_join.ref_1 t1 LEFT JOIN (recurring_outer_join.ref_1 t2(a_1, b) RIGHT JOIN (SELECT t3_1.x AS a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t3_1(x)) t3(x, y) ON ((t2.a_1 OPERATOR(pg_catalog.=) t3.x))) t5(a, b, x, y) USING (a)) LEFT JOIN (SELECT t4_1.a, t4_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t4_1) t4 ON (((t4.a OPERATOR(pg_catalog.=) t5.a) AND (t4.b OPERATOR(pg_catalog.=) t5.b)))) WHERE (t4.b IS NULL) count --------------------------------------------------------------------- 40 @@ -705,15 +706,14 @@ DEBUG: recursively planning left side of the right join since the outer side is DEBUG: recursively planning distributed relation "dist_1" "t6" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" "t6" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.dist_1 t6 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "dist_1" "t8" to a subquery +DEBUG: generating subplan XXX_2 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t8 WHERE true DEBUG: recursively planning right side of the left join since the outer side is a recurring rel DEBUG: recursively planning distributed relation "dist_1" "t4" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" "t4" to a subquery -DEBUG: generating subplan XXX_2 for subquery SELECT a FROM recurring_outer_join.dist_1 t4 WHERE true -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t8" since it is part of a distributed join node that is outer joined with a recurring rel -DEBUG: Wrapping relation "dist_1" "t8" to a subquery -DEBUG: generating subplan XXX_3 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t8 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((recurring_outer_join.ref_1 t1 LEFT JOIN ((SELECT t4_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t4_1) t4 JOIN (SELECT t6.a FROM ((SELECT t6_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t6_1) t6 RIGHT JOIN recurring_outer_join.ref_1 t7 USING (a))) t5 USING (a)) q USING (a)) LEFT JOIN (SELECT t8_1.a, t8_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t8_1) t8 USING (a)) WHERE (t8.b IS NULL) +DEBUG: generating subplan XXX_3 for subquery SELECT a FROM recurring_outer_join.dist_1 t4 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((recurring_outer_join.ref_1 t1 LEFT JOIN ((SELECT t4_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t4_1) t4 JOIN (SELECT t6.a FROM ((SELECT t6_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t6_1) t6 RIGHT JOIN recurring_outer_join.ref_1 t7 USING (a))) t5 USING (a)) q USING (a)) LEFT JOIN (SELECT t8_1.a, t8_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t8_1) t8 USING (a)) WHERE (t8.b IS NULL) count --------------------------------------------------------------------- 10 @@ -986,8 +986,7 @@ RIGHT JOIN ) t2 USING (a); DEBUG: pathlist hook for columnar table am -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t4" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: recursively planning noncolocated relation DEBUG: Wrapping relation "dist_1" "t4" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.dist_1 t4 WHERE true DEBUG: recursively planning left side of the right join since the outer side is a recurring rel @@ -1025,23 +1024,20 @@ RIGHT JOIN USING(a) ) t2 USING (a); -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t4" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: recursively planning noncolocated relation DEBUG: Wrapping relation "dist_1" "t4" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.dist_1 t4 WHERE true -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t8" since it is part of a distributed join node that is outer joined with a recurring rel -DEBUG: Wrapping relation "dist_1" "t8" to a subquery -DEBUG: generating subplan XXX_2 for subquery SELECT a FROM recurring_outer_join.dist_1 t8 WHERE true -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t6" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: recursively planning noncolocated relation DEBUG: Wrapping relation "dist_1" "t6" to a subquery -DEBUG: generating subplan XXX_3 for subquery SELECT a FROM recurring_outer_join.dist_1 t6 WHERE true +DEBUG: generating subplan XXX_2 for subquery SELECT a FROM recurring_outer_join.dist_1 t6 WHERE true +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "dist_1" "t8" to a subquery +DEBUG: generating subplan XXX_3 for subquery SELECT a FROM recurring_outer_join.dist_1 t8 WHERE true DEBUG: recursively planning left side of the right join since the outer side is a recurring rel DEBUG: recursively planning distributed relation "dist_1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" "t1" to a subquery DEBUG: generating subplan XXX_4 for subquery SELECT a FROM recurring_outer_join.dist_1 t1 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT t1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t1_1) t1 RIGHT JOIN (recurring_outer_join.ref_1 t3 LEFT JOIN (((recurring_outer_join.ref_1 t5 LEFT JOIN (SELECT t4_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t4_1) t4 USING (a)) JOIN (SELECT t6_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t6_1) t6 USING (a)) JOIN (recurring_outer_join.ref_1 t7 LEFT JOIN (SELECT t8_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t8_1) t8 USING (a)) USING (a)) USING (a)) t2(a, b, b_1, b_2, b_3, b_4, b_5) USING (a)) +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM ((SELECT t1_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t1_1) t1 RIGHT JOIN (recurring_outer_join.ref_1 t3 LEFT JOIN (((recurring_outer_join.ref_1 t5 LEFT JOIN (SELECT t4_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t4_1) t4 USING (a)) JOIN (SELECT t6_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t6_1) t6 USING (a)) JOIN (recurring_outer_join.ref_1 t7 LEFT JOIN (SELECT t8_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t8_1) t8 USING (a)) USING (a)) USING (a)) t2(a, b, b_1, b_2, b_3, b_4, b_5) USING (a)) count --------------------------------------------------------------------- 7570 @@ -1599,12 +1595,14 @@ FROM ref_1 LEFT JOIN dist_1 t1 USING (a,b) JOIN dist_1 t2 USING (a,b) ORDER BY 1,2,3 LIMIT 5; +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "dist_1" "t2" to a subquery +DEBUG: generating subplan XXX_1 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t2 WHERE true DEBUG: recursively planning right side of the left join since the outer side is a recurring rel DEBUG: recursively planning distributed relation "dist_1" "t1" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" "t1" to a subquery -DEBUG: generating subplan XXX_1 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t1 WHERE true -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.b, (SELECT ref_1_1.b FROM recurring_outer_join.ref_1 ref_1_1 WHERE (t1.a OPERATOR(pg_catalog.=) ref_1_1.a) ORDER BY ref_1_1.a, ref_1_1.b LIMIT 1) AS b, (SELECT t2.a) AS a FROM ((recurring_outer_join.ref_1 LEFT JOIN (SELECT t1_1.a, t1_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t1_1) t1 USING (a, b)) JOIN recurring_outer_join.dist_1 t2 USING (a, b)) ORDER BY t1.b, (SELECT ref_1_1.b FROM recurring_outer_join.ref_1 ref_1_1 WHERE (t1.a OPERATOR(pg_catalog.=) ref_1_1.a) ORDER BY ref_1_1.a, ref_1_1.b LIMIT 1), (SELECT t2.a) LIMIT 5 -DEBUG: push down of limit count: 5 +DEBUG: generating subplan XXX_2 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t1 WHERE true +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.b, (SELECT ref_1_1.b FROM recurring_outer_join.ref_1 ref_1_1 WHERE (t1.a OPERATOR(pg_catalog.=) ref_1_1.a) ORDER BY ref_1_1.a, ref_1_1.b LIMIT 1) AS b, (SELECT t2.a) AS a FROM ((recurring_outer_join.ref_1 LEFT JOIN (SELECT t1_1.a, t1_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t1_1) t1 USING (a, b)) JOIN (SELECT t2_1.a, t2_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t2_1) t2 USING (a, b)) ORDER BY t1.b, (SELECT ref_1_1.b FROM recurring_outer_join.ref_1 ref_1_1 WHERE (t1.a OPERATOR(pg_catalog.=) ref_1_1.a) ORDER BY ref_1_1.a, ref_1_1.b LIMIT 1), (SELECT t2.a) LIMIT 5 b | b | a --------------------------------------------------------------------- 11 | 11 | 1 @@ -1763,15 +1761,14 @@ DEBUG: recursively planning distributed relation "dist_1" "d" since it is part DEBUG: Wrapping relation "dist_1" "d" to a subquery DEBUG: generating subplan XXX_14 for subquery SELECT NULL::integer AS "dummy-1" FROM recurring_outer_join.dist_1 d WHERE true DEBUG: generating subplan XXX_15 for subquery SELECT count(DISTINCT t20.a) AS a FROM (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_5'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t20, (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_6'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t21, (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_7'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t22, (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_8'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t23, (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_9'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t24, (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_10'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t25, (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_11'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t26, (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_12'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t27, (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_13'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t28, (SELECT r.a, d.b FROM (recurring_outer_join.ref_1 r LEFT JOIN (SELECT NULL::integer AS a, NULL::integer AS b FROM (SELECT intermediate_result."dummy-1" FROM read_intermediate_result('XXX_14'::text, 'binary'::citus_copy_format) intermediate_result("dummy-1" integer)) d_1) d USING (b)) WHERE (r.a IS NOT NULL)) t29 WHERE ((t20.a OPERATOR(pg_catalog.=) t29.a) AND (t20.a OPERATOR(pg_catalog.=) t28.a) AND (t20.a OPERATOR(pg_catalog.=) t27.a) AND (t20.a OPERATOR(pg_catalog.=) t26.a) AND (t20.a OPERATOR(pg_catalog.=) t25.a) AND (t20.a OPERATOR(pg_catalog.=) t24.a) AND (t20.a OPERATOR(pg_catalog.=) t23.a) AND (t20.a OPERATOR(pg_catalog.=) t21.a) AND (t20.a OPERATOR(pg_catalog.=) t21.a) AND (t20.a OPERATOR(pg_catalog.=) t20.a)) +DEBUG: recursively planning noncolocated relation +DEBUG: Wrapping relation "dist_1" "t34" to a subquery +DEBUG: generating subplan XXX_16 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t34 WHERE true DEBUG: recursively planning right side of the left join since the outer side is a recurring rel DEBUG: recursively planning distributed relation "dist_1" "t31" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" "t31" to a subquery -DEBUG: generating subplan XXX_16 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t31 WHERE true -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t34" since it is part of a distributed join node that is outer joined with a recurring rel -DEBUG: Wrapping relation "dist_1" "t34" to a subquery -DEBUG: generating subplan XXX_17 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t34 WHERE true -DEBUG: generating subplan XXX_18 for subquery SELECT DISTINCT t31.b, (SELECT max(t32.b) AS max FROM (recurring_outer_join.ref_1 t32 LEFT JOIN (SELECT t33_1.a, t33_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t33_1) t33 USING (a, b)) WHERE (t31.a OPERATOR(pg_catalog.=) t32.a)) AS max, (SELECT t34.a) AS a FROM ((((recurring_outer_join.ref_1 t35 LEFT JOIN (SELECT t31_1.a, t31_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_16'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t31_1) t31 USING (a, b)) LEFT JOIN (SELECT t34_1.a, t34_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_17'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t34_1) t34 USING (a, b)) LEFT JOIN (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) cte_1 USING (a, b)) LEFT JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_15'::text, 'binary'::citus_copy_format) intermediate_result(a bigint)) t30 ON ((t30.a OPERATOR(pg_catalog.=) cte_1.a))) ORDER BY t31.b, (SELECT max(t32.b) AS max FROM (recurring_outer_join.ref_1 t32 LEFT JOIN (SELECT t33_1.a, t33_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t33_1) t33 USING (a, b)) WHERE (t31.a OPERATOR(pg_catalog.=) t32.a)), (SELECT t34.a) +DEBUG: generating subplan XXX_17 for subquery SELECT a, b FROM recurring_outer_join.dist_1 t31 WHERE true +DEBUG: generating subplan XXX_18 for subquery SELECT DISTINCT t31.b, (SELECT max(t32.b) AS max FROM (recurring_outer_join.ref_1 t32 LEFT JOIN (SELECT t33_1.a, t33_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t33_1) t33 USING (a, b)) WHERE (t31.a OPERATOR(pg_catalog.=) t32.a)) AS max, (SELECT t34.a) AS a FROM ((((recurring_outer_join.ref_1 t35 LEFT JOIN (SELECT t31_1.a, t31_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_17'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t31_1) t31 USING (a, b)) LEFT JOIN (SELECT t34_1.a, t34_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_16'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t34_1) t34 USING (a, b)) LEFT JOIN (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_4'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) cte_1 USING (a, b)) LEFT JOIN (SELECT intermediate_result.a FROM read_intermediate_result('XXX_15'::text, 'binary'::citus_copy_format) intermediate_result(a bigint)) t30 ON ((t30.a OPERATOR(pg_catalog.=) cte_1.a))) ORDER BY t31.b, (SELECT max(t32.b) AS max FROM (recurring_outer_join.ref_1 t32 LEFT JOIN (SELECT t33_1.a, t33_1.b FROM (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) t33_1) t33 USING (a, b)) WHERE (t31.a OPERATOR(pg_catalog.=) t32.a)), (SELECT t34.a) DEBUG: recursively planning right side of the left join since the outer side is a recurring rel DEBUG: recursively planning distributed relation "dist_1" "t3" since it is part of a distributed join node that is outer joined with a recurring rel DEBUG: Wrapping relation "dist_1" "t3" to a subquery @@ -1835,13 +1832,11 @@ cte_2 AS ( SELECT * FROM cte_1, cte_2; DEBUG: CTE cte_1 is going to be inlined via distributed planning DEBUG: CTE cte_2 is going to be inlined via distributed planning -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t8" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: recursively planning noncolocated relation DEBUG: Wrapping relation "dist_1" "t8" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.dist_1 t8 WHERE true DEBUG: generating subplan XXX_2 for subquery SELECT count(*) AS count FROM (recurring_outer_join.dist_1 t1 JOIN ((recurring_outer_join.dist_1 t2 JOIN recurring_outer_join.dist_1 t3 USING (a)) JOIN (recurring_outer_join.dist_1 t4 JOIN (recurring_outer_join.dist_1 t5 JOIN (recurring_outer_join.dist_1 t6 JOIN (recurring_outer_join.ref_1 t7 LEFT JOIN (SELECT t8_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t8_1) t8 USING (a)) USING (a)) USING (a)) USING (a)) USING (a)) USING (a)) -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t16" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: recursively planning noncolocated relation DEBUG: Wrapping relation "dist_1" "t16" to a subquery DEBUG: generating subplan XXX_3 for subquery SELECT a FROM recurring_outer_join.dist_1 t16 WHERE true DEBUG: generating subplan XXX_4 for subquery SELECT count(*) AS count FROM (recurring_outer_join.dist_1 t9 JOIN ((recurring_outer_join.dist_1 t10 JOIN recurring_outer_join.dist_1 t11 USING (a)) JOIN (recurring_outer_join.dist_1 t12 JOIN (recurring_outer_join.dist_1 t13 JOIN (recurring_outer_join.dist_1 t14 JOIN (recurring_outer_join.ref_1 t15 LEFT JOIN (SELECT t16_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_3'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t16_1) t16 USING (a)) USING (a)) USING (a)) USING (a)) USING (a)) USING (a)) @@ -1989,8 +1984,7 @@ BEGIN; DEBUG: cannot perform distributed INSERT INTO ... SELECT because the partition columns in the source table and subquery do not match DETAIL: Subquery contains an operator in the same position as the target table's partition column. HINT: Ensure the target table's partition column has a corresponding simple column reference to a distributed table's partition column in the subquery. -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t3" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: recursively planning noncolocated relation DEBUG: Wrapping relation "dist_1" "t3" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.dist_1 t3 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT (t1.a OPERATOR(pg_catalog.*) 3) AS a, t1.b FROM (recurring_outer_join.dist_1 t1 JOIN (recurring_outer_join.ref_1 t2 LEFT JOIN (SELECT t3_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t3_1) t3 USING (a)) t4(a, b, b_1) ON ((t1.a OPERATOR(pg_catalog.=) t4.a))) @@ -2006,8 +2000,7 @@ BEGIN; (ref_1 t2 LEFT JOIN dist_1 t3 USING(a)) t4 ON (t1.a = t4.a); DEBUG: Router planner cannot handle multi-shard select queries -DEBUG: recursively planning right side of the left join since the outer side is a recurring rel -DEBUG: recursively planning distributed relation "dist_1" "t3" since it is part of a distributed join node that is outer joined with a recurring rel +DEBUG: recursively planning noncolocated relation DEBUG: Wrapping relation "dist_1" "t3" to a subquery DEBUG: generating subplan XXX_1 for subquery SELECT a FROM recurring_outer_join.dist_1 t3 WHERE true DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT t1.a, t1.b FROM (recurring_outer_join.dist_1 t1 JOIN (recurring_outer_join.ref_1 t2 LEFT JOIN (SELECT t3_1.a, NULL::integer AS b FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer)) t3_1) t3 USING (a)) t4(a, b, b_1) ON ((t1.a OPERATOR(pg_catalog.=) t4.a))) diff --git a/src/test/regress/expected/subquery_local_tables.out b/src/test/regress/expected/subquery_local_tables.out index ce5e844aa..534fe0c8c 100644 --- a/src/test/regress/expected/subquery_local_tables.out +++ b/src/test/regress/expected/subquery_local_tables.out @@ -234,7 +234,8 @@ GROUP BY user_id HAVING count(*) > 1 AND sum(value_2) > 29 ORDER BY 1; DEBUG: generating subplan XXX_1 for subquery SELECT user_id, count(*) AS count_pay FROM subquery_local_tables.users_table_local WHERE ((user_id OPERATOR(pg_catalog.>=) 1) AND (user_id OPERATOR(pg_catalog.<=) 3) AND (value_1 OPERATOR(pg_catalog.>) 3) AND (value_1 OPERATOR(pg_catalog.<) 5)) GROUP BY user_id HAVING (count(*) OPERATOR(pg_catalog.>) 1) LIMIT 10 -DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT user_id FROM public.users_table WHERE (user_id OPERATOR(pg_catalog.=) ANY (SELECT subquery_top.user_id FROM (SELECT subquery_1.user_id, subquery_2.count_pay FROM ((SELECT users_table_1.user_id, 'action=>1'::text AS event, events_table."time" FROM public.users_table users_table_1, public.events_table WHERE ((users_table_1.user_id OPERATOR(pg_catalog.=) events_table.user_id) AND (users_table_1.user_id OPERATOR(pg_catalog.>=) 1) AND (users_table_1.user_id OPERATOR(pg_catalog.<=) 3) AND (events_table.event_type OPERATOR(pg_catalog.>) 1) AND (events_table.event_type OPERATOR(pg_catalog.<) 3)) UNION SELECT users_table_1.user_id, 'action=>2'::text AS event, events_table."time" FROM public.users_table users_table_1, public.events_table WHERE ((users_table_1.user_id OPERATOR(pg_catalog.=) events_table.user_id) AND (users_table_1.user_id OPERATOR(pg_catalog.>=) 1) AND (users_table_1.user_id OPERATOR(pg_catalog.<=) 3) AND (events_table.event_type OPERATOR(pg_catalog.>) 2) AND (events_table.event_type OPERATOR(pg_catalog.<) 4))) subquery_1 LEFT JOIN (SELECT intermediate_result.user_id, intermediate_result.count_pay FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, count_pay bigint)) subquery_2 ON ((subquery_1.user_id OPERATOR(pg_catalog.=) subquery_2.user_id))) GROUP BY subquery_1.user_id, subquery_2.count_pay) subquery_top GROUP BY subquery_top.count_pay, subquery_top.user_id)) GROUP BY user_id HAVING ((count(*) OPERATOR(pg_catalog.>) 1) AND (sum(value_2) OPERATOR(pg_catalog.>) 29)) ORDER BY user_id +DEBUG: generating subplan XXX_2 for subquery SELECT user_id FROM (SELECT subquery_1.user_id, subquery_2.count_pay FROM ((SELECT users_table.user_id, 'action=>1'::text AS event, events_table."time" FROM public.users_table, public.events_table WHERE ((users_table.user_id OPERATOR(pg_catalog.=) events_table.user_id) AND (users_table.user_id OPERATOR(pg_catalog.>=) 1) AND (users_table.user_id OPERATOR(pg_catalog.<=) 3) AND (events_table.event_type OPERATOR(pg_catalog.>) 1) AND (events_table.event_type OPERATOR(pg_catalog.<) 3)) UNION SELECT users_table.user_id, 'action=>2'::text AS event, events_table."time" FROM public.users_table, public.events_table WHERE ((users_table.user_id OPERATOR(pg_catalog.=) events_table.user_id) AND (users_table.user_id OPERATOR(pg_catalog.>=) 1) AND (users_table.user_id OPERATOR(pg_catalog.<=) 3) AND (events_table.event_type OPERATOR(pg_catalog.>) 2) AND (events_table.event_type OPERATOR(pg_catalog.<) 4))) subquery_1 LEFT JOIN (SELECT intermediate_result.user_id, intermediate_result.count_pay FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, count_pay bigint)) subquery_2 ON ((subquery_1.user_id OPERATOR(pg_catalog.=) subquery_2.user_id))) GROUP BY subquery_1.user_id, subquery_2.count_pay) subquery_top GROUP BY count_pay, user_id +DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT user_id FROM public.users_table WHERE (user_id OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.user_id FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer))) GROUP BY user_id HAVING ((count(*) OPERATOR(pg_catalog.>) 1) AND (sum(value_2) OPERATOR(pg_catalog.>) 29)) ORDER BY user_id user_id --------------------------------------------------------------------- 2 diff --git a/src/test/regress/multi_1_schedule b/src/test/regress/multi_1_schedule index 5e2cd17c1..a751747ef 100644 --- a/src/test/regress/multi_1_schedule +++ b/src/test/regress/multi_1_schedule @@ -201,6 +201,7 @@ test: local_table_join test: local_dist_join_mixed test: citus_local_dist_joins test: recurring_outer_join +test: non_colocated_outer_joins test: pg_dump # --------- diff --git a/src/test/regress/sql/non_colocated_outer_joins.sql b/src/test/regress/sql/non_colocated_outer_joins.sql new file mode 100644 index 000000000..2f67cea84 --- /dev/null +++ b/src/test/regress/sql/non_colocated_outer_joins.sql @@ -0,0 +1,248 @@ +CREATE SCHEMA non_colocated_outer_joins; +SET search_path TO non_colocated_outer_joins; + +CREATE TABLE test_hash1(col1 INT, col2 INT); +SELECT create_distributed_table('test_hash1', 'col1'); +INSERT INTO test_hash1 SELECT i, i FROM generate_series(1,10) i; + +CREATE TABLE test_hash2(col1 INT, col2 INT); +SELECT create_distributed_table('test_hash2', 'col2'); +INSERT INTO test_hash2 SELECT i, i FROM generate_series(6,15) i; + +CREATE TABLE test_hash3(col1 INT, col2 INT); +SELECT create_distributed_table('test_hash3', 'col1'); +INSERT INTO test_hash3 SELECT i, i FROM generate_series(11,20) i; + +SET citus.enable_repartition_joins TO ON; +SET citus.log_multi_join_order TO ON; +SET client_min_messages TO DEBUG1; + + +-- join order planner can handle left outer join between tables with simple join clause + +-- outer table restricted on partition column whereas inner one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +-- inner table restricted on partition column whereas outer one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col2 = t2.col2) ORDER BY 1,2,3,4; +-- both tables are not restricted on partition column +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col2 = t2.col1) ORDER BY 1,2,3,4; + + +-- join order planner can handle right outer join between tables with simple join clause + +-- outer table restricted on partition column whereas inner one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +-- inner table restricted on partition column whereas outer one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col2) ORDER BY 1,2,3,4; +-- both tables are not restricted on partition column +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col1) ORDER BY 1,2,3,4; + + +-- join order planner can handle full outer join between tables with simple join clause + +-- left outer table restricted on partition column whereas right outer one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +-- right outer table restricted on partition column whereas left outer one is not restricted on the partition column +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col2) ORDER BY 1,2,3,4; +-- both tables are not restricted on partition column +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col1) ORDER BY 1,2,3,4; + + +-- join order planner can handle queries with multi joins consisting of outer joins with simple join clause + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t1.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col2) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col2) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col1) ORDER BY 1,2,3,4,5,6; + +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t1.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col2) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col2) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash2 t2 LEFT JOIN test_hash1 t1 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col1) ORDER BY 1,2,3,4,5,6; + +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t1.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col2) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col2) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col2) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t1.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_hash2 t2 ON (t1.col2 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col2 = t2.col1) ORDER BY 1,2,3,4,5,6; + +-- join order planner handles left outer join between tables with nonsimple join or where clause + +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) WHERE (t1.col1 IS NULL or t2.col2 IS NULL) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1 and t1.col1 < 0) ORDER BY 1,2,3,4; + +-- join order planner supports repartition join between append distributed tables + +CREATE TABLE test_append1 (col1 INT, col2 INT); +SELECT create_distributed_table('test_append1', 'col1', 'append'); +SELECT master_create_empty_shard('test_append1') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 1, shardmaxvalue = 5 WHERE shardid = :new_shard_id; +SELECT master_create_empty_shard('test_append1') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 6, shardmaxvalue = 10 WHERE shardid = :new_shard_id; +INSERT INTO test_append1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10); + +CREATE TABLE test_append2 (col1 INT, col2 INT); +SELECT create_distributed_table('test_append2', 'col2', 'append'); +SELECT master_create_empty_shard('test_append2') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 6, shardmaxvalue = 10 WHERE shardid = :new_shard_id; +SELECT master_create_empty_shard('test_append2') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 11, shardmaxvalue = 15 WHERE shardid = :new_shard_id; +INSERT INTO test_append2 VALUES (6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12),(13,13),(14,14),(15,15); + +CREATE TABLE test_append3(col1 INT, col2 INT); +SELECT create_distributed_table('test_append3', 'col1', 'append'); +SELECT master_create_empty_shard('test_append3') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 11, shardmaxvalue = 15 WHERE shardid = :new_shard_id; +SELECT master_create_empty_shard('test_append3') AS new_shard_id \gset +UPDATE pg_dist_shard SET shardminvalue = 16, shardmaxvalue = 20 WHERE shardid = :new_shard_id; +INSERT INTO test_append3 VALUES (11,11),(12,12),(13,13),(14,14),(15,15),(16,16),(17,17),(18,18),(19,19),(20,20); + +-- join order planner supports repartition join between append-append distributed tables + +SELECT t1.*, t2.* FROM test_append1 t1 LEFT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_append1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_append1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.*, t3.* FROM test_append1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_append3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_append2 t2 LEFT JOIN test_append1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_append3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_append1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_append3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; + +-- join order planner supports repartition join between append-hash distributed tables + +SELECT t1.*, t2.* FROM test_append1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_append1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_append1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_append2 t2 LEFT JOIN test_hash1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; + +-- join order planner supports repartition join between range distributed tables + +CREATE TABLE test_range1(col1 INT, col2 INT); +SELECT create_distributed_table('test_range1', 'col1', 'range'); +CALL public.create_range_partitioned_shards('test_range1', + '{0,6,11,16}', + '{5,10,15,20}'); +INSERT INTO test_range1 SELECT i, i FROM generate_series(1,10) i; + +CREATE TABLE test_range2(col1 INT, col2 INT); +SELECT create_distributed_table('test_range2', 'col2', 'range'); +CALL public.create_range_partitioned_shards('test_range2', + '{0,6,11,16}', + '{5,10,15,20}'); +INSERT INTO test_range2 SELECT i, i FROM generate_series(6,15) i; + +CREATE TABLE test_range3(col1 INT, col2 INT); +SELECT create_distributed_table('test_range3', 'col1', 'range'); +CALL public.create_range_partitioned_shards('test_range3', + '{0,6,11,16}', + '{5,10,15,20}'); +INSERT INTO test_range3 SELECT i, i FROM generate_series(11,20) i; + +-- join order planner supports repartition join between range-range distributed tables + +SELECT t1.*, t2.* FROM test_range1 t1 LEFT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_range1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_range1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.*, t3.* FROM test_range1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_range3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_range2 t2 LEFT JOIN test_range1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_range3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_range1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_range3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; + +-- join order planner supports repartition join between range-hash distributed tables + +SELECT t1.*, t2.* FROM test_range1 t1 LEFT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_range1 t1 RIGHT JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_hash1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_range1 t1 FULL JOIN test_hash2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_hash1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_range2 t2 LEFT JOIN test_hash1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_hash1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; + +-- join order planner supports repartition join between range-append distributed tables + +SELECT t1.*, t2.* FROM test_range1 t1 LEFT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_append1 t1 LEFT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_range1 t1 RIGHT JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_append1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_range1 t1 FULL JOIN test_append2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.* FROM test_append1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; +SELECT t1.*, t2.*, t3.* FROM test_append1 t1 RIGHT JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_range2 t2 LEFT JOIN test_append1 t1 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; +SELECT t1.*, t2.*, t3.* FROM test_append1 t1 FULL JOIN test_range2 t2 ON (t1.col1 = t2.col1) INNER JOIN test_hash3 t3 ON (t3.col1 = t2.col1) ORDER BY 1,2,3,4,5,6; + +-- join order planner cannot handle semi joins + +SELECT t1.* FROM test_hash1 t1 WHERE EXISTS (SELECT * FROM test_hash2 t2 WHERE t1.col1 = t2.col1) ORDER BY 1,2; +SELECT t1.* FROM test_hash1 t1 WHERE EXISTS (SELECT * FROM test_hash2 t2 WHERE t1.col2 = t2.col2) ORDER BY 1,2; +SELECT t2.* FROM test_hash2 t2 WHERE EXISTS (SELECT * FROM test_hash1 t1 WHERE t1.col1 = t2.col1) ORDER BY 1,2; +SELECT t2.* FROM test_hash2 t2 WHERE EXISTS (SELECT * FROM test_hash1 t1 WHERE t1.col2 = t2.col2) ORDER BY 1,2; + +-- join order planner cannot handle anti joins + +SELECT t1.* FROM test_hash1 t1 WHERE NOT EXISTS (SELECT * FROM test_hash2 t2 WHERE t1.col1 = t2.col1) ORDER BY 1,2; +SELECT t1.* FROM test_hash1 t1 WHERE NOT EXISTS (SELECT * FROM test_hash2 t2 WHERE t1.col2 = t2.col2) ORDER BY 1,2; +SELECT t2.* FROM test_hash2 t2 WHERE NOT EXISTS (SELECT * FROM test_hash1 t1 WHERE t1.col1 = t2.col1) ORDER BY 1,2; +SELECT t2.* FROM test_hash2 t2 WHERE NOT EXISTS (SELECT * FROM test_hash1 t1 WHERE t1.col2 = t2.col2) ORDER BY 1,2; + +-- join order planner cannot handle lateral outer joins + +SELECT t1.*, tt2.* FROM test_hash1 t1 LEFT JOIN LATERAL (SELECT * FROM test_hash2 t2 WHERE t1.col1 = t2.col1) tt2 ON (t1.col1 = tt2.col1) ORDER BY 1,2,3,4; + +-- join order planner cannot handle cartesian joins + +SELECT tt1.*, t3.* FROM (SELECT t1.* FROM test_hash1 t1, test_hash2 t2) tt1 LEFT JOIN test_hash3 t3 ON (tt1.col1 = t3.col1) ORDER BY 1,2,3,4; + +-- join order planner cannot handle right recursive joins + +SELECT t1.*, t2.* FROM test_hash1 t1 LEFT JOIN ( test_hash2 t2 JOIN test_hash3 t3 ON t2.col2 = t3.col1) ON (t1.col1 = t2.col1) ORDER BY 1,2,3,4; + + +-- sometimes join filters are pushed down and applied before join by PG +CREATE TABLE dist1 (x INT, y INT); +CREATE TABLE dist2 (x INT, y INT); +SELECT create_distributed_table('dist1','x'); +SELECT create_distributed_table('dist2','x'); +INSERT INTO dist1 VALUES (1,2); +INSERT INTO dist1 VALUES (3,4); +INSERT INTO dist2 VALUES (1,2); +INSERT INTO dist2 VALUES (5,6); + +-- single join condition +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x) ORDER BY 1,2,3,4; +-- single join condition and dist2.x >2 will be pushed down as it is on inner part of the join. e.g. filter out dist2.x <= 2 beforehand +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x AND dist2.x >2) ORDER BY 1,2,3,4; +-- single join condition and dist2.x >2 is regular filter and applied after join +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x) WHERE dist2.x >2 ORDER BY 1,2,3,4; +-- single join condition and dist1.x >2 will not be pushed down as it is on outer part of the join +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x AND dist1.x >2) ORDER BY 1,2,3,4; +-- single join condition and dist1.x >2 is regular filter and applied after join +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.x = dist2.x) WHERE dist1.x >2 ORDER BY 1,2,3,4; + + +--- constant false filter as join filter for left join. +-- inner table will be converted to empty result. Constant filter will be applied before join but will not be pushdowned. +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.y = dist2.y AND false) ORDER BY 1,2,3,4; +--- constant false filter as base filter for left join. +-- both tables will be converted to empty result .e.g RTE_RESULT +SELECT * FROM dist1 LEFT JOIN dist2 ON (dist1.y = dist2.y) WHERE false ORDER BY 1,2,3,4; +--- constant false filter as join filter for inner join. +-- both tables will be converted to empty result .e.g RTE_RESULT +SELECT * FROM dist1 INNER JOIN dist2 ON (dist1.y = dist2.y AND false) ORDER BY 1,2,3,4; +--- constant false filter as base filter for inner join. +-- both tables will be converted to empty result .e.g RTE_RESULT +SELECT * FROM dist1 INNER JOIN dist2 ON (dist1.y = dist2.y) WHERE false ORDER BY 1,2,3,4; + + +DROP SCHEMA non_colocated_outer_joins CASCADE; +RESET client_min_messages; +RESET citus.log_multi_join_order; +RESET citus.enable_repartition_joins;