Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit dc6bb09

Browse filesBrowse files
committed
Cope with lateral references in the quals of a subquery RTE.
The qual pushdown logic assumed that all Vars in a restriction clause must be Vars referencing subquery outputs; but since we introduced LATERAL, it's possible for such a Var to be a lateral reference instead. This led to an assertion failure in debug builds. In a non-debug build, there might be no ill effects (if qual_is_pushdown_safe decided the qual was unsafe anyway), or we could get failures later due to construction of an invalid plan. I've not gone to much length to characterize the possible failures, but at least segfaults in the executor have been observed. Given that this has been busted since 9.3 and it took this long for anybody to notice, I judge that the case isn't worth going to great lengths to optimize. Hence, fix by just teaching qual_is_pushdown_safe that such quals are unsafe to push down, matching the previous behavior when it accidentally didn't fail. Per report from Tom Ellis. Back-patch to all supported branches. Discussion: https://postgr.es/m/20200713175124.GQ8220@cloudinit-builder
1 parent 303322c commit dc6bb09
Copy full SHA for dc6bb09

File tree

Expand file treeCollapse file tree

3 files changed

+96
-3
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+96
-3
lines changed

‎src/backend/optimizer/path/allpaths.c

Copy file name to clipboardExpand all lines: src/backend/optimizer/path/allpaths.c
+17-3Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2599,8 +2599,10 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,
25992599
Assert(!contain_window_function(qual));
26002600

26012601
/*
2602-
* Examine all Vars used in clause; since it's a restriction clause, all
2603-
* such Vars must refer to subselect output columns.
2602+
* Examine all Vars used in clause. Since it's a restriction clause, all
2603+
* such Vars must refer to subselect output columns ... unless this is
2604+
* part of a LATERAL subquery, in which case there could be lateral
2605+
* references.
26042606
*/
26052607
vars = pull_var_clause(qual, PVC_INCLUDE_PLACEHOLDERS);
26062608
foreach(vl, vars)
@@ -2620,7 +2622,19 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,
26202622
break;
26212623
}
26222624

2623-
Assert(var->varno == rti);
2625+
/*
2626+
* Punt if we find any lateral references. It would be safe to push
2627+
* these down, but we'd have to convert them into outer references,
2628+
* which subquery_push_qual lacks the infrastructure to do. The case
2629+
* arises so seldom that it doesn't seem worth working hard on.
2630+
*/
2631+
if (var->varno != rti)
2632+
{
2633+
safe = false;
2634+
break;
2635+
}
2636+
2637+
/* Subqueries have no system columns */
26242638
Assert(var->varattno >= 0);
26252639

26262640
/* Check point 4 */

‎src/test/regress/expected/subselect.out

Copy file name to clipboardExpand all lines: src/test/regress/expected/subselect.out
+53Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,59 @@ from int4_tbl;
931931
(4,5,6.0)
932932
(5 rows)
933933

934+
--
935+
-- Check for sane handling of a lateral reference in a subquery's quals
936+
-- (most of the complication here is to prevent the test case from being
937+
-- flattened too much)
938+
--
939+
explain (verbose, costs off)
940+
select * from
941+
int4_tbl i4,
942+
lateral (
943+
select i4.f1 > 1 as b, 1 as id
944+
from (select random() order by 1) as t1
945+
union all
946+
select true as b, 2 as id
947+
) as t2
948+
where b and f1 >= 0;
949+
QUERY PLAN
950+
--------------------------------------------
951+
Nested Loop
952+
Output: i4.f1, ((i4.f1 > 1)), (1)
953+
-> Seq Scan on public.int4_tbl i4
954+
Output: i4.f1
955+
Filter: (i4.f1 >= 0)
956+
-> Append
957+
-> Subquery Scan on t1
958+
Output: (i4.f1 > 1), 1
959+
Filter: (i4.f1 > 1)
960+
-> Sort
961+
Output: (random())
962+
Sort Key: (random())
963+
-> Result
964+
Output: random()
965+
-> Result
966+
Output: true, 2
967+
(16 rows)
968+
969+
select * from
970+
int4_tbl i4,
971+
lateral (
972+
select i4.f1 > 1 as b, 1 as id
973+
from (select random() order by 1) as t1
974+
union all
975+
select true as b, 2 as id
976+
) as t2
977+
where b and f1 >= 0;
978+
f1 | b | id
979+
------------+---+----
980+
0 | t | 2
981+
123456 | t | 1
982+
123456 | t | 2
983+
2147483647 | t | 1
984+
2147483647 | t | 2
985+
(5 rows)
986+
934987
--
935988
-- Check that volatile quals aren't pushed down past a DISTINCT:
936989
-- nextval() should not be called more than the nominal number of times

‎src/test/regress/sql/subselect.sql

Copy file name to clipboardExpand all lines: src/test/regress/sql/subselect.sql
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,32 @@ select (select q from
498498
) q )
499499
from int4_tbl;
500500

501+
--
502+
-- Check for sane handling of a lateral reference in a subquery's quals
503+
-- (most of the complication here is to prevent the test case from being
504+
-- flattened too much)
505+
--
506+
explain (verbose, costs off)
507+
select * from
508+
int4_tbl i4,
509+
lateral (
510+
select i4.f1 > 1 as b, 1 as id
511+
from (select random() order by 1) as t1
512+
union all
513+
select true as b, 2 as id
514+
) as t2
515+
where b and f1 >= 0;
516+
517+
select * from
518+
int4_tbl i4,
519+
lateral (
520+
select i4.f1 > 1 as b, 1 as id
521+
from (select random() order by 1) as t1
522+
union all
523+
select true as b, 2 as id
524+
) as t2
525+
where b and f1 >= 0;
526+
501527
--
502528
-- Check that volatile quals aren't pushed down past a DISTINCT:
503529
-- nextval() should not be called more than the nominal number of times

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.