diff options
Diffstat (limited to 'src/backend/tcop/utility.c')
-rw-r--r-- | src/backend/tcop/utility.c | 23 |
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, |