From 544b6c47163231759d780c6efb1fe4416d064b55 Mon Sep 17 00:00:00 2001 From: Naisila Puka <37271756+naisila@users.noreply.github.com> Date: Wed, 27 Aug 2025 22:31:22 +0300 Subject: [PATCH] Add GUC for queries with outer joins and pseudoconstant quals (#8163) Users can turn on this GUC at their own risk. --- .../distributed/planner/recursive_planning.c | 3 +- src/backend/distributed/shared_library_init.c | 17 +++++++++ src/include/distributed/recursive_planning.h | 1 + src/test/regress/expected/pg17.out | 35 +++++++++++++++++ src/test/regress/expected/pg17_0.out | 38 +++++++++++++++++++ src/test/regress/sql/pg17.sql | 28 ++++++++++++++ 6 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/backend/distributed/planner/recursive_planning.c b/src/backend/distributed/planner/recursive_planning.c index 856b09b3c..07aa442b0 100644 --- a/src/backend/distributed/planner/recursive_planning.c +++ b/src/backend/distributed/planner/recursive_planning.c @@ -97,6 +97,7 @@ #include "distributed/version_compat.h" bool EnableRecurringOuterJoinPushdown = true; +bool EnableOuterJoinsWithPseudoconstantQualsPrePG17 = false; /* * RecursivePlanningContext is used to recursively plan subqueries @@ -509,7 +510,7 @@ ShouldRecursivelyPlanOuterJoins(Query *query, RecursivePlanningContext *context) bool hasOuterJoin = context->plannerRestrictionContext->joinRestrictionContext->hasOuterJoin; #if PG_VERSION_NUM < PG_VERSION_17 - if (!hasOuterJoin) + if (!EnableOuterJoinsWithPseudoconstantQualsPrePG17 && !hasOuterJoin) { /* * PG15 commit d1ef5631e620f9a5b6480a32bb70124c857af4f1 diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index 0ad977d30..c3bd09f17 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -1480,6 +1480,23 @@ RegisterCitusConfigVariables(void) GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE, NULL, NULL, NULL); + DefineCustomBoolVariable( + "citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17", + gettext_noop("Enables running distributed queries with outer joins " + "and pseudoconstant quals pre PG17."), + gettext_noop("Set to false by default. If set to true, enables " + "running distributed queries with outer joins and " + "pseudoconstant quals, at user's own risk, because " + "pre PG17, Citus doesn't have access to " + "set_join_pathlist_hook, which doesn't guarantee correct" + "query results. Note that in PG17+, this GUC has no effect" + "and the user can run such queries"), + &EnableOuterJoinsWithPseudoconstantQualsPrePG17, + false, + PGC_USERSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); + DefineCustomBoolVariable( "citus.enable_recurring_outer_join_pushdown", gettext_noop("Enables outer join pushdown for recurring relations."), diff --git a/src/include/distributed/recursive_planning.h b/src/include/distributed/recursive_planning.h index 219e8b745..dec8916bf 100644 --- a/src/include/distributed/recursive_planning.h +++ b/src/include/distributed/recursive_planning.h @@ -22,6 +22,7 @@ #include "distributed/relation_restriction_equivalence.h" extern bool EnableRecurringOuterJoinPushdown; +extern bool EnableOuterJoinsWithPseudoconstantQualsPrePG17; typedef struct RecursivePlanningContextInternal RecursivePlanningContext; typedef struct RangeTblEntryIndex diff --git a/src/test/regress/expected/pg17.out b/src/test/regress/expected/pg17.out index a2a590a94..4b28413b4 100644 --- a/src/test/regress/expected/pg17.out +++ b/src/test/regress/expected/pg17.out @@ -422,6 +422,19 @@ where (exists (select * from t4)) order by 1, 2, 3; | | 1 | Tue Mar 26 17:36:53 2024 (2 rows) +SET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 TO true; +-- wrong result pre-pg17 +select * from + (t0 full outer join t3 + on (t0.c3 = t3.c26 )) +where (exists (select * from t4)) order by 1, 2, 3; + vkey | c3 | vkey | c26 +--------------------------------------------------------------------- + 13 | Wed Oct 23 15:34:50 2019 | | + | | 1 | Tue Mar 26 17:36:53 2024 +(2 rows) + +RESET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17; -- issue https://github.com/citusdata/citus/issues/7696 create table t1 ( vkey int4 ); create table t2 ( vkey int4 ); @@ -456,6 +469,16 @@ where not((85) in (select 1 from t2)); 5 | (1 row) +SET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 TO true; +-- wrong result pre-pg17 +select * from (t2 full outer join t1 on(t2.vkey = t1.vkey )) +where not((85) in (select 1 from t2)); + vkey | vkey +--------------------------------------------------------------------- + 5 | +(1 row) + +RESET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17; -- issue https://github.com/citusdata/citus/issues/7698 create table t5 ( vkey int4, c10 int4 ); create table t6 ( vkey int4 ); @@ -489,6 +512,18 @@ where exists (select * from t6); 1 (1 row) +SET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 TO true; +-- wrong result pre-pg17 +select t6.vkey +from (t5 right outer join t6 + on (t5.c10 = t6.vkey)) +where exists (select * from t6); + vkey +--------------------------------------------------------------------- + 1 +(1 row) + +RESET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17; -- issue https://github.com/citusdata/citus/issues/7119 -- this test was removed in -- https://github.com/citusdata/citus/commit/a5ce601c0 diff --git a/src/test/regress/expected/pg17_0.out b/src/test/regress/expected/pg17_0.out index c29cbdab8..970fbf21f 100644 --- a/src/test/regress/expected/pg17_0.out +++ b/src/test/regress/expected/pg17_0.out @@ -374,6 +374,20 @@ where (exists (select * from t4)) order by 1, 2, 3; ERROR: Distributed queries with outer joins and pseudoconstant quals are not supported in PG15 and PG16. DETAIL: PG15 and PG16 disallow replacing joins with scans when the query has pseudoconstant quals HINT: Consider upgrading your PG version to PG17+ +SET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 TO true; +-- wrong result pre-pg17 +select * from + (t0 full outer join t3 + on (t0.c3 = t3.c26 )) +where (exists (select * from t4)) order by 1, 2, 3; + vkey | c3 | vkey | c26 +--------------------------------------------------------------------- + 13 | Wed Oct 23 15:34:50 2019 | | + | | 1 | Tue Mar 26 17:36:53 2024 + | | 1 | Tue Mar 26 17:36:53 2024 +(3 rows) + +RESET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17; -- issue https://github.com/citusdata/citus/issues/7696 create table t1 ( vkey int4 ); create table t2 ( vkey int4 ); @@ -406,6 +420,17 @@ where not((85) in (select 1 from t2)); ERROR: Distributed queries with outer joins and pseudoconstant quals are not supported in PG15 and PG16. DETAIL: PG15 and PG16 disallow replacing joins with scans when the query has pseudoconstant quals HINT: Consider upgrading your PG version to PG17+ +SET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 TO true; +-- wrong result pre-pg17 +select * from (t2 full outer join t1 on(t2.vkey = t1.vkey )) +where not((85) in (select 1 from t2)); + vkey | vkey +--------------------------------------------------------------------- + 5 | + 5 | +(2 rows) + +RESET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17; -- issue https://github.com/citusdata/citus/issues/7698 create table t5 ( vkey int4, c10 int4 ); create table t6 ( vkey int4 ); @@ -437,6 +462,19 @@ where exists (select * from t6); ERROR: Distributed queries with outer joins and pseudoconstant quals are not supported in PG15 and PG16. DETAIL: PG15 and PG16 disallow replacing joins with scans when the query has pseudoconstant quals HINT: Consider upgrading your PG version to PG17+ +SET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 TO true; +-- wrong result pre-pg17 +select t6.vkey +from (t5 right outer join t6 + on (t5.c10 = t6.vkey)) +where exists (select * from t6); + vkey +--------------------------------------------------------------------- + 1 + 1 +(2 rows) + +RESET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17; -- issue https://github.com/citusdata/citus/issues/7119 -- this test was removed in -- https://github.com/citusdata/citus/commit/a5ce601c0 diff --git a/src/test/regress/sql/pg17.sql b/src/test/regress/sql/pg17.sql index 9a3979bee..3bcbc07b7 100644 --- a/src/test/regress/sql/pg17.sql +++ b/src/test/regress/sql/pg17.sql @@ -220,6 +220,16 @@ select * from on (t0.c3 = t3.c26 )) where (exists (select * from t4)) order by 1, 2, 3; +SET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 TO true; + +-- wrong result pre-pg17 +select * from + (t0 full outer join t3 + on (t0.c3 = t3.c26 )) +where (exists (select * from t4)) order by 1, 2, 3; + +RESET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17; + -- issue https://github.com/citusdata/citus/issues/7696 create table t1 ( vkey int4 ); create table t2 ( vkey int4 ); @@ -234,6 +244,14 @@ SELECT create_reference_table('t2'); select * from (t2 full outer join t1 on(t2.vkey = t1.vkey )) where not((85) in (select 1 from t2)); +SET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 TO true; + +-- wrong result pre-pg17 +select * from (t2 full outer join t1 on(t2.vkey = t1.vkey )) +where not((85) in (select 1 from t2)); + +RESET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17; + -- issue https://github.com/citusdata/citus/issues/7698 create table t5 ( vkey int4, c10 int4 ); create table t6 ( vkey int4 ); @@ -252,6 +270,16 @@ from (t5 right outer join t6 on (t5.c10 = t6.vkey)) where exists (select * from t6); +SET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17 TO true; + +-- wrong result pre-pg17 +select t6.vkey +from (t5 right outer join t6 + on (t5.c10 = t6.vkey)) +where exists (select * from t6); + +RESET citus.enable_outer_joins_with_pseudoconstant_quals_pre_pg17; + -- issue https://github.com/citusdata/citus/issues/7119 -- this test was removed in -- https://github.com/citusdata/citus/commit/a5ce601c0