mirror of https://github.com/citusdata/citus.git
Error out for queries with outer joins and pseudoconstant quals in PG<17 (#7937)
PG15 commit d1ef5631e620f9a5b6480a32bb70124c857af4f1 and PG16 commit 695f5deb7902865901eb2d50a70523af655c3a00 disallow replacing joins with scans in queries with pseudoconstant quals. This commit prevents the set_join_pathlist_hook from being called if any of the join restrictions is a pseudo-constant. So in these cases, citus has no info on the join, never sees that the query has an outer join, and ends up producing an incorrect plan. PG17 fixes this by commit 9e9931d2bf40e2fea447d779c2e133c2c1256ef3 Therefore, we take this extra measure here for PG versions less than 17. hasOuterJoin can never be true when set_join_pathlist_hook is absent.pull/8008/head
parent
902cef3745
commit
e254ced1db
|
@ -84,7 +84,6 @@ int ValuesMaterializationThreshold = 100;
|
|||
/* Local functions forward declarations */
|
||||
static bool JoinTreeContainsSubqueryWalker(Node *joinTreeNode, void *context);
|
||||
static bool IsFunctionOrValuesRTE(Node *node);
|
||||
static bool IsOuterJoinExpr(Node *node);
|
||||
static bool WindowPartitionOnDistributionColumn(Query *query);
|
||||
static DeferredErrorMessage * DeferErrorIfFromClauseRecurs(Query *queryTree);
|
||||
static RecurringTuplesType FromClauseRecurringTupleType(Query *queryTree);
|
||||
|
@ -394,7 +393,7 @@ IsNodeSubquery(Node *node)
|
|||
/*
|
||||
* IsOuterJoinExpr returns whether the given node is an outer join expression.
|
||||
*/
|
||||
static bool
|
||||
bool
|
||||
IsOuterJoinExpr(Node *node)
|
||||
{
|
||||
bool isOuterJoin = false;
|
||||
|
|
|
@ -137,7 +137,8 @@ static bool ShouldRecursivelyPlanNonColocatedSubqueries(Query *subquery,
|
|||
RecursivePlanningContext *
|
||||
context);
|
||||
static bool ContainsSubquery(Query *query);
|
||||
static bool ShouldRecursivelyPlanOuterJoins(RecursivePlanningContext *context);
|
||||
static bool ShouldRecursivelyPlanOuterJoins(Query *query,
|
||||
RecursivePlanningContext *context);
|
||||
static void RecursivelyPlanNonColocatedSubqueries(Query *subquery,
|
||||
RecursivePlanningContext *context);
|
||||
static void RecursivelyPlanNonColocatedJoinWalker(Node *joinNode,
|
||||
|
@ -192,6 +193,10 @@ static Query * CreateOuterSubquery(RangeTblEntry *rangeTableEntry,
|
|||
List *outerSubqueryTargetList);
|
||||
static List * GenerateRequiredColNamesFromTargetList(List *targetList);
|
||||
static char * GetRelationNameAndAliasName(RangeTblEntry *rangeTablentry);
|
||||
#if PG_VERSION_NUM < PG_VERSION_17
|
||||
static bool hasPseudoconstantQuals(
|
||||
RelationRestrictionContext *relationRestrictionContext);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GenerateSubplansForSubqueriesAndCTEs is a wrapper around RecursivelyPlanSubqueriesAndCTEs.
|
||||
|
@ -355,7 +360,7 @@ RecursivelyPlanSubqueriesAndCTEs(Query *query, RecursivePlanningContext *context
|
|||
* result and logical planner can handle the new query since it's of the from
|
||||
* "<recurring> LEFT JOIN <recurring>".
|
||||
*/
|
||||
if (ShouldRecursivelyPlanOuterJoins(context))
|
||||
if (ShouldRecursivelyPlanOuterJoins(query, context))
|
||||
{
|
||||
RecursivelyPlanRecurringTupleOuterJoinWalker((Node *) query->jointree,
|
||||
query, context);
|
||||
|
@ -468,7 +473,7 @@ ContainsSubquery(Query *query)
|
|||
* join(s) that might need to be recursively planned.
|
||||
*/
|
||||
static bool
|
||||
ShouldRecursivelyPlanOuterJoins(RecursivePlanningContext *context)
|
||||
ShouldRecursivelyPlanOuterJoins(Query *query, RecursivePlanningContext *context)
|
||||
{
|
||||
if (!context || !context->plannerRestrictionContext ||
|
||||
!context->plannerRestrictionContext->joinRestrictionContext)
|
||||
|
@ -477,7 +482,37 @@ ShouldRecursivelyPlanOuterJoins(RecursivePlanningContext *context)
|
|||
"planning context")));
|
||||
}
|
||||
|
||||
return context->plannerRestrictionContext->joinRestrictionContext->hasOuterJoin;
|
||||
bool hasOuterJoin =
|
||||
context->plannerRestrictionContext->joinRestrictionContext->hasOuterJoin;
|
||||
#if PG_VERSION_NUM < PG_VERSION_17
|
||||
if (!hasOuterJoin)
|
||||
{
|
||||
/*
|
||||
* PG15 commit d1ef5631e620f9a5b6480a32bb70124c857af4f1
|
||||
* PG16 commit 695f5deb7902865901eb2d50a70523af655c3a00
|
||||
* disallows replacing joins with scans in queries with pseudoconstant quals.
|
||||
* This commit prevents the set_join_pathlist_hook from being called
|
||||
* if any of the join restrictions is a pseudo-constant.
|
||||
* So in these cases, citus has no info on the join, never sees that the query
|
||||
* has an outer join, and ends up producing an incorrect plan.
|
||||
* PG17 fixes this by commit 9e9931d2bf40e2fea447d779c2e133c2c1256ef3
|
||||
* Therefore, we take this extra measure here for PG versions less than 17.
|
||||
* hasOuterJoin can never be true when set_join_pathlist_hook is absent.
|
||||
*/
|
||||
if (hasPseudoconstantQuals(
|
||||
context->plannerRestrictionContext->relationRestrictionContext) &&
|
||||
FindNodeMatchingCheckFunction((Node *) query->jointree, IsOuterJoinExpr))
|
||||
{
|
||||
ereport(ERROR, (errmsg("Distributed queries with outer joins and "
|
||||
"pseudoconstant quals are not supported in PG15 and PG16."),
|
||||
errdetail(
|
||||
"PG15 and PG16 disallow replacing joins with scans when the"
|
||||
" query has pseudoconstant quals"),
|
||||
errhint("Consider upgrading your PG version to PG17+")));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return hasOuterJoin;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2109,7 +2144,6 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry)
|
|||
subquery->targetList = lappend(subquery->targetList, targetEntry);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If tupleDesc is NULL we have 2 different cases:
|
||||
*
|
||||
|
@ -2159,7 +2193,6 @@ TransformFunctionRTE(RangeTblEntry *rangeTblEntry)
|
|||
columnType = list_nth_oid(rangeTblFunction->funccoltypes,
|
||||
targetColumnIndex);
|
||||
}
|
||||
|
||||
/* use the types in the function definition otherwise */
|
||||
else
|
||||
{
|
||||
|
@ -2583,3 +2616,29 @@ GeneratingSubplans(void)
|
|||
{
|
||||
return recursivePlanningDepth > 0;
|
||||
}
|
||||
|
||||
|
||||
#if PG_VERSION_NUM < PG_VERSION_17
|
||||
|
||||
/*
|
||||
* hasPseudoconstantQuals returns true if any of the planner infos in the
|
||||
* relation restriction list of the input relation restriction context
|
||||
* has a pseudoconstant qual
|
||||
*/
|
||||
static bool
|
||||
hasPseudoconstantQuals(RelationRestrictionContext *relationRestrictionContext)
|
||||
{
|
||||
ListCell *objectCell = NULL;
|
||||
foreach(objectCell, relationRestrictionContext->relationRestrictionList)
|
||||
{
|
||||
if (((RelationRestriction *) lfirst(
|
||||
objectCell))->plannerInfo->hasPseudoConstantQuals)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -47,6 +47,7 @@ extern DeferredErrorMessage * DeferErrorIfCannotPushdownSubquery(Query *subquery
|
|||
outerMostQueryHasLimit);
|
||||
extern DeferredErrorMessage * DeferErrorIfUnsupportedUnionQuery(Query *queryTree);
|
||||
extern bool IsJsonTableRTE(RangeTblEntry *rte);
|
||||
extern bool IsOuterJoinExpr(Node *node);
|
||||
|
||||
|
||||
#endif /* QUERY_PUSHDOWN_PLANNING_H */
|
||||
|
|
|
@ -185,6 +185,7 @@ DEPS = {
|
|||
"minimal_schedule", ["remove_coordinator_from_metadata"]
|
||||
),
|
||||
"limit_intermediate_size": TestDeps("base_schedule"),
|
||||
"pg17": TestDeps("minimal_schedule", ["multi_behavioral_analytics_create_table"]),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -343,6 +343,165 @@ NOTICE: drop cascades to 3 other objects
|
|||
DETAIL: drop cascades to table pg17_corr_subq_folding.test
|
||||
drop cascades to table pg17_corr_subq_folding.users
|
||||
drop cascades to table pg17_corr_subq_folding.events
|
||||
-- Queries with outer joins with pseudoconstant quals work only in PG17
|
||||
-- Relevant PG17 commit:
|
||||
-- https://github.com/postgres/postgres/commit/9e9931d2b
|
||||
CREATE SCHEMA pg17_outerjoin;
|
||||
SET search_path to pg17_outerjoin, public;
|
||||
SET citus.next_shard_id TO 20250321;
|
||||
-- issue https://github.com/citusdata/citus/issues/7697
|
||||
create table t0 (vkey int4 , c3 timestamp);
|
||||
create table t3 ( vkey int4 ,c26 timestamp);
|
||||
create table t4 ( vkey int4 );
|
||||
insert into t0 (vkey, c3) values (13,make_timestamp(2019, 10, 23, 15, 34, 50));
|
||||
insert into t3 (vkey,c26) values (1, make_timestamp(2024, 3, 26, 17, 36, 53));
|
||||
insert into t4 (vkey) values (1);
|
||||
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)
|
||||
|
||||
SELECT create_distributed_table('t0', 'vkey');
|
||||
NOTICE: Copying data from local table...
|
||||
NOTICE: copying the data has completed
|
||||
DETAIL: The local data in the table is no longer visible, but is still on disk.
|
||||
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg17_outerjoin.t0$$)
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
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)
|
||||
|
||||
-- issue https://github.com/citusdata/citus/issues/7696
|
||||
create table t1 ( vkey int4 );
|
||||
create table t2 ( vkey int4 );
|
||||
insert into t2 (vkey) values (5);
|
||||
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)
|
||||
|
||||
SELECT create_distributed_table('t1', 'vkey');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT create_reference_table('t2');
|
||||
NOTICE: Copying data from local table...
|
||||
NOTICE: copying the data has completed
|
||||
DETAIL: The local data in the table is no longer visible, but is still on disk.
|
||||
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg17_outerjoin.t2$$)
|
||||
create_reference_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
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)
|
||||
|
||||
-- issue https://github.com/citusdata/citus/issues/7698
|
||||
create table t5 ( vkey int4, c10 int4 );
|
||||
create table t6 ( vkey int4 );
|
||||
insert into t5 (vkey,c10) values (4, -70);
|
||||
insert into t6 (vkey) values (1);
|
||||
select t6.vkey
|
||||
from (t5 right outer join t6
|
||||
on (t5.c10 = t6.vkey))
|
||||
where exists (select * from t6);
|
||||
vkey
|
||||
---------------------------------------------------------------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
SELECT create_distributed_table('t5', 'vkey');
|
||||
NOTICE: Copying data from local table...
|
||||
NOTICE: copying the data has completed
|
||||
DETAIL: The local data in the table is no longer visible, but is still on disk.
|
||||
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg17_outerjoin.t5$$)
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
select t6.vkey
|
||||
from (t5 right outer join t6
|
||||
on (t5.c10 = t6.vkey))
|
||||
where exists (select * from t6);
|
||||
vkey
|
||||
---------------------------------------------------------------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
-- issue https://github.com/citusdata/citus/issues/7119
|
||||
-- this test was removed in
|
||||
-- https://github.com/citusdata/citus/commit/a5ce601c0
|
||||
-- Citus doesn't support it in PG15 and PG16, but supports it in PG17
|
||||
CREATE TABLE users_table_local AS SELECT * FROM users_table;
|
||||
CREATE TABLE events_table_local AS SELECT * FROM events_table;
|
||||
SET client_min_messages TO DEBUG1;
|
||||
-- subquery in FROM -> FROM -> WHERE -> WHERE should be replaced if
|
||||
-- it contains onle local tables
|
||||
-- Later the upper level query is also recursively planned due to LIMIT
|
||||
SELECT user_id, array_length(events_table, 1)
|
||||
FROM (
|
||||
SELECT user_id, array_agg(event ORDER BY time) AS events_table
|
||||
FROM (
|
||||
SELECT
|
||||
u.user_id, e.event_type::text AS event, e.time
|
||||
FROM
|
||||
users_table AS u,
|
||||
events_table AS e
|
||||
WHERE u.user_id = e.user_id AND
|
||||
u.user_id IN
|
||||
(
|
||||
SELECT
|
||||
user_id
|
||||
FROM
|
||||
users_table
|
||||
WHERE value_2 >= 5
|
||||
AND EXISTS (SELECT user_id FROM events_table_local WHERE event_type > 1 AND event_type <= 3 AND value_3 > 1)
|
||||
AND NOT EXISTS (SELECT user_id FROM events_table WHERE event_type > 3 AND event_type <= 4 AND value_3 > 1 AND user_id = users_table.user_id)
|
||||
LIMIT 5
|
||||
)
|
||||
) t
|
||||
GROUP BY user_id
|
||||
) q
|
||||
ORDER BY 2 DESC, 1;
|
||||
DEBUG: generating subplan XXX_1 for subquery SELECT user_id FROM pg17_outerjoin.events_table_local WHERE ((event_type OPERATOR(pg_catalog.>) 1) AND (event_type OPERATOR(pg_catalog.<=) 3) AND (value_3 OPERATOR(pg_catalog.>) (1)::double precision))
|
||||
DEBUG: push down of limit count: 5
|
||||
DEBUG: generating subplan XXX_2 for subquery SELECT user_id FROM public.users_table WHERE ((value_2 OPERATOR(pg_catalog.>=) 5) AND (EXISTS (SELECT intermediate_result.user_id FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer))) AND (NOT (EXISTS (SELECT events_table.user_id FROM public.events_table WHERE ((events_table.event_type OPERATOR(pg_catalog.>) 3) AND (events_table.event_type OPERATOR(pg_catalog.<=) 4) AND (events_table.value_3 OPERATOR(pg_catalog.>) (1)::double precision) AND (events_table.user_id OPERATOR(pg_catalog.=) users_table.user_id)))))) LIMIT 5
|
||||
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT user_id, array_length(events_table, 1) AS array_length FROM (SELECT t.user_id, array_agg(t.event ORDER BY t."time") AS events_table FROM (SELECT u.user_id, (e.event_type)::text AS event, e."time" FROM public.users_table u, public.events_table e WHERE ((u.user_id OPERATOR(pg_catalog.=) e.user_id) AND (u.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))))) t GROUP BY t.user_id) q ORDER BY (array_length(events_table, 1)) DESC, user_id
|
||||
user_id | array_length
|
||||
---------------------------------------------------------------------
|
||||
5 | 364
|
||||
(1 row)
|
||||
|
||||
RESET search_path;
|
||||
SET citus.next_shard_id TO 20240023;
|
||||
SET client_min_messages TO ERROR;
|
||||
DROP SCHEMA pg17_outerjoin CASCADE;
|
||||
RESET client_min_messages;
|
||||
\if :server_version_ge_17
|
||||
\else
|
||||
\q
|
||||
|
|
|
@ -287,6 +287,151 @@ NOTICE: drop cascades to 3 other objects
|
|||
DETAIL: drop cascades to table pg17_corr_subq_folding.test
|
||||
drop cascades to table pg17_corr_subq_folding.users
|
||||
drop cascades to table pg17_corr_subq_folding.events
|
||||
-- Queries with outer joins with pseudoconstant quals work only in PG17
|
||||
-- Relevant PG17 commit:
|
||||
-- https://github.com/postgres/postgres/commit/9e9931d2b
|
||||
CREATE SCHEMA pg17_outerjoin;
|
||||
SET search_path to pg17_outerjoin, public;
|
||||
SET citus.next_shard_id TO 20250321;
|
||||
-- issue https://github.com/citusdata/citus/issues/7697
|
||||
create table t0 (vkey int4 , c3 timestamp);
|
||||
create table t3 ( vkey int4 ,c26 timestamp);
|
||||
create table t4 ( vkey int4 );
|
||||
insert into t0 (vkey, c3) values (13,make_timestamp(2019, 10, 23, 15, 34, 50));
|
||||
insert into t3 (vkey,c26) values (1, make_timestamp(2024, 3, 26, 17, 36, 53));
|
||||
insert into t4 (vkey) values (1);
|
||||
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)
|
||||
|
||||
SELECT create_distributed_table('t0', 'vkey');
|
||||
NOTICE: Copying data from local table...
|
||||
NOTICE: copying the data has completed
|
||||
DETAIL: The local data in the table is no longer visible, but is still on disk.
|
||||
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg17_outerjoin.t0$$)
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
select * from
|
||||
(t0 full outer join t3
|
||||
on (t0.c3 = t3.c26 ))
|
||||
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+
|
||||
-- issue https://github.com/citusdata/citus/issues/7696
|
||||
create table t1 ( vkey int4 );
|
||||
create table t2 ( vkey int4 );
|
||||
insert into t2 (vkey) values (5);
|
||||
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)
|
||||
|
||||
SELECT create_distributed_table('t1', 'vkey');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT create_reference_table('t2');
|
||||
NOTICE: Copying data from local table...
|
||||
NOTICE: copying the data has completed
|
||||
DETAIL: The local data in the table is no longer visible, but is still on disk.
|
||||
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg17_outerjoin.t2$$)
|
||||
create_reference_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
select * from (t2 full outer join t1 on(t2.vkey = t1.vkey ))
|
||||
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+
|
||||
-- issue https://github.com/citusdata/citus/issues/7698
|
||||
create table t5 ( vkey int4, c10 int4 );
|
||||
create table t6 ( vkey int4 );
|
||||
insert into t5 (vkey,c10) values (4, -70);
|
||||
insert into t6 (vkey) values (1);
|
||||
select t6.vkey
|
||||
from (t5 right outer join t6
|
||||
on (t5.c10 = t6.vkey))
|
||||
where exists (select * from t6);
|
||||
vkey
|
||||
---------------------------------------------------------------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
SELECT create_distributed_table('t5', 'vkey');
|
||||
NOTICE: Copying data from local table...
|
||||
NOTICE: copying the data has completed
|
||||
DETAIL: The local data in the table is no longer visible, but is still on disk.
|
||||
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg17_outerjoin.t5$$)
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
select t6.vkey
|
||||
from (t5 right outer join t6
|
||||
on (t5.c10 = t6.vkey))
|
||||
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+
|
||||
-- issue https://github.com/citusdata/citus/issues/7119
|
||||
-- this test was removed in
|
||||
-- https://github.com/citusdata/citus/commit/a5ce601c0
|
||||
-- Citus doesn't support it in PG15 and PG16, but supports it in PG17
|
||||
CREATE TABLE users_table_local AS SELECT * FROM users_table;
|
||||
CREATE TABLE events_table_local AS SELECT * FROM events_table;
|
||||
SET client_min_messages TO DEBUG1;
|
||||
-- subquery in FROM -> FROM -> WHERE -> WHERE should be replaced if
|
||||
-- it contains onle local tables
|
||||
-- Later the upper level query is also recursively planned due to LIMIT
|
||||
SELECT user_id, array_length(events_table, 1)
|
||||
FROM (
|
||||
SELECT user_id, array_agg(event ORDER BY time) AS events_table
|
||||
FROM (
|
||||
SELECT
|
||||
u.user_id, e.event_type::text AS event, e.time
|
||||
FROM
|
||||
users_table AS u,
|
||||
events_table AS e
|
||||
WHERE u.user_id = e.user_id AND
|
||||
u.user_id IN
|
||||
(
|
||||
SELECT
|
||||
user_id
|
||||
FROM
|
||||
users_table
|
||||
WHERE value_2 >= 5
|
||||
AND EXISTS (SELECT user_id FROM events_table_local WHERE event_type > 1 AND event_type <= 3 AND value_3 > 1)
|
||||
AND NOT EXISTS (SELECT user_id FROM events_table WHERE event_type > 3 AND event_type <= 4 AND value_3 > 1 AND user_id = users_table.user_id)
|
||||
LIMIT 5
|
||||
)
|
||||
) t
|
||||
GROUP BY user_id
|
||||
) q
|
||||
ORDER BY 2 DESC, 1;
|
||||
DEBUG: generating subplan XXX_1 for subquery SELECT user_id FROM pg17_outerjoin.events_table_local WHERE ((event_type OPERATOR(pg_catalog.>) 1) AND (event_type OPERATOR(pg_catalog.<=) 3) AND (value_3 OPERATOR(pg_catalog.>) (1)::double precision))
|
||||
ERROR: complex joins are only supported when all distributed tables are co-located and joined on their distribution columns
|
||||
RESET search_path;
|
||||
SET citus.next_shard_id TO 20240023;
|
||||
SET client_min_messages TO ERROR;
|
||||
DROP SCHEMA pg17_outerjoin CASCADE;
|
||||
RESET client_min_messages;
|
||||
\if :server_version_ge_17
|
||||
\else
|
||||
\q
|
||||
|
|
|
@ -170,6 +170,109 @@ RESET client_min_messages;
|
|||
RESET search_path;
|
||||
DROP SCHEMA pg17_corr_subq_folding CASCADE;
|
||||
|
||||
-- Queries with outer joins with pseudoconstant quals work only in PG17
|
||||
-- Relevant PG17 commit:
|
||||
-- https://github.com/postgres/postgres/commit/9e9931d2b
|
||||
|
||||
CREATE SCHEMA pg17_outerjoin;
|
||||
SET search_path to pg17_outerjoin, public;
|
||||
SET citus.next_shard_id TO 20250321;
|
||||
|
||||
-- issue https://github.com/citusdata/citus/issues/7697
|
||||
create table t0 (vkey int4 , c3 timestamp);
|
||||
create table t3 ( vkey int4 ,c26 timestamp);
|
||||
create table t4 ( vkey int4 );
|
||||
insert into t0 (vkey, c3) values (13,make_timestamp(2019, 10, 23, 15, 34, 50));
|
||||
insert into t3 (vkey,c26) values (1, make_timestamp(2024, 3, 26, 17, 36, 53));
|
||||
insert into t4 (vkey) values (1);
|
||||
|
||||
select * from
|
||||
(t0 full outer join t3
|
||||
on (t0.c3 = t3.c26 ))
|
||||
where (exists (select * from t4)) order by 1, 2, 3;
|
||||
|
||||
SELECT create_distributed_table('t0', 'vkey');
|
||||
|
||||
select * from
|
||||
(t0 full outer join t3
|
||||
on (t0.c3 = t3.c26 ))
|
||||
where (exists (select * from t4)) order by 1, 2, 3;
|
||||
|
||||
-- issue https://github.com/citusdata/citus/issues/7696
|
||||
create table t1 ( vkey int4 );
|
||||
create table t2 ( vkey int4 );
|
||||
insert into t2 (vkey) values (5);
|
||||
|
||||
select * from (t2 full outer join t1 on(t2.vkey = t1.vkey ))
|
||||
where not((85) in (select 1 from t2));
|
||||
|
||||
SELECT create_distributed_table('t1', 'vkey');
|
||||
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));
|
||||
|
||||
-- issue https://github.com/citusdata/citus/issues/7698
|
||||
create table t5 ( vkey int4, c10 int4 );
|
||||
create table t6 ( vkey int4 );
|
||||
insert into t5 (vkey,c10) values (4, -70);
|
||||
insert into t6 (vkey) values (1);
|
||||
|
||||
select t6.vkey
|
||||
from (t5 right outer join t6
|
||||
on (t5.c10 = t6.vkey))
|
||||
where exists (select * from t6);
|
||||
|
||||
SELECT create_distributed_table('t5', 'vkey');
|
||||
|
||||
select t6.vkey
|
||||
from (t5 right outer join t6
|
||||
on (t5.c10 = t6.vkey))
|
||||
where exists (select * from t6);
|
||||
|
||||
-- issue https://github.com/citusdata/citus/issues/7119
|
||||
-- this test was removed in
|
||||
-- https://github.com/citusdata/citus/commit/a5ce601c0
|
||||
-- Citus doesn't support it in PG15 and PG16, but supports it in PG17
|
||||
CREATE TABLE users_table_local AS SELECT * FROM users_table;
|
||||
CREATE TABLE events_table_local AS SELECT * FROM events_table;
|
||||
|
||||
SET client_min_messages TO DEBUG1;
|
||||
-- subquery in FROM -> FROM -> WHERE -> WHERE should be replaced if
|
||||
-- it contains onle local tables
|
||||
-- Later the upper level query is also recursively planned due to LIMIT
|
||||
SELECT user_id, array_length(events_table, 1)
|
||||
FROM (
|
||||
SELECT user_id, array_agg(event ORDER BY time) AS events_table
|
||||
FROM (
|
||||
SELECT
|
||||
u.user_id, e.event_type::text AS event, e.time
|
||||
FROM
|
||||
users_table AS u,
|
||||
events_table AS e
|
||||
WHERE u.user_id = e.user_id AND
|
||||
u.user_id IN
|
||||
(
|
||||
SELECT
|
||||
user_id
|
||||
FROM
|
||||
users_table
|
||||
WHERE value_2 >= 5
|
||||
AND EXISTS (SELECT user_id FROM events_table_local WHERE event_type > 1 AND event_type <= 3 AND value_3 > 1)
|
||||
AND NOT EXISTS (SELECT user_id FROM events_table WHERE event_type > 3 AND event_type <= 4 AND value_3 > 1 AND user_id = users_table.user_id)
|
||||
LIMIT 5
|
||||
)
|
||||
) t
|
||||
GROUP BY user_id
|
||||
) q
|
||||
ORDER BY 2 DESC, 1;
|
||||
|
||||
RESET search_path;
|
||||
SET citus.next_shard_id TO 20240023;
|
||||
SET client_min_messages TO ERROR;
|
||||
DROP SCHEMA pg17_outerjoin CASCADE;
|
||||
RESET client_min_messages;
|
||||
|
||||
\if :server_version_ge_17
|
||||
\else
|
||||
\q
|
||||
|
|
Loading…
Reference in New Issue