aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_utilcmd.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-06-18 11:22:58 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-06-18 11:22:58 -0400
commit7c337b6b527b7052e6a751f966d5734c56f668b5 (patch)
tree6f9efd562b298171456e1cbae1b137effcd56f1b /src/backend/parser/parse_utilcmd.c
parent0a4efdc7ebf2584257b166c87e82797eb92815b5 (diff)
downloadpostgresql-7c337b6b527b7052e6a751f966d5734c56f668b5.tar.gz
postgresql-7c337b6b527b7052e6a751f966d5734c56f668b5.zip
Centralize the logic for protective copying of utility statements.
In the "simple Query" code path, it's fine for parse analysis or execution of a utility statement to scribble on the statement's node tree, since that'll just be thrown away afterwards. However it's not fine if the node tree is in the plan cache, as then it'd be corrupted for subsequent executions. Up to now we've dealt with that by having individual utility-statement functions apply copyObject() if they were going to modify the tree. But that's prone to errors of omission. Bug #17053 from Charles Samborski shows that CREATE/ALTER DOMAIN didn't get this memo, and can crash if executed repeatedly from plan cache. In the back branches, we'll just apply a narrow band-aid for that, but in HEAD it seems prudent to have a more principled fix that will close off the possibility of other similar bugs in future. Hence, let's hoist the responsibility for doing copyObject up into ProcessUtility from its children, thus ensuring that it happens for all utility statement types. Also, modify ProcessUtility's API so that its callers can tell it whether a copy step is necessary. It turns out that in all cases, the immediate caller knows whether the node tree is transient, so this doesn't involve a huge amount of code thrashing. In this way, while we lose a little bit in the execute-from-cache code path due to sometimes copying node trees that wouldn't be mutated anyway, we gain something in the simple-Query code path by not copying throwaway node trees. Statements that are complex enough to be expensive to copy are almost certainly ones that would have to be copied anyway, so the loss in the cache code path shouldn't be much. (Note that this whole problem applies only to utility statements. Optimizable statements don't have the issue because we long ago made the executor treat Plan trees as read-only. Perhaps someday we will make utility statement execution act likewise, but I'm not holding my breath.) Discussion: https://postgr.es/m/931771.1623893989@sss.pgh.pa.us Discussion: https://postgr.es/m/17053-3ca3f501bbc212b4@postgresql.org
Diffstat (limited to 'src/backend/parser/parse_utilcmd.c')
-rw-r--r--src/backend/parser/parse_utilcmd.c36
1 files changed, 2 insertions, 34 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index c9708e38f46..81d3e7990c6 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -11,10 +11,6 @@
* Hence these functions are now called at the start of execution of their
* respective utility commands.
*
- * NOTE: in general we must avoid scribbling on the passed-in raw parse
- * tree, since it might be in a plan cache. The simplest solution is
- * a quick copyObject() call before manipulating the query tree.
- *
*
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
@@ -177,12 +173,6 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
Oid existing_relid;
ParseCallbackState pcbstate;
- /*
- * We must not scribble on the passed-in CreateStmt, so copy it. (This is
- * overkill, but easy.)
- */
- stmt = copyObject(stmt);
-
/* Set up pstate */
pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString;
@@ -2824,12 +2814,6 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
if (stmt->transformed)
return stmt;
- /*
- * We must not scribble on the passed-in IndexStmt, so copy it. (This is
- * overkill, but easy.)
- */
- stmt = copyObject(stmt);
-
/* Set up pstate */
pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString;
@@ -2925,12 +2909,6 @@ transformStatsStmt(Oid relid, CreateStatsStmt *stmt, const char *queryString)
if (stmt->transformed)
return stmt;
- /*
- * We must not scribble on the passed-in CreateStatsStmt, so copy it.
- * (This is overkill, but easy.)
- */
- stmt = copyObject(stmt);
-
/* Set up pstate */
pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString;
@@ -2993,9 +2971,6 @@ transformStatsStmt(Oid relid, CreateStatsStmt *stmt, const char *queryString)
*
* actions and whereClause are output parameters that receive the
* transformed results.
- *
- * Note that we must not scribble on the passed-in RuleStmt, so we do
- * copyObject() on the actions and WHERE clause.
*/
void
transformRuleStmt(RuleStmt *stmt, const char *queryString,
@@ -3070,7 +3045,7 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
/* take care of the where clause */
*whereClause = transformWhereClause(pstate,
- (Node *) copyObject(stmt->whereClause),
+ stmt->whereClause,
EXPR_KIND_WHERE,
"WHERE");
/* we have to fix its collations too */
@@ -3142,8 +3117,7 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
addNSItemToQuery(sub_pstate, newnsitem, false, true, false);
/* Transform the rule action statement */
- top_subqry = transformStmt(sub_pstate,
- (Node *) copyObject(action));
+ top_subqry = transformStmt(sub_pstate, action);
/*
* We cannot support utility-statement actions (eg NOTIFY) with
@@ -3325,12 +3299,6 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
AlterTableCmd *newcmd;
ParseNamespaceItem *nsitem;
- /*
- * We must not scribble on the passed-in AlterTableStmt, so copy it. (This
- * is overkill, but easy.)
- */
- stmt = copyObject(stmt);
-
/* Caller is responsible for locking the relation */
rel = relation_open(relid, NoLock);
tupdesc = RelationGetDescr(rel);