aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/allpaths.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-07-13 20:38:20 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-07-13 20:38:20 -0400
commita742ecf9c63d454ccb107a357288c8ec1444ca12 (patch)
tree13a753cfcc6535c48ce92cac17d28d7edec17b29 /src/backend/optimizer/path/allpaths.c
parentb5b4c0fef9fb905d98f93c1f455397449c6e63a8 (diff)
downloadpostgresql-a742ecf9c63d454ccb107a357288c8ec1444ca12.tar.gz
postgresql-a742ecf9c63d454ccb107a357288c8ec1444ca12.zip
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
Diffstat (limited to 'src/backend/optimizer/path/allpaths.c')
-rw-r--r--src/backend/optimizer/path/allpaths.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index c4e1967f123..6da0dcd61ce 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 */