]> granicus.if.org Git - postgresql/blobdiff - src/backend/tcop/utility.c
Change representation of statement lists, and add statement location info.
[postgresql] / src / backend / tcop / utility.c
index fd4eff490744b584b57d19abe124a2b2c6f7a7ec..149210133606443b3f3ba142f4df18836530bc4c 100644 (file)
@@ -5,7 +5,7 @@
  *       commands.  At one time acted as an interface between the Lisp and C
  *       systems.
  *
- * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
@@ -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 */
@@ -1479,7 +1494,14 @@ ProcessUtilitySlow(ParseState *pstate,
                                break;
 
                        case T_AlterTSConfigurationStmt:
-                               address = AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
+                               AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
+
+                               /*
+                                * Commands are stashed in MakeConfigurationMapping and
+                                * DropConfigurationMapping, which are called from
+                                * AlterTSConfiguration
+                                */
+                               commandCollected = true;
                                break;
 
                        case T_AlterTableMoveAllStmt:
@@ -1730,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:
@@ -1774,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));
@@ -1925,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.
@@ -1940,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";
@@ -2602,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)
@@ -2641,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);
@@ -2664,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)
@@ -2729,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.
@@ -2741,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:
@@ -2844,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;
                        }
@@ -3151,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);