aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-10-24 18:42:47 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2017-10-24 18:42:47 -0400
commit896eb5efbdcea5df12e7a464ae9c23dd1e25abd2 (patch)
tree1e4307f598accc9e82653fc6e02993f52861c16d /src/backend/optimizer/plan/planner.c
parenta32c0923b4da7f7df95616aaecbb85ef9f12f93f (diff)
downloadpostgresql-896eb5efbdcea5df12e7a464ae9c23dd1e25abd2.tar.gz
postgresql-896eb5efbdcea5df12e7a464ae9c23dd1e25abd2.zip
In the planner, delete joinaliasvars lists after we're done with them.
Although joinaliasvars lists coming out of the parser are quite simple, those lists can contain arbitrarily complex expressions after subquery pullup. We do not perform expression preprocessing on them, meaning that expressions in those lists will not meet the expectations of later phases of the planner (for example, that they do not contain SubLinks). This had been thought pretty harmless, since we don't intentionally touch those lists in later phases --- but Andreas Seltenreich found a case in which adjust_appendrel_attrs() could recurse into a joinaliasvars list and then die on its assertion that it never sees a SubLink. We considered a couple of localized fixes to prevent that specific case from looking at the joinaliasvars lists, but really this seems like a generic hazard for all expression processing in the planner. Therefore, probably the best answer is to delete the joinaliasvars lists from the parsetree at the end of expression preprocessing, so that there are no reachable expressions that haven't been through preprocessing. The case Andreas found seems to be harmless in non-Assert builds, and so far there are no field reports suggesting that there are user-visible effects in other cases. I considered back-patching this anyway, but it turns out that Andreas' test doesn't fail at all in 9.4-9.6, because in those versions adjust_appendrel_attrs contains code (added in commit 842faa714 and removed again in commit 215b43cdc) to process SubLinks rather than complain about them. Barring discovery of another path by which unprocessed joinaliasvars lists can cause trouble, the most prudent compromise seems to be to patch this into v10 but not further. Patch by me, with thanks to Amit Langote for initial investigation and review. Discussion: https://postgr.es/m/87r2tvt9f1.fsf@ansel.ydns.eu
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ecdd7280eb8..d58635c887c 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -777,6 +777,27 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
}
/*
+ * Now that we are done preprocessing expressions, and in particular done
+ * flattening join alias variables, get rid of the joinaliasvars lists.
+ * They no longer match what expressions in the rest of the tree look
+ * like, because we have not preprocessed expressions in those lists (and
+ * do not want to; for example, expanding a SubLink there would result in
+ * a useless unreferenced subplan). Leaving them in place simply creates
+ * a hazard for later scans of the tree. We could try to prevent that by
+ * using QTW_IGNORE_JOINALIASES in every tree scan done after this point,
+ * but that doesn't sound very reliable.
+ */
+ if (root->hasJoinRTEs)
+ {
+ foreach(l, parse->rtable)
+ {
+ RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
+
+ rte->joinaliasvars = NIL;
+ }
+ }
+
+ /*
* In some cases we may want to transfer a HAVING clause into WHERE. We
* cannot do so if the HAVING clause contains aggregates (obviously) or
* volatile functions (since a HAVING clause is supposed to be executed
@@ -902,11 +923,12 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
/*
* If the query has any join RTEs, replace join alias variables with
- * base-relation variables. We must do this before sublink processing,
- * else sublinks expanded out from join aliases would not get processed.
- * We can skip it in non-lateral RTE functions, VALUES lists, and
- * TABLESAMPLE clauses, however, since they can't contain any Vars of the
- * current query level.
+ * base-relation variables. We must do this first, since any expressions
+ * we may extract from the joinaliasvars lists have not been preprocessed.
+ * For example, if we did this after sublink processing, sublinks expanded
+ * out from join aliases would not get processed. But we can skip this in
+ * non-lateral RTE functions, VALUES lists, and TABLESAMPLE clauses, since
+ * they can't contain any Vars of the current query level.
*/
if (root->hasJoinRTEs &&
!(kind == EXPRKIND_RTFUNC ||