Remove assertion for subqueries in WHERE clause ANDed with FALSE

In the code, we had the assumption that if restriction information
is NULL, it means that we cannot have any disributetd tables in
the subquery.

However, for subqueries in WHERE clause, that is not the case when
the subquery is ANDed with FALSE. In that case, Citus operates
on the originalQuery (which doesn't go through the standard_planner()),
and rely on the restriction information generated by standard_plannner().
As Postgres is smart enough to no generate restriction information for
subqueries ANDed with FALSE, we hit the assertion.
pull/3816/head
Onder Kalaci 2020-05-04 10:52:15 +02:00
parent 6bcf6d3411
commit f9d4a9cf38
3 changed files with 96 additions and 3 deletions

View File

@ -191,12 +191,16 @@ SubqueryColocated(Query *subquery, ColocatedJoinChecker *checker)
/*
* There are no relations in the input subquery, such as a subquery
* that consist of only intermediate results or without FROM
* clause.
* clause or subquery in WHERE clause anded with FALSE.
*
* Note that for the subquery in WHERE clause, the input original
* subquery (a.k.a., which didn't go through standard_planner()) may
* contain distributed relations, but postgres is smart enough to
* not generate the restriction information. That's the reason for
* not asserting non-existence of distributed relations.
*/
if (list_length(filteredRestrictionList) == 0)
{
Assert(!FindNodeCheck((Node *) subquery, IsDistributedTableRTE));
return true;
}

View File

@ -634,6 +634,64 @@ DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT generate_seri
3
(3 rows)
-- non-colocated subquery in WHERE clause ANDed with false
SELECT count(*)
FROM users_Table
WHERE (FALSE AND EXISTS (SELECT * FROM events_table));
count
---------------------------------------------------------------------
0
(1 row)
-- multiple non-colocated subqueries in WHERE clause ANDed with false
SELECT count(*)
FROM users_Table
WHERE value_1 IN
(SELECT value_1
FROM users_Table) OR (FALSE AND EXISTS (SELECT * FROM events_table));
DEBUG: generating subplan XXX_1 for subquery SELECT value_1 FROM public.users_table
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM public.users_table WHERE ((value_1 OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.value_1 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value_1 integer))) OR (false AND (EXISTS (SELECT events_table.user_id, events_table."time", events_table.event_type, events_table.value_2, events_table.value_3, events_table.value_4 FROM public.events_table))))
count
---------------------------------------------------------------------
101
(1 row)
-- multiple non-colocated subqueries in WHERE clause ANDed with false
SELECT count(*)
FROM users_Table
WHERE value_1 IN
(SELECT value_1
FROM users_Table) AND (FALSE AND EXISTS (SELECT * FROM events_table));
count
---------------------------------------------------------------------
0
(1 row)
-- non-colocated subquery in WHERE clause ANDed with true
SELECT count(*)
FROM users_Table
WHERE (TRUE AND EXISTS (SELECT * FROM events_table));
DEBUG: generating subplan XXX_1 for subquery SELECT user_id, "time", event_type, value_2, value_3, value_4 FROM public.events_table
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM public.users_table WHERE (true AND (EXISTS (SELECT intermediate_result.user_id, intermediate_result."time", intermediate_result.event_type, intermediate_result.value_2, intermediate_result.value_3, intermediate_result.value_4 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, "time" timestamp without time zone, event_type integer, value_2 integer, value_3 double precision, value_4 bigint))))
count
---------------------------------------------------------------------
101
(1 row)
-- multiple non-colocated subqueries in WHERE clause ANDed with true
SELECT count(*)
FROM users_Table
WHERE value_1 IN
(SELECT value_1
FROM users_Table) OR (EXISTS (SELECT * FROM events_table));
DEBUG: generating subplan XXX_1 for subquery SELECT value_1 FROM public.users_table
DEBUG: generating subplan XXX_2 for subquery SELECT user_id, "time", event_type, value_2, value_3, value_4 FROM public.events_table
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM public.users_table WHERE ((value_1 OPERATOR(pg_catalog.=) ANY (SELECT intermediate_result.value_1 FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value_1 integer))) OR (EXISTS (SELECT intermediate_result.user_id, intermediate_result."time", intermediate_result.event_type, intermediate_result.value_2, intermediate_result.value_3, intermediate_result.value_4 FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(user_id integer, "time" timestamp without time zone, event_type integer, value_2 integer, value_3 double precision, value_4 bigint))))
count
---------------------------------------------------------------------
101
(1 row)
-- Local tables also planned recursively, so using it as part of the FROM clause
-- make the clause recurring
CREATE TABLE local_table(id int, value_1 int);

View File

@ -471,6 +471,37 @@ IN
ORDER BY
generate_series ASC;
-- non-colocated subquery in WHERE clause ANDed with false
SELECT count(*)
FROM users_Table
WHERE (FALSE AND EXISTS (SELECT * FROM events_table));
-- multiple non-colocated subqueries in WHERE clause ANDed with false
SELECT count(*)
FROM users_Table
WHERE value_1 IN
(SELECT value_1
FROM users_Table) OR (FALSE AND EXISTS (SELECT * FROM events_table));
-- multiple non-colocated subqueries in WHERE clause ANDed with false
SELECT count(*)
FROM users_Table
WHERE value_1 IN
(SELECT value_1
FROM users_Table) AND (FALSE AND EXISTS (SELECT * FROM events_table));
-- non-colocated subquery in WHERE clause ANDed with true
SELECT count(*)
FROM users_Table
WHERE (TRUE AND EXISTS (SELECT * FROM events_table));
-- multiple non-colocated subqueries in WHERE clause ANDed with true
SELECT count(*)
FROM users_Table
WHERE value_1 IN
(SELECT value_1
FROM users_Table) OR (EXISTS (SELECT * FROM events_table));
-- Local tables also planned recursively, so using it as part of the FROM clause
-- make the clause recurring
CREATE TABLE local_table(id int, value_1 int);