summaryrefslogtreecommitdiff
path: root/src/backend/tcop/utility.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/tcop/utility.c')
-rw-r--r--src/backend/tcop/utility.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 1a8fc167733..7a2da9dab43 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -476,6 +476,7 @@ CheckRestrictedOperation(const char *cmdname)
*
* pstmt: PlannedStmt wrapper for the utility statement
* queryString: original source text of command
+ * readOnlyTree: if true, pstmt's node tree must not be modified
* context: identifies source of statement (toplevel client command,
* non-toplevel client command, subcommand of a larger utility command)
* params: parameters to use during execution
@@ -501,6 +502,7 @@ CheckRestrictedOperation(const char *cmdname)
void
ProcessUtility(PlannedStmt *pstmt,
const char *queryString,
+ bool readOnlyTree,
ProcessUtilityContext context,
ParamListInfo params,
QueryEnvironment *queryEnv,
@@ -518,11 +520,11 @@ ProcessUtility(PlannedStmt *pstmt,
* call standard_ProcessUtility().
*/
if (ProcessUtility_hook)
- (*ProcessUtility_hook) (pstmt, queryString,
+ (*ProcessUtility_hook) (pstmt, queryString, readOnlyTree,
context, params, queryEnv,
dest, qc);
else
- standard_ProcessUtility(pstmt, queryString,
+ standard_ProcessUtility(pstmt, queryString, readOnlyTree,
context, params, queryEnv,
dest, qc);
}
@@ -541,13 +543,14 @@ ProcessUtility(PlannedStmt *pstmt,
void
standard_ProcessUtility(PlannedStmt *pstmt,
const char *queryString,
+ bool readOnlyTree,
ProcessUtilityContext context,
ParamListInfo params,
QueryEnvironment *queryEnv,
DestReceiver *dest,
QueryCompletion *qc)
{
- Node *parsetree = pstmt->utilityStmt;
+ Node *parsetree;
bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
bool isAtomicContext = (!(context == PROCESS_UTILITY_TOPLEVEL || context == PROCESS_UTILITY_QUERY_NONATOMIC) || IsTransactionBlock());
ParseState *pstate;
@@ -556,6 +559,18 @@ standard_ProcessUtility(PlannedStmt *pstmt,
/* This can recurse, so check for excessive recursion */
check_stack_depth();
+ /*
+ * If the given node tree is read-only, make a copy to ensure that parse
+ * transformations don't damage the original tree. This could be
+ * refactored to avoid making unnecessary copies in more cases, but it's
+ * not clear that it's worth a great deal of trouble over. Statements
+ * that are complex enough to be expensive to copy are exactly the ones
+ * we'd need to copy, so that only marginal savings seem possible.
+ */
+ if (readOnlyTree)
+ pstmt = copyObject(pstmt);
+ parsetree = pstmt->utilityStmt;
+
/* Prohibit read/write commands in read-only states. */
readonly_flags = ClassifyUtilityCommandAsReadOnly(parsetree);
if (readonly_flags != COMMAND_IS_STRICTLY_READ_ONLY &&
@@ -1211,6 +1226,7 @@ ProcessUtilitySlow(ParseState *pstate,
ProcessUtility(wrapper,
queryString,
+ false,
PROCESS_UTILITY_SUBCOMMAND,
params,
NULL,
@@ -1918,6 +1934,7 @@ ProcessUtilityForAlterTable(Node *stmt, AlterTableUtilityContext *context)
ProcessUtility(wrapper,
context->queryString,
+ false,
PROCESS_UTILITY_SUBCOMMAND,
context->params,
context->queryEnv,