SET citus.next_shard_id TO 1260000; SET citus.log_multi_join_order to true; SET client_min_messages TO LOG; SET citus.shard_count TO 4; CREATE TABLE multi_outer_join_left_hash ( l_custkey integer not null, l_name varchar(25) not null, l_address varchar(40) not null, l_nationkey integer not null, l_phone char(15) not null, l_acctbal decimal(15,2) not null, l_mktsegment char(10) not null, l_comment varchar(117) not null ); SELECT create_distributed_table('multi_outer_join_left_hash', 'l_custkey'); create_distributed_table -------------------------- (1 row) CREATE TABLE multi_outer_join_right_reference ( r_custkey integer not null, r_name varchar(25) not null, r_address varchar(40) not null, r_nationkey integer not null, r_phone char(15) not null, r_acctbal decimal(15,2) not null, r_mktsegment char(10) not null, r_comment varchar(117) not null ); SELECT create_reference_table('multi_outer_join_right_reference'); create_reference_table ------------------------ (1 row) CREATE TABLE multi_outer_join_third_reference ( t_custkey integer not null, t_name varchar(25) not null, t_address varchar(40) not null, t_nationkey integer not null, t_phone char(15) not null, t_acctbal decimal(15,2) not null, t_mktsegment char(10) not null, t_comment varchar(117) not null ); SELECT create_reference_table('multi_outer_join_third_reference'); create_reference_table ------------------------ (1 row) CREATE TABLE multi_outer_join_right_hash ( r_custkey integer not null, r_name varchar(25) not null, r_address varchar(40) not null, r_nationkey integer not null, r_phone char(15) not null, r_acctbal decimal(15,2) not null, r_mktsegment char(10) not null, r_comment varchar(117) not null ); SELECT create_distributed_table('multi_outer_join_right_hash', 'r_custkey'); create_distributed_table -------------------------- (1 row) -- Make sure we do not crash if both tables are emmpty SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_third_reference b ON (l_custkey = t_custkey); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_third_reference" ] min | max -----+----- | (1 row) -- Left table is a large table \copy multi_outer_join_left_hash FROM '@abs_srcdir@/data/customer-1-10.data' with delimiter '|' \copy multi_outer_join_left_hash FROM '@abs_srcdir@/data/customer-11-20.data' with delimiter '|' -- Right table is a small table \copy multi_outer_join_right_reference FROM '@abs_srcdir@/data/customer-1-15.data' with delimiter '|' \copy multi_outer_join_right_hash FROM '@abs_srcdir@/data/customer-1-15.data' with delimiter '|' -- Make sure we do not crash if one table has data SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_third_reference b ON (l_custkey = t_custkey); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_third_reference" ] min | max -----+----- 1 | 20 (1 row) SELECT min(t_custkey), max(t_custkey) FROM multi_outer_join_third_reference a LEFT JOIN multi_outer_join_right_reference b ON (r_custkey = t_custkey); min | max -----+----- | (1 row) -- Third table is a single shard table with all data \copy multi_outer_join_third_reference FROM '@abs_srcdir@/data/customer-1-30.data' with delimiter '|' \copy multi_outer_join_right_hash FROM '@abs_srcdir@/data/customer-1-30.data' with delimiter '|' -- Regular outer join should return results for all rows SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] min | max -----+----- 1 | 20 (1 row) -- Since this is a broadcast join, we should be able to join on any key SELECT count(*) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_nationkey = r_nationkey); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] count ------- 28 (1 row) -- Anti-join should return customers for which there is no row in the right table SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey) WHERE r_custkey IS NULL; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] min | max -----+----- 16 | 20 (1 row) -- Partial anti-join with specific value SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey) WHERE r_custkey IS NULL OR r_custkey = 5; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] min | max -----+----- 5 | 20 (1 row) -- This query is an INNER JOIN in disguise since there cannot be NULL results -- Added extra filter to make query not router plannable SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey) WHERE r_custkey = 5 or r_custkey > 15; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] min | max -----+----- 5 | 5 (1 row) -- Apply a filter before the join SELECT count(l_custkey), count(r_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey AND r_custkey = 5); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] count | count -------+------- 20 | 1 (1 row) -- Apply a filter before the join (no matches right) SELECT count(l_custkey), count(r_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey AND r_custkey = -1 /* nonexistant */); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] count | count -------+------- 20 | 0 (1 row) -- Apply a filter before the join (no matches left) SELECT count(l_custkey), count(r_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey AND l_custkey = -1 /* nonexistant */); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] count | count -------+------- 20 | 0 (1 row) -- Right join should be disallowed in this case SELECT min(r_custkey), max(r_custkey) FROM multi_outer_join_left_hash a RIGHT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey); ERROR: cannot run outer join query if join is not on the partition column DETAIL: Outer joins requiring repartitioning are not supported. -- Reverse right join should be same as left join SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_right_reference a RIGHT JOIN multi_outer_join_left_hash b ON (l_custkey = r_custkey); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] min | max -----+----- 1 | 20 (1 row) -- load some more data \copy multi_outer_join_right_reference FROM '@abs_srcdir@/data/customer-21-30.data' with delimiter '|' -- Update shards so that they do not have 1-1 matching, triggering an error. UPDATE pg_dist_shard SET shardminvalue = '2147483646' WHERE shardid = 1260006; UPDATE pg_dist_shard SET shardmaxvalue = '2147483647' WHERE shardid = 1260006; SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_hash b ON (l_custkey = r_custkey); ERROR: hash partitioned table has overlapping shards UPDATE pg_dist_shard SET shardminvalue = '-2147483648' WHERE shardid = 1260006; UPDATE pg_dist_shard SET shardmaxvalue = '-1073741825' WHERE shardid = 1260006; -- empty tables SELECT master_modify_multiple_shards('DELETE FROM multi_outer_join_left_hash'); master_modify_multiple_shards ------------------------------- 20 (1 row) SELECT master_modify_multiple_shards('DELETE FROM multi_outer_join_right_hash'); master_modify_multiple_shards ------------------------------- 45 (1 row) DELETE FROM multi_outer_join_right_reference; -- reload shards with 1-1 matching \copy multi_outer_join_left_hash FROM '@abs_srcdir@/data/customer-1-15.data' with delimiter '|' \copy multi_outer_join_left_hash FROM '@abs_srcdir@/data/customer-21-30.data' with delimiter '|' \copy multi_outer_join_right_reference FROM '@abs_srcdir@/data/customer-11-20.data' with delimiter '|' \copy multi_outer_join_right_reference FROM '@abs_srcdir@/data/customer-21-30.data' with delimiter '|' \copy multi_outer_join_right_hash FROM '@abs_srcdir@/data/customer-11-20.data' with delimiter '|' \copy multi_outer_join_right_hash FROM '@abs_srcdir@/data/customer-21-30.data' with delimiter '|' -- multi_outer_join_third_reference is a single shard table -- Regular left join should work as expected SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_hash b ON (l_custkey = r_custkey); LOG: join order: [ "multi_outer_join_left_hash" ][ local partition join "multi_outer_join_right_hash" ] min | max -----+----- 1 | 30 (1 row) -- Citus can use broadcast join here SELECT count(*) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_hash b ON (l_nationkey = r_nationkey); ERROR: cannot run outer join query if join is not on the partition column DETAIL: Outer joins requiring repartitioning are not supported. -- Anti-join should return customers for which there is no row in the right table SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey) WHERE r_custkey IS NULL; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] min | max -----+----- 1 | 10 (1 row) -- Partial anti-join with specific value (5, 11-15) SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey) WHERE r_custkey IS NULL OR r_custkey = 15; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] min | max -----+----- 1 | 15 (1 row) -- This query is an INNER JOIN in disguise since there cannot be NULL results (21) -- Added extra filter to make query not router plannable SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey) WHERE r_custkey = 21 or r_custkey < 10; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] min | max -----+----- 21 | 21 (1 row) -- Apply a filter before the join SELECT count(l_custkey), count(r_custkey) FROM multi_outer_join_left_hash a LEFT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey AND r_custkey = 21); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] count | count -------+------- 25 | 1 (1 row) -- Right join should not be allowed in this case SELECT min(r_custkey), max(r_custkey) FROM multi_outer_join_left_hash a RIGHT JOIN multi_outer_join_right_reference b ON (l_custkey = r_custkey); ERROR: cannot run outer join query if join is not on the partition column DETAIL: Outer joins requiring repartitioning are not supported. -- Reverse right join should be same as left join SELECT min(l_custkey), max(l_custkey) FROM multi_outer_join_right_reference a RIGHT JOIN multi_outer_join_left_hash b ON (l_custkey = r_custkey); LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ] min | max -----+----- 1 | 30 (1 row) -- complex query tree should error out SELECT * FROM multi_outer_join_left_hash l1 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: could not run distributed query with complex join orders HINT: Consider joining tables on partition column and have equal filter on joining columns. -- add an anti-join, this should also error out SELECT * FROM multi_outer_join_left_hash l1 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) WHERE r1.r_custkey is NULL; ERROR: could not run distributed query with complex join orders HINT: Consider joining tables on partition column and have equal filter on joining columns. -- Three way join 2-1-1 (broadcast + broadcast join) should work SELECT l_custkey, r_custkey, t_custkey FROM multi_outer_join_left_hash l1 LEFT JOIN multi_outer_join_right_reference r1 ON (l1.l_custkey = r1.r_custkey) LEFT JOIN multi_outer_join_third_reference t1 ON (r1.r_custkey = t1.t_custkey) ORDER BY 1; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_right_reference" ][ reference join "multi_outer_join_third_reference" ] l_custkey | r_custkey | t_custkey -----------+-----------+----------- 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 | | 9 | | 10 | | 11 | 11 | 11 12 | 12 | 12 13 | 13 | 13 14 | 14 | 14 15 | 15 | 15 21 | 21 | 21 22 | 22 | 22 23 | 23 | 23 24 | 24 | 24 25 | 25 | 25 26 | 26 | 26 27 | 27 | 27 28 | 28 | 28 29 | 29 | 29 30 | 30 | 30 (25 rows) -- Right join with single shard right most table should error out SELECT l_custkey, r_custkey, t_custkey FROM multi_outer_join_left_hash l1 LEFT JOIN multi_outer_join_right_hash r1 ON (l1.l_custkey = r1.r_custkey) RIGHT JOIN multi_outer_join_third_reference t1 ON (r1.r_custkey = t1.t_custkey); ERROR: could not run distributed query with complex join orders HINT: Consider joining tables on partition column and have equal filter on joining columns. -- Right join with single shard left most table should work SELECT t_custkey, r_custkey, l_custkey FROM multi_outer_join_third_reference t1 RIGHT JOIN multi_outer_join_right_hash r1 ON (t1.t_custkey = r1.r_custkey) LEFT JOIN multi_outer_join_left_hash l1 ON (r1.r_custkey = l1.l_custkey) ORDER BY 1,2,3; LOG: join order: [ "multi_outer_join_right_hash" ][ reference join "multi_outer_join_third_reference" ][ local partition join "multi_outer_join_left_hash" ] t_custkey | r_custkey | l_custkey -----------+-----------+----------- 11 | 11 | 11 12 | 12 | 12 13 | 13 | 13 14 | 14 | 14 15 | 15 | 15 16 | 16 | 17 | 17 | 18 | 18 | 19 | 19 | 20 | 20 | 21 | 21 | 21 22 | 22 | 22 23 | 23 | 23 24 | 24 | 24 25 | 25 | 25 26 | 26 | 26 27 | 27 | 27 28 | 28 | 28 29 | 29 | 29 30 | 30 | 30 (20 rows) -- Make it anti-join, should display values with l_custkey is null SELECT t_custkey, r_custkey, l_custkey FROM multi_outer_join_third_reference t1 RIGHT JOIN multi_outer_join_right_hash r1 ON (t1.t_custkey = r1.r_custkey) LEFT JOIN multi_outer_join_left_hash l1 ON (r1.r_custkey = l1.l_custkey) WHERE l_custkey is NULL ORDER BY 1; LOG: join order: [ "multi_outer_join_right_hash" ][ reference join "multi_outer_join_third_reference" ][ local partition join "multi_outer_join_left_hash" ] t_custkey | r_custkey | l_custkey -----------+-----------+----------- 16 | 16 | 17 | 17 | 18 | 18 | 19 | 19 | 20 | 20 | (5 rows) -- Cascading right join with single shard left most table should error out SELECT t_custkey, r_custkey, l_custkey FROM multi_outer_join_third_reference t1 RIGHT JOIN multi_outer_join_right_hash r1 ON (t1.t_custkey = r1.r_custkey) RIGHT JOIN multi_outer_join_left_hash l1 ON (r1.r_custkey = l1.l_custkey); ERROR: could not run distributed query with complex join orders HINT: Consider joining tables on partition column and have equal filter on joining columns. -- full outer join should work with 1-1 matched shards SELECT l_custkey, r_custkey FROM multi_outer_join_left_hash l1 FULL JOIN multi_outer_join_right_hash r1 ON (l1.l_custkey = r1.r_custkey) ORDER BY 1,2; LOG: join order: [ "multi_outer_join_left_hash" ][ local partition join "multi_outer_join_right_hash" ] l_custkey | r_custkey -----------+----------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 11 12 | 12 13 | 13 14 | 14 15 | 15 21 | 21 22 | 22 23 | 23 24 | 24 25 | 25 26 | 26 27 | 27 28 | 28 29 | 29 30 | 30 | 16 | 17 | 18 | 19 | 20 (30 rows) -- full outer join + anti (right) should work with 1-1 matched shards SELECT l_custkey, r_custkey FROM multi_outer_join_left_hash l1 FULL JOIN multi_outer_join_right_hash r1 ON (l1.l_custkey = r1.r_custkey) WHERE r_custkey is NULL ORDER BY 1; LOG: join order: [ "multi_outer_join_left_hash" ][ local partition join "multi_outer_join_right_hash" ] l_custkey | r_custkey -----------+----------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | (10 rows) -- full outer join + anti (left) should work with 1-1 matched shards SELECT l_custkey, r_custkey FROM multi_outer_join_left_hash l1 FULL JOIN multi_outer_join_right_hash r1 ON (l1.l_custkey = r1.r_custkey) WHERE l_custkey is NULL ORDER BY 2; LOG: join order: [ "multi_outer_join_left_hash" ][ local partition join "multi_outer_join_right_hash" ] l_custkey | r_custkey -----------+----------- | 16 | 17 | 18 | 19 | 20 (5 rows) -- full outer join + anti (both) should work with 1-1 matched shards SELECT l_custkey, r_custkey FROM multi_outer_join_left_hash l1 FULL JOIN multi_outer_join_right_hash r1 ON (l1.l_custkey = r1.r_custkey) WHERE l_custkey is NULL or r_custkey is NULL ORDER BY 1,2 DESC; LOG: join order: [ "multi_outer_join_left_hash" ][ local partition join "multi_outer_join_right_hash" ] l_custkey | r_custkey -----------+----------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | | 20 | 19 | 18 | 17 | 16 (15 rows) -- full outer join should error out for mismatched shards SELECT l_custkey, t_custkey FROM multi_outer_join_left_hash l1 FULL JOIN multi_outer_join_third_reference t1 ON (l1.l_custkey = t1.t_custkey); ERROR: cannot run outer join query if join is not on the partition column DETAIL: Outer joins requiring repartitioning are not supported. -- inner join + single shard left join should work SELECT l_custkey, r_custkey, t_custkey FROM multi_outer_join_left_hash l1 INNER JOIN multi_outer_join_right_hash r1 ON (l1.l_custkey = r1.r_custkey) LEFT JOIN multi_outer_join_third_reference t1 ON (r1.r_custkey = t1.t_custkey) ORDER BY 1; LOG: join order: [ "multi_outer_join_left_hash" ][ local partition join "multi_outer_join_right_hash" ][ reference join "multi_outer_join_third_reference" ] l_custkey | r_custkey | t_custkey -----------+-----------+----------- 11 | 11 | 11 12 | 12 | 12 13 | 13 | 13 14 | 14 | 14 15 | 15 | 15 21 | 21 | 21 22 | 22 | 22 23 | 23 | 23 24 | 24 | 24 25 | 25 | 25 26 | 26 | 26 27 | 27 | 27 28 | 28 | 28 29 | 29 | 29 30 | 30 | 30 (15 rows) -- inner (broadcast) join + 2 shards left (local) join should work SELECT l_custkey, t_custkey, r_custkey FROM multi_outer_join_left_hash l1 INNER JOIN multi_outer_join_third_reference t1 ON (l1.l_custkey = t1.t_custkey) LEFT JOIN multi_outer_join_right_hash r1 ON (l1.l_custkey = r1.r_custkey) ORDER BY 1,2,3; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_third_reference" ][ local partition join "multi_outer_join_right_hash" ] l_custkey | t_custkey | r_custkey -----------+-----------+----------- 1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 5 | 5 | 6 | 6 | 7 | 7 | 8 | 8 | 9 | 9 | 10 | 10 | 11 | 11 | 11 12 | 12 | 12 13 | 13 | 13 14 | 14 | 14 15 | 15 | 15 21 | 21 | 21 22 | 22 | 22 23 | 23 | 23 24 | 24 | 24 25 | 25 | 25 26 | 26 | 26 27 | 27 | 27 28 | 28 | 28 29 | 29 | 29 30 | 30 | 30 (25 rows) -- inner (local) join + 2 shards left (dual partition) join should error out SELECT t_custkey, l_custkey, r_custkey FROM multi_outer_join_third_reference t1 INNER JOIN multi_outer_join_left_hash l1 ON (l1.l_custkey = t1.t_custkey) LEFT JOIN multi_outer_join_right_reference r1 ON (l1.l_custkey = r1.r_custkey); ERROR: cannot run outer join query if join is not on the partition column DETAIL: Outer joins requiring repartitioning are not supported. -- inner (local) join + 2 shards left (dual partition) join should work SELECT l_custkey, t_custkey, r_custkey FROM multi_outer_join_left_hash l1 INNER JOIN multi_outer_join_third_reference t1 ON (l1.l_custkey = t1.t_custkey) LEFT JOIN multi_outer_join_right_hash r1 ON (l1.l_custkey = r1.r_custkey) ORDER BY 1,2,3; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_third_reference" ][ local partition join "multi_outer_join_right_hash" ] l_custkey | t_custkey | r_custkey -----------+-----------+----------- 1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 5 | 5 | 6 | 6 | 7 | 7 | 8 | 8 | 9 | 9 | 10 | 10 | 11 | 11 | 11 12 | 12 | 12 13 | 13 | 13 14 | 14 | 14 15 | 15 | 15 21 | 21 | 21 22 | 22 | 22 23 | 23 | 23 24 | 24 | 24 25 | 25 | 25 26 | 26 | 26 27 | 27 | 27 28 | 28 | 28 29 | 29 | 29 30 | 30 | 30 (25 rows) -- inner (broadcast) join + 2 shards left (local) + anti join should work SELECT l_custkey, t_custkey, r_custkey FROM multi_outer_join_left_hash l1 INNER JOIN multi_outer_join_third_reference t1 ON (l1.l_custkey = t1.t_custkey) LEFT JOIN multi_outer_join_right_hash r1 ON (l1.l_custkey = r1.r_custkey) WHERE r_custkey is NULL ORDER BY 1; LOG: join order: [ "multi_outer_join_left_hash" ][ reference join "multi_outer_join_third_reference" ][ local partition join "multi_outer_join_right_hash" ] l_custkey | t_custkey | r_custkey -----------+-----------+----------- 1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 5 | 5 | 6 | 6 | 7 | 7 | 8 | 8 | 9 | 9 | 10 | 10 | (10 rows) -- Test joinExpr aliases by performing an outer-join. SELECT t_custkey FROM (multi_outer_join_right_hash r1 LEFT OUTER JOIN multi_outer_join_left_hash l1 ON (l1.l_custkey = r1.r_custkey)) AS test(c_custkey, c_nationkey) INNER JOIN multi_outer_join_third_reference t1 ON (test.c_custkey = t1.t_custkey) ORDER BY 1; LOG: join order: [ "multi_outer_join_right_hash" ][ local partition join "multi_outer_join_left_hash" ][ reference join "multi_outer_join_third_reference" ] t_custkey ----------- 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 (20 rows) -- flattened out subqueries with outer joins are not supported SELECT l1.l_custkey, count(*) as cnt FROM ( SELECT l_custkey, l_nationkey FROM multi_outer_join_left_hash WHERE l_comment like '%a%' ) l1 LEFT JOIN ( SELECT r_custkey, r_name FROM multi_outer_join_right_reference WHERE r_comment like '%b%' ) l2 ON l1.l_custkey = l2.r_custkey GROUP BY l1.l_custkey ORDER BY cnt DESC, l1.l_custkey DESC LIMIT 20; ERROR: cannot perform distributed planning on this query DETAIL: Subqueries in outer joins are not supported -- full join among reference tables should go thourgh router planner SELECT t_custkey, r_custkey FROM multi_outer_join_right_reference FULL JOIN multi_outer_join_third_reference ON (t_custkey = r_custkey) ORDER BY 1; t_custkey | r_custkey -----------+----------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 11 12 | 12 13 | 13 14 | 14 15 | 15 16 | 16 17 | 17 18 | 18 19 | 19 20 | 20 21 | 21 22 | 22 23 | 23 24 | 24 25 | 25 26 | 26 27 | 27 28 | 28 29 | 29 30 | 30 (30 rows) -- DROP unused tables to clean up workspace DROP TABLE multi_outer_join_left_hash; DROP TABLE multi_outer_join_right_reference; DROP TABLE multi_outer_join_third_reference; DROP TABLE multi_outer_join_right_hash;