diff options
Diffstat (limited to 'src/backend/tcop/utility.c')
-rw-r--r-- | src/backend/tcop/utility.c | 190 |
1 files changed, 110 insertions, 80 deletions
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 127dc862e8d..14921013360 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -72,7 +72,7 @@ ProcessUtility_hook_type ProcessUtility_hook = NULL; /* local function declarations */ static void ProcessUtilitySlow(ParseState *pstate, - Node *parsetree, + PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, @@ -88,35 +88,33 @@ static void ExecDropStmt(DropStmt *stmt, bool isTopLevel); * the query must be *in truth* read-only, because the caller wishes * not to do CommandCounterIncrement for it. * - * Note: currently no need to support Query nodes here + * Note: currently no need to support raw or analyzed queries here */ bool -CommandIsReadOnly(Node *parsetree) +CommandIsReadOnly(PlannedStmt *pstmt) { - if (IsA(parsetree, PlannedStmt)) + Assert(IsA(pstmt, PlannedStmt)); + switch (pstmt->commandType) { - PlannedStmt *stmt = (PlannedStmt *) parsetree; - - switch (stmt->commandType) - { - case CMD_SELECT: - if (stmt->rowMarks != NIL) - return false; /* SELECT FOR [KEY] UPDATE/SHARE */ - else if (stmt->hasModifyingCTE) - return false; /* data-modifying CTE */ - else - return true; - case CMD_UPDATE: - case CMD_INSERT: - case CMD_DELETE: - return false; - default: - elog(WARNING, "unrecognized commandType: %d", - (int) stmt->commandType); - break; - } + case CMD_SELECT: + if (pstmt->rowMarks != NIL) + return false; /* SELECT FOR [KEY] UPDATE/SHARE */ + else if (pstmt->hasModifyingCTE) + return false; /* data-modifying CTE */ + else + return true; + case CMD_UPDATE: + case CMD_INSERT: + case CMD_DELETE: + return false; + case CMD_UTILITY: + /* For now, treat all utility commands as read/write */ + return false; + default: + elog(WARNING, "unrecognized commandType: %d", + (int) pstmt->commandType); + break; } - /* For now, treat all utility commands as read/write */ return false; } @@ -297,7 +295,7 @@ CheckRestrictedOperation(const char *cmdname) * ProcessUtility * general utility function invoker * - * parsetree: the parse tree for the utility statement + * pstmt: PlannedStmt wrapper for the utility statement * queryString: original source text of command * context: identifies source of statement (toplevel client command, * non-toplevel client command, subcommand of a larger utility command) @@ -315,13 +313,15 @@ CheckRestrictedOperation(const char *cmdname) * completionTag may be NULL if caller doesn't want a status string. */ void -ProcessUtility(Node *parsetree, +ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { + Assert(IsA(pstmt, PlannedStmt)); + Assert(pstmt->commandType == CMD_UTILITY); Assert(queryString != NULL); /* required as of 8.4 */ /* @@ -330,11 +330,11 @@ ProcessUtility(Node *parsetree, * call standard_ProcessUtility(). */ if (ProcessUtility_hook) - (*ProcessUtility_hook) (parsetree, queryString, + (*ProcessUtility_hook) (pstmt, queryString, context, params, dest, completionTag); else - standard_ProcessUtility(parsetree, queryString, + standard_ProcessUtility(pstmt, queryString, context, params, dest, completionTag); } @@ -351,13 +351,14 @@ ProcessUtility(Node *parsetree, * which requires being in a valid transaction. */ void -standard_ProcessUtility(Node *parsetree, +standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { + Node *parsetree = pstmt->utilityStmt; bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL); ParseState *pstate; @@ -486,20 +487,10 @@ standard_ProcessUtility(Node *parsetree, /* * Portal (cursor) manipulation - * - * Note: DECLARE CURSOR is processed mostly as a SELECT, and - * therefore what we will get here is a PlannedStmt not a bare - * DeclareCursorStmt. */ - case T_PlannedStmt: - { - PlannedStmt *stmt = (PlannedStmt *) parsetree; - - if (stmt->utilityStmt == NULL || - !IsA(stmt->utilityStmt, DeclareCursorStmt)) - elog(ERROR, "non-DECLARE CURSOR PlannedStmt passed to ProcessUtility"); - PerformCursorOpen(stmt, params, queryString, isTopLevel); - } + case T_DeclareCursorStmt: + PerformCursorOpen((DeclareCursorStmt *) parsetree, params, + queryString, isTopLevel); break; case T_ClosePortalStmt: @@ -545,7 +536,9 @@ standard_ProcessUtility(Node *parsetree, { uint64 processed; - DoCopy(pstate, (CopyStmt *) parsetree, &processed); + DoCopy(pstate, (CopyStmt *) parsetree, + pstmt->stmt_location, pstmt->stmt_len, + &processed); if (completionTag) snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "COPY " UINT64_FORMAT, processed); @@ -554,7 +547,8 @@ standard_ProcessUtility(Node *parsetree, case T_PrepareStmt: CheckRestrictedOperation("PREPARE"); - PrepareQuery((PrepareStmt *) parsetree, queryString); + PrepareQuery((PrepareStmt *) parsetree, queryString, + pstmt->stmt_location, pstmt->stmt_len); break; case T_ExecuteStmt: @@ -808,11 +802,11 @@ standard_ProcessUtility(Node *parsetree, GrantStmt *stmt = (GrantStmt *) parsetree; if (EventTriggerSupportsGrantObjectType(stmt->objtype)) - ProcessUtilitySlow(pstate, parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else - ExecuteGrantStmt((GrantStmt *) parsetree); + ExecuteGrantStmt(stmt); } break; @@ -821,7 +815,7 @@ standard_ProcessUtility(Node *parsetree, DropStmt *stmt = (DropStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->removeType)) - ProcessUtilitySlow(pstate, parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -834,7 +828,7 @@ standard_ProcessUtility(Node *parsetree, RenameStmt *stmt = (RenameStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->renameType)) - ProcessUtilitySlow(pstate, parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -847,7 +841,7 @@ standard_ProcessUtility(Node *parsetree, AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objectType)) - ProcessUtilitySlow(pstate, parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -860,7 +854,7 @@ standard_ProcessUtility(Node *parsetree, AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objectType)) - ProcessUtilitySlow(pstate, parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -873,7 +867,7 @@ standard_ProcessUtility(Node *parsetree, AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objectType)) - ProcessUtilitySlow(pstate, parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -886,11 +880,11 @@ standard_ProcessUtility(Node *parsetree, CommentStmt *stmt = (CommentStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objtype)) - ProcessUtilitySlow(pstate, parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else - CommentObject((CommentStmt *) parsetree); + CommentObject(stmt); break; } @@ -899,7 +893,7 @@ standard_ProcessUtility(Node *parsetree, SecLabelStmt *stmt = (SecLabelStmt *) parsetree; if (EventTriggerSupportsObjectType(stmt->objtype)) - ProcessUtilitySlow(pstate, parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); else @@ -909,7 +903,7 @@ standard_ProcessUtility(Node *parsetree, default: /* All other statement types have event trigger support */ - ProcessUtilitySlow(pstate, parsetree, queryString, + ProcessUtilitySlow(pstate, pstmt, queryString, context, params, dest, completionTag); break; @@ -925,13 +919,14 @@ standard_ProcessUtility(Node *parsetree, */ static void ProcessUtilitySlow(ParseState *pstate, - Node *parsetree, + PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { + Node *parsetree = pstmt->utilityStmt; bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL); bool isCompleteQuery = (context <= PROCESS_UTILITY_QUERY); bool needCleanup; @@ -955,7 +950,9 @@ ProcessUtilitySlow(ParseState *pstate, */ case T_CreateSchemaStmt: CreateSchemaCommand((CreateSchemaStmt *) parsetree, - queryString); + queryString, + pstmt->stmt_location, + pstmt->stmt_len); /* * EventTriggerCollectSimpleCommand called by @@ -1036,7 +1033,16 @@ ProcessUtilitySlow(ParseState *pstate, * call will stash the objects so created into our * event trigger context. */ - ProcessUtility(stmt, + PlannedStmt *wrapper; + + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = pstmt->stmt_location; + wrapper->stmt_len = pstmt->stmt_len; + + ProcessUtility(wrapper, queryString, PROCESS_UTILITY_SUBCOMMAND, params, @@ -1105,8 +1111,16 @@ ProcessUtilitySlow(ParseState *pstate, * queued commands is consistent with the way * they are executed here. */ + PlannedStmt *wrapper; + EventTriggerAlterTableEnd(); - ProcessUtility(stmt, + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = pstmt->stmt_location; + wrapper->stmt_len = pstmt->stmt_len; + ProcessUtility(wrapper, queryString, PROCESS_UTILITY_SUBCOMMAND, params, @@ -1376,7 +1390,8 @@ ProcessUtilitySlow(ParseState *pstate, case T_ViewStmt: /* CREATE VIEW */ EventTriggerAlterTableStart(parsetree); - address = DefineView((ViewStmt *) parsetree, queryString); + address = DefineView((ViewStmt *) parsetree, queryString, + pstmt->stmt_location, pstmt->stmt_len); EventTriggerCollectSimpleCommand(address, secondaryObject, parsetree); /* stashed internally */ @@ -1480,6 +1495,7 @@ ProcessUtilitySlow(ParseState *pstate, case T_AlterTSConfigurationStmt: AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree); + /* * Commands are stashed in MakeConfigurationMapping and * DropConfigurationMapping, which are called from @@ -1736,10 +1752,8 @@ QueryReturnsTuples(Query *parsetree) switch (parsetree->commandType) { case CMD_SELECT: - /* returns tuples ... unless it's DECLARE CURSOR */ - if (parsetree->utilityStmt == NULL) - return true; - break; + /* returns tuples */ + return true; case CMD_INSERT: case CMD_UPDATE: case CMD_DELETE: @@ -1780,6 +1794,13 @@ UtilityContainsQuery(Node *parsetree) switch (nodeTag(parsetree)) { + case T_DeclareCursorStmt: + qry = (Query *) ((DeclareCursorStmt *) parsetree)->query; + Assert(IsA(qry, Query)); + if (qry->commandType == CMD_UTILITY) + return UtilityContainsQuery(qry->utilityStmt); + return qry; + case T_ExplainStmt: qry = (Query *) ((ExplainStmt *) parsetree)->query; Assert(IsA(qry, Query)); @@ -1931,7 +1952,8 @@ AlterObjectTypeCommandTag(ObjectType objtype) /* * CreateCommandTag * utility to get a string representation of the command operation, - * given either a raw (un-analyzed) parsetree or a planned query. + * given either a raw (un-analyzed) parsetree, an analyzed Query, + * or a PlannedStmt. * * This must handle all command types, but since the vast majority * of 'em are utility commands, it seems sensible to keep it here. @@ -1946,6 +1968,11 @@ CreateCommandTag(Node *parsetree) switch (nodeTag(parsetree)) { + /* recurse if we're given a RawStmt */ + case T_RawStmt: + tag = CreateCommandTag(((RawStmt *) parsetree)->stmt); + break; + /* raw plannable queries */ case T_InsertStmt: tag = "INSERT"; @@ -2608,12 +2635,7 @@ CreateCommandTag(Node *parsetree) * will be useful for complaints about read-only * statements */ - if (stmt->utilityStmt != NULL) - { - Assert(IsA(stmt->utilityStmt, DeclareCursorStmt)); - tag = "DECLARE CURSOR"; - } - else if (stmt->rowMarks != NIL) + if (stmt->rowMarks != NIL) { /* not 100% but probably close enough */ switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength) @@ -2647,6 +2669,9 @@ CreateCommandTag(Node *parsetree) case CMD_DELETE: tag = "DELETE"; break; + case CMD_UTILITY: + tag = CreateCommandTag(stmt->utilityStmt); + break; default: elog(WARNING, "unrecognized commandType: %d", (int) stmt->commandType); @@ -2670,12 +2695,7 @@ CreateCommandTag(Node *parsetree) * will be useful for complaints about read-only * statements */ - if (stmt->utilityStmt != NULL) - { - Assert(IsA(stmt->utilityStmt, DeclareCursorStmt)); - tag = "DECLARE CURSOR"; - } - else if (stmt->rowMarks != NIL) + if (stmt->rowMarks != NIL) { /* not 100% but probably close enough */ switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength) @@ -2735,7 +2755,8 @@ CreateCommandTag(Node *parsetree) /* * GetCommandLogLevel * utility to get the minimum log_statement level for a command, - * given either a raw (un-analyzed) parsetree or a planned query. + * given either a raw (un-analyzed) parsetree, an analyzed Query, + * or a PlannedStmt. * * This must handle all command types, but since the vast majority * of 'em are utility commands, it seems sensible to keep it here. @@ -2747,6 +2768,11 @@ GetCommandLogLevel(Node *parsetree) switch (nodeTag(parsetree)) { + /* recurse if we're given a RawStmt */ + case T_RawStmt: + lev = GetCommandLogLevel(((RawStmt *) parsetree)->stmt); + break; + /* raw plannable queries */ case T_InsertStmt: case T_DeleteStmt: @@ -2850,7 +2876,7 @@ GetCommandLogLevel(Node *parsetree) /* Look through an EXECUTE to the referenced stmt */ ps = FetchPreparedStatement(stmt->name, false); if (ps && ps->plansource->raw_parse_tree) - lev = GetCommandLogLevel(ps->plansource->raw_parse_tree); + lev = GetCommandLogLevel(ps->plansource->raw_parse_tree->stmt); else lev = LOGSTMT_ALL; } @@ -3157,6 +3183,10 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_MOD; break; + case CMD_UTILITY: + lev = GetCommandLogLevel(stmt->utilityStmt); + break; + default: elog(WARNING, "unrecognized commandType: %d", (int) stmt->commandType); |