aboutsummaryrefslogtreecommitdiff
path: root/src/backend/rewrite/rewriteHandler.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-09-08 12:05:43 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-09-08 12:05:43 -0400
commit1fedbcc7ab26174686cbad7f8b836616c906d267 (patch)
tree67f0b444f1a15ab0a35f6d50965fc259f3d13427 /src/backend/rewrite/rewriteHandler.c
parent2eb09f27db6c5e2e017ac98f208d982486e0edc5 (diff)
downloadpostgresql-1fedbcc7ab26174686cbad7f8b836616c906d267.tar.gz
postgresql-1fedbcc7ab26174686cbad7f8b836616c906d267.zip
Fix rewriter to set hasModifyingCTE correctly on rewritten queries.
If we copy data-modifying CTEs from the original query to a replacement query (from a DO INSTEAD rule), we must set hasModifyingCTE properly in the replacement query. Failure to do this can cause various unpleasantness, such as unsafe usage of parallel plans. The code also neglected to propagate hasRecursive, though that's only cosmetic at the moment. A difficulty arises if the rule action is an INSERT...SELECT. We attach the original query's RTEs and CTEs to the sub-SELECT Query, but data-modifying CTEs are only allowed to appear in the topmost Query. For the moment, throw an error in such cases. It would probably be possible to avoid this error by attaching the CTEs to the top INSERT Query instead; but that would require a bunch of new code to adjust ctelevelsup references. Given the narrowness of the use-case, and the need to back-patch this fix, it does not seem worth the trouble for now. We can revisit this if we get field complaints. Per report from Greg Nancarrow. Back-patch to all supported branches. (The test case added here does not fail before v10, but there are plenty of places checking top-level hasModifyingCTE in 9.6, so I have no doubt that this code change is necessary there too.) Greg Nancarrow and Tom Lane Discussion: https://postgr.es/m/CAJcOf-f68DT=26YAMz_i0+Au3TcLO5oiHY5=fL6Sfuits6r+_w@mail.gmail.com Discussion: https://postgr.es/m/CAJcOf-fAdj=nDKMsRhQzndm-O13NY4dL6xGcEvdX5Xvbbi0V7g@mail.gmail.com
Diffstat (limited to 'src/backend/rewrite/rewriteHandler.c')
-rw-r--r--src/backend/rewrite/rewriteHandler.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index a69d8a3989e..e063077f096 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -530,6 +530,9 @@ rewriteRuleAction(Query *parsetree,
*
* This could possibly be fixed by using some sort of internally
* generated ID, instead of names, to link CTE RTEs to their CTEs.
+ * However, decompiling the results would be quite confusing; note the
+ * merge of hasRecursive flags below, which could change the apparent
+ * semantics of such redundantly-named CTEs.
*/
foreach(lc, parsetree->cteList)
{
@@ -551,6 +554,26 @@ rewriteRuleAction(Query *parsetree,
/* OK, it's safe to combine the CTE lists */
sub_action->cteList = list_concat(sub_action->cteList,
copyObject(parsetree->cteList));
+ /* ... and don't forget about the associated flags */
+ sub_action->hasRecursive |= parsetree->hasRecursive;
+ sub_action->hasModifyingCTE |= parsetree->hasModifyingCTE;
+
+ /*
+ * If rule_action is different from sub_action (i.e., the rule action
+ * is an INSERT...SELECT), then we might have just added some
+ * data-modifying CTEs that are not at the top query level. This is
+ * disallowed by the parser and we mustn't generate such trees here
+ * either, so throw an error.
+ *
+ * Conceivably such cases could be supported by attaching the original
+ * query's CTEs to rule_action not sub_action. But to do that, we'd
+ * have to increment ctelevelsup in RTEs and SubLinks copied from the
+ * original query. For now, it doesn't seem worth the trouble.
+ */
+ if (sub_action->hasModifyingCTE && rule_action != sub_action)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("INSERT...SELECT rule actions are not supported for queries having data-modifying statements in WITH")));
}
/*