diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index c4e1967f12..6da0dcd61c 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -3508,8 +3508,10 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, Assert(!contain_window_function(qual)); /* - * Examine all Vars used in clause; since it's a restriction clause, all - * such Vars must refer to subselect output columns. + * Examine all Vars used in clause. Since it's a restriction clause, all + * such Vars must refer to subselect output columns ... unless this is + * part of a LATERAL subquery, in which case there could be lateral + * references. */ vars = pull_var_clause(qual, PVC_INCLUDE_PLACEHOLDERS); foreach(vl, vars) @@ -3529,7 +3531,19 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, break; } - Assert(var->varno == rti); + /* + * Punt if we find any lateral references. It would be safe to push + * these down, but we'd have to convert them into outer references, + * which subquery_push_qual lacks the infrastructure to do. The case + * arises so seldom that it doesn't seem worth working hard on. + */ + if (var->varno != rti) + { + safe = false; + break; + } + + /* Subqueries have no system columns */ Assert(var->varattno >= 0); /* Check point 4 */ diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index 4c6cd5f146..1c5d80da32 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -1159,6 +1159,59 @@ from int4_tbl; (4,5,6.0) (5 rows) +-- +-- Check for sane handling of a lateral reference in a subquery's quals +-- (most of the complication here is to prevent the test case from being +-- flattened too much) +-- +explain (verbose, costs off) +select * from + int4_tbl i4, + lateral ( + select i4.f1 > 1 as b, 1 as id + from (select random() order by 1) as t1 + union all + select true as b, 2 as id + ) as t2 +where b and f1 >= 0; + QUERY PLAN +-------------------------------------------- + Nested Loop + Output: i4.f1, ((i4.f1 > 1)), (1) + -> Seq Scan on public.int4_tbl i4 + Output: i4.f1 + Filter: (i4.f1 >= 0) + -> Append + -> Subquery Scan on t1 + Output: (i4.f1 > 1), 1 + Filter: (i4.f1 > 1) + -> Sort + Output: (random()) + Sort Key: (random()) + -> Result + Output: random() + -> Result + Output: true, 2 +(16 rows) + +select * from + int4_tbl i4, + lateral ( + select i4.f1 > 1 as b, 1 as id + from (select random() order by 1) as t1 + union all + select true as b, 2 as id + ) as t2 +where b and f1 >= 0; + f1 | b | id +------------+---+---- + 0 | t | 2 + 123456 | t | 1 + 123456 | t | 2 + 2147483647 | t | 1 + 2147483647 | t | 2 +(5 rows) + -- -- Check that volatile quals aren't pushed down past a DISTINCT: -- nextval() should not be called more than the nominal number of times diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql index 893d8d0f62..a56057bd4f 100644 --- a/src/test/regress/sql/subselect.sql +++ b/src/test/regress/sql/subselect.sql @@ -627,6 +627,32 @@ select (select q from ) q ) from int4_tbl; +-- +-- Check for sane handling of a lateral reference in a subquery's quals +-- (most of the complication here is to prevent the test case from being +-- flattened too much) +-- +explain (verbose, costs off) +select * from + int4_tbl i4, + lateral ( + select i4.f1 > 1 as b, 1 as id + from (select random() order by 1) as t1 + union all + select true as b, 2 as id + ) as t2 +where b and f1 >= 0; + +select * from + int4_tbl i4, + lateral ( + select i4.f1 > 1 as b, 1 as id + from (select random() order by 1) as t1 + union all + select true as b, 2 as id + ) as t2 +where b and f1 >= 0; + -- -- Check that volatile quals aren't pushed down past a DISTINCT: -- nextval() should not be called more than the nominal number of times