mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
Support data-modifying commands (INSERT/UPDATE/DELETE) in WITH.
This patch implements data-modifying WITH queries according to the semantics that the updates all happen with the same command counter value, and in an unspecified order. Therefore one WITH clause can't see the effects of another, nor can the outer query see the effects other than through the RETURNING values. And attempts to do conflicting updates will have unpredictable results. We'll need to document all that. This commit just fixes the code; documentation updates are waiting on author. Marko Tiikkaja and Hitoshi Harada
This commit is contained in:
@ -1801,6 +1801,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
|
||||
bool returning = false;
|
||||
Query *qual_product = NULL;
|
||||
List *rewritten = NIL;
|
||||
ListCell *lc1;
|
||||
|
||||
/*
|
||||
* If the statement is an insert, update, or delete, adjust its targetlist
|
||||
@ -1980,6 +1981,67 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
|
||||
heap_close(rt_entry_relation, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursively process any insert/update/delete statements in WITH clauses
|
||||
*/
|
||||
foreach(lc1, parsetree->cteList)
|
||||
{
|
||||
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc1);
|
||||
Query *ctequery = (Query *) cte->ctequery;
|
||||
List *newstuff;
|
||||
|
||||
Assert(IsA(ctequery, Query));
|
||||
|
||||
if (ctequery->commandType == CMD_SELECT)
|
||||
continue;
|
||||
|
||||
newstuff = RewriteQuery(ctequery, rewrite_events);
|
||||
|
||||
/*
|
||||
* Currently we can only handle unconditional, single-statement DO
|
||||
* INSTEAD rules correctly; we have to get exactly one Query out of
|
||||
* the rewrite operation to stuff back into the CTE node.
|
||||
*/
|
||||
if (list_length(newstuff) == 1)
|
||||
{
|
||||
/* Push the single Query back into the CTE node */
|
||||
ctequery = (Query *) linitial(newstuff);
|
||||
Assert(IsA(ctequery, Query));
|
||||
/* WITH queries should never be canSetTag */
|
||||
Assert(!ctequery->canSetTag);
|
||||
cte->ctequery = (Node *) ctequery;
|
||||
}
|
||||
else if (newstuff == NIL)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH")));
|
||||
}
|
||||
else
|
||||
{
|
||||
ListCell *lc2;
|
||||
|
||||
/* examine queries to determine which error message to issue */
|
||||
foreach(lc2, newstuff)
|
||||
{
|
||||
Query *q = (Query *) lfirst(lc2);
|
||||
|
||||
if (q->querySource == QSRC_QUAL_INSTEAD_RULE)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("conditional DO INSTEAD rules are not supported for data-modifying statements in WITH")));
|
||||
if (q->querySource == QSRC_NON_INSTEAD_RULE)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("DO ALSO rules are not supported for data-modifying statements in WITH")));
|
||||
}
|
||||
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH")));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For INSERTs, the original query is done first; for UPDATE/DELETE, it is
|
||||
* done last. This is needed because update and delete rule actions might
|
||||
@ -2033,6 +2095,12 @@ QueryRewrite(Query *parsetree)
|
||||
bool foundOriginalQuery;
|
||||
Query *lastInstead;
|
||||
|
||||
/*
|
||||
* This function is only applied to top-level original queries
|
||||
*/
|
||||
Assert(parsetree->querySource == QSRC_ORIGINAL);
|
||||
Assert(parsetree->canSetTag);
|
||||
|
||||
/*
|
||||
* Step 1
|
||||
*
|
||||
|
Reference in New Issue
Block a user