]> 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 0698cafbce13e4cf1f04153f6a8c69ec48d78989..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-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  */
 #include "postgres.h"
 
+#include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "access/twophase.h"
 #include "access/xact.h"
+#include "access/xlog.h"
 #include "catalog/catalog.h"
 #include "catalog/namespace.h"
 #include "catalog/toasting.h"
 #include "commands/collationcmds.h"
 #include "commands/conversioncmds.h"
 #include "commands/copy.h"
+#include "commands/createas.h"
 #include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/discard.h"
+#include "commands/event_trigger.h"
 #include "commands/explain.h"
 #include "commands/extension.h"
+#include "commands/matview.h"
 #include "commands/lockcmds.h"
+#include "commands/policy.h"
 #include "commands/portalcmds.h"
 #include "commands/prepare.h"
 #include "commands/proclang.h"
 /* Hook for plugins to get control in ProcessUtility() */
 ProcessUtility_hook_type ProcessUtility_hook = NULL;
 
-
-/*
- * Verify user has ownership of specified relation, else ereport.
- *
- * If noCatalogs is true then we also deny access to system catalogs,
- * except when allowSystemTableMods is true.
- */
-void
-CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
-{
-       Oid                     relOid;
-       HeapTuple       tuple;
-
-       /*
-        * XXX: This is unsafe in the presence of concurrent DDL, since it is
-        * called before acquiring any lock on the target relation.  However,
-        * locking the target relation (especially using something like
-        * AccessExclusiveLock) before verifying that the user has permissions
-        * is not appealing either.
-        */
-       relOid = RangeVarGetRelid(rel, NoLock, false, false);
-
-       tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
-       if (!HeapTupleIsValid(tuple))           /* should not happen */
-               elog(ERROR, "cache lookup failed for relation %u", relOid);
-
-       if (!pg_class_ownercheck(relOid, GetUserId()))
-               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
-                                          rel->relname);
-
-       if (noCatalogs)
-       {
-               if (!allowSystemTableMods &&
-                       IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                        errmsg("permission denied: \"%s\" is a system catalog",
-                                                       rel->relname)));
-       }
-
-       ReleaseSysCache(tuple);
-}
+/* local function declarations */
+static void ProcessUtilitySlow(ParseState *pstate,
+                                  PlannedStmt *pstmt,
+                                  const char *queryString,
+                                  ProcessUtilityContext context,
+                                  ParamListInfo params,
+                                  DestReceiver *dest,
+                                  char *completionTag);
+static void ExecDropStmt(DropStmt *stmt, bool isTopLevel);
 
 
 /*
@@ -115,37 +88,33 @@ CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
  * 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->intoClause != NULL)
-                                       return false;           /* SELECT INTO */
-                               else if (stmt->rowMarks != NIL)
-                                       return false;           /* SELECT FOR 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;
 }
 
@@ -158,14 +127,15 @@ CommandIsReadOnly(Node *parsetree)
 static void
 check_xact_readonly(Node *parsetree)
 {
-       if (!XactReadOnly)
+       /* Only perform the check if we have a reason to do so. */
+       if (!XactReadOnly && !IsInParallelMode())
                return;
 
        /*
         * Note: Commands that need to do more complicated checking are handled
         * elsewhere, in particular COPY and plannable statements do their own
-        * checking.  However they should all call PreventCommandIfReadOnly to
-        * actually throw the error.
+        * checking.  However they should all call PreventCommandIfReadOnly or
+        * PreventCommandIfParallelMode to actually throw the error.
         */
 
        switch (nodeTag(parsetree))
@@ -176,14 +146,19 @@ check_xact_readonly(Node *parsetree)
                case T_AlterFunctionStmt:
                case T_AlterRoleStmt:
                case T_AlterRoleSetStmt:
+               case T_AlterObjectDependsStmt:
                case T_AlterObjectSchemaStmt:
                case T_AlterOwnerStmt:
+               case T_AlterOperatorStmt:
                case T_AlterSeqStmt:
+               case T_AlterTableMoveAllStmt:
                case T_AlterTableStmt:
                case T_RenameStmt:
                case T_CommentStmt:
                case T_DefineStmt:
                case T_CreateCastStmt:
+               case T_CreateEventTrigStmt:
+               case T_AlterEventTrigStmt:
                case T_CreateConversionStmt:
                case T_CreatedbStmt:
                case T_CreateDomainStmt:
@@ -198,22 +173,20 @@ check_xact_readonly(Node *parsetree)
                case T_CreateSchemaStmt:
                case T_CreateSeqStmt:
                case T_CreateStmt:
+               case T_CreateTableAsStmt:
+               case T_RefreshMatViewStmt:
                case T_CreateTableSpaceStmt:
+               case T_CreateTransformStmt:
                case T_CreateTrigStmt:
                case T_CompositeTypeStmt:
                case T_CreateEnumStmt:
+               case T_CreateRangeStmt:
                case T_AlterEnumStmt:
                case T_ViewStmt:
-               case T_DropCastStmt:
                case T_DropStmt:
                case T_DropdbStmt:
                case T_DropTableSpaceStmt:
-               case T_RemoveFuncStmt:
                case T_DropRoleStmt:
-               case T_DropPLangStmt:
-               case T_RemoveOpClassStmt:
-               case T_RemoveOpFamilyStmt:
-               case T_DropPropertyStmt:
                case T_GrantStmt:
                case T_GrantRoleStmt:
                case T_AlterDefaultPrivilegesStmt:
@@ -227,17 +200,17 @@ check_xact_readonly(Node *parsetree)
                case T_AlterExtensionContentsStmt:
                case T_CreateFdwStmt:
                case T_AlterFdwStmt:
-               case T_DropFdwStmt:
                case T_CreateForeignServerStmt:
                case T_AlterForeignServerStmt:
-               case T_DropForeignServerStmt:
                case T_CreateUserMappingStmt:
                case T_AlterUserMappingStmt:
                case T_DropUserMappingStmt:
                case T_AlterTableSpaceOptionsStmt:
                case T_CreateForeignTableStmt:
+               case T_ImportForeignSchemaStmt:
                case T_SecLabelStmt:
                        PreventCommandIfReadOnly(CreateCommandTag(parsetree));
+                       PreventCommandIfParallelMode(CreateCommandTag(parsetree));
                        break;
                default:
                        /* do nothing */
@@ -262,11 +235,29 @@ PreventCommandIfReadOnly(const char *cmdname)
                                                cmdname)));
 }
 
+/*
+ * PreventCommandIfParallelMode: throw error if current (sub)transaction is
+ * in parallel mode.
+ *
+ * This is useful mainly to ensure consistency of the error message wording;
+ * most callers have checked IsInParallelMode() for themselves.
+ */
+void
+PreventCommandIfParallelMode(const char *cmdname)
+{
+       if (IsInParallelMode())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
+               /* translator: %s is name of a SQL command, eg CREATE */
+                                errmsg("cannot execute %s during a parallel operation",
+                                               cmdname)));
+}
+
 /*
  * PreventCommandDuringRecovery: throw error if RecoveryInProgress
  *
  * The majority of operations that are unsafe in a Hot Standby slave
- * will be rejected by XactReadOnly tests.     However there are a few
+ * will be rejected by XactReadOnly tests.  However there are a few
  * commands that are allowed in "read-only" xacts but cannot be allowed
  * in Hot Standby mode.  Those commands should call this function.
  */
@@ -304,10 +295,11 @@ 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)
  *     params: parameters to use during execution
- *     isTopLevel: true if executing a "top level" (interactively issued) command
  *     dest: where to send results
  *     completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
  *             in which to store a command completion status string.
@@ -321,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,
-                          bool isTopLevel,
                           DestReceiver *dest,
                           char *completionTag)
 {
+       Assert(IsA(pstmt, PlannedStmt));
+       Assert(pstmt->commandType == CMD_UTILITY);
        Assert(queryString != NULL);    /* required as of 8.4 */
 
        /*
@@ -336,26 +330,46 @@ ProcessUtility(Node *parsetree,
         * call standard_ProcessUtility().
         */
        if (ProcessUtility_hook)
-               (*ProcessUtility_hook) (parsetree, queryString, params,
-                                                               isTopLevel, dest, completionTag);
+               (*ProcessUtility_hook) (pstmt, queryString,
+                                                               context, params,
+                                                               dest, completionTag);
        else
-               standard_ProcessUtility(parsetree, queryString, params,
-                                                               isTopLevel, dest, completionTag);
+               standard_ProcessUtility(pstmt, queryString,
+                                                               context, params,
+                                                               dest, completionTag);
 }
 
+/*
+ * standard_ProcessUtility itself deals only with utility commands for
+ * which we do not provide event trigger support.  Commands that do have
+ * such support are passed down to ProcessUtilitySlow, which contains the
+ * necessary infrastructure for such triggers.
+ *
+ * This division is not just for performance: it's critical that the
+ * event trigger code not be invoked when doing START TRANSACTION for
+ * example, because we might need to refresh the event trigger cache,
+ * which requires being in a valid transaction.
+ */
 void
-standard_ProcessUtility(Node *parsetree,
+standard_ProcessUtility(PlannedStmt *pstmt,
                                                const char *queryString,
+                                               ProcessUtilityContext context,
                                                ParamListInfo params,
-                                               bool isTopLevel,
                                                DestReceiver *dest,
                                                char *completionTag)
 {
+       Node       *parsetree = pstmt->utilityStmt;
+       bool            isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
+       ParseState *pstate;
+
        check_xact_readonly(parsetree);
 
        if (completionTag)
                completionTag[0] = '\0';
 
+       pstate = make_parsestate(NULL);
+       pstate->p_sourcetext = queryString;
+
        switch (nodeTag(parsetree))
        {
                        /*
@@ -473,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:
@@ -503,799 +507,1137 @@ standard_ProcessUtility(Node *parsetree,
                                                           completionTag);
                        break;
 
-                       /*
-                        * relation and attribute manipulation
-                        */
-               case T_CreateSchemaStmt:
-                       CreateSchemaCommand((CreateSchemaStmt *) parsetree,
-                                                               queryString);
-                       break;
-
-               case T_CreateStmt:
-               case T_CreateForeignTableStmt:
-                       {
-                               List       *stmts;
-                               ListCell   *l;
-                               Oid                     relOid;
-
-                               /* Run parse analysis ... */
-                               stmts = transformCreateStmt((CreateStmt *) parsetree,
-                                                                                       queryString);
-
-                               /* ... and do it */
-                               foreach(l, stmts)
-                               {
-                                       Node       *stmt = (Node *) lfirst(l);
-
-                                       if (IsA(stmt, CreateStmt))
-                                       {
-                                               Datum           toast_options;
-                                               static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
-
-                                               /* Create the table itself */
-                                               relOid = DefineRelation((CreateStmt *) stmt,
-                                                                                               RELKIND_RELATION,
-                                                                                               InvalidOid);
-
-                                               /*
-                                                * Let AlterTableCreateToastTable decide if this one
-                                                * needs a secondary relation too.
-                                                */
-                                               CommandCounterIncrement();
-
-                                               /* parse and validate reloptions for the toast table */
-                                               toast_options = transformRelOptions((Datum) 0,
-                                                                                         ((CreateStmt *) stmt)->options,
-                                                                                                                       "toast",
-                                                                                                                       validnsps,
-                                                                                                                       true, false);
-                                               (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options,
-                                                                                          true);
-
-                                               AlterTableCreateToastTable(relOid, toast_options);
-                                       }
-                                       else if (IsA(stmt, CreateForeignTableStmt))
-                                       {
-                                               /* Create the table itself */
-                                               relOid = DefineRelation((CreateStmt *) stmt,
-                                                                                               RELKIND_FOREIGN_TABLE,
-                                                                                               InvalidOid);
-                                               CreateForeignTable((CreateForeignTableStmt *) stmt,
-                                                                                  relOid);
-                                       }
-                                       else
-                                       {
-                                               /* Recurse for anything else */
-                                               ProcessUtility(stmt,
-                                                                          queryString,
-                                                                          params,
-                                                                          false,
-                                                                          None_Receiver,
-                                                                          NULL);
-                                       }
-
-                                       /* Need CCI between commands */
-                                       if (lnext(l) != NULL)
-                                               CommandCounterIncrement();
-                               }
-                       }
+               case T_DoStmt:
+                       ExecuteDoStmt((DoStmt *) parsetree);
                        break;
 
                case T_CreateTableSpaceStmt:
+                       /* no event triggers for global objects */
                        PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
                        CreateTableSpace((CreateTableSpaceStmt *) parsetree);
                        break;
 
                case T_DropTableSpaceStmt:
+                       /* no event triggers for global objects */
                        PreventTransactionChain(isTopLevel, "DROP TABLESPACE");
                        DropTableSpace((DropTableSpaceStmt *) parsetree);
                        break;
 
                case T_AlterTableSpaceOptionsStmt:
+                       /* no event triggers for global objects */
                        AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree);
                        break;
 
-               case T_CreateExtensionStmt:
-                       CreateExtension((CreateExtensionStmt *) parsetree);
+               case T_TruncateStmt:
+                       ExecuteTruncate((TruncateStmt *) parsetree);
                        break;
 
-               case T_AlterExtensionStmt:
-                       ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree);
-                       break;
+               case T_CopyStmt:
+                       {
+                               uint64          processed;
 
-               case T_AlterExtensionContentsStmt:
-                       ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree);
+                               DoCopy(pstate, (CopyStmt *) parsetree,
+                                          pstmt->stmt_location, pstmt->stmt_len,
+                                          &processed);
+                               if (completionTag)
+                                       snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
+                                                        "COPY " UINT64_FORMAT, processed);
+                       }
                        break;
 
-               case T_CreateFdwStmt:
-                       CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
+               case T_PrepareStmt:
+                       CheckRestrictedOperation("PREPARE");
+                       PrepareQuery((PrepareStmt *) parsetree, queryString,
+                                                pstmt->stmt_location, pstmt->stmt_len);
                        break;
 
-               case T_AlterFdwStmt:
-                       AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
+               case T_ExecuteStmt:
+                       ExecuteQuery((ExecuteStmt *) parsetree, NULL,
+                                                queryString, params,
+                                                dest, completionTag);
                        break;
 
-               case T_DropFdwStmt:
-                       RemoveForeignDataWrapper((DropFdwStmt *) parsetree);
+               case T_DeallocateStmt:
+                       CheckRestrictedOperation("DEALLOCATE");
+                       DeallocateQuery((DeallocateStmt *) parsetree);
                        break;
 
-               case T_CreateForeignServerStmt:
-                       CreateForeignServer((CreateForeignServerStmt *) parsetree);
+               case T_GrantRoleStmt:
+                       /* no event triggers for global objects */
+                       GrantRole((GrantRoleStmt *) parsetree);
                        break;
 
-               case T_AlterForeignServerStmt:
-                       AlterForeignServer((AlterForeignServerStmt *) parsetree);
+               case T_CreatedbStmt:
+                       /* no event triggers for global objects */
+                       PreventTransactionChain(isTopLevel, "CREATE DATABASE");
+                       createdb(pstate, (CreatedbStmt *) parsetree);
                        break;
 
-               case T_DropForeignServerStmt:
-                       RemoveForeignServer((DropForeignServerStmt *) parsetree);
+               case T_AlterDatabaseStmt:
+                       /* no event triggers for global objects */
+                       AlterDatabase(pstate, (AlterDatabaseStmt *) parsetree, isTopLevel);
                        break;
 
-               case T_CreateUserMappingStmt:
-                       CreateUserMapping((CreateUserMappingStmt *) parsetree);
+               case T_AlterDatabaseSetStmt:
+                       /* no event triggers for global objects */
+                       AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
                        break;
 
-               case T_AlterUserMappingStmt:
-                       AlterUserMapping((AlterUserMappingStmt *) parsetree);
-                       break;
+               case T_DropdbStmt:
+                       {
+                               DropdbStmt *stmt = (DropdbStmt *) parsetree;
 
-               case T_DropUserMappingStmt:
-                       RemoveUserMapping((DropUserMappingStmt *) parsetree);
+                               /* no event triggers for global objects */
+                               PreventTransactionChain(isTopLevel, "DROP DATABASE");
+                               dropdb(stmt->dbname, stmt->missing_ok);
+                       }
                        break;
 
-               case T_DropStmt:
+                       /* Query-level asynchronous notification */
+               case T_NotifyStmt:
                        {
-                               DropStmt   *stmt = (DropStmt *) parsetree;
-
-                               switch (stmt->removeType)
-                               {
-                                       case OBJECT_TABLE:
-                                       case OBJECT_SEQUENCE:
-                                       case OBJECT_VIEW:
-                                       case OBJECT_INDEX:
-                                       case OBJECT_FOREIGN_TABLE:
-                                               RemoveRelations(stmt);
-                                               break;
+                               NotifyStmt *stmt = (NotifyStmt *) parsetree;
 
-                                       case OBJECT_TYPE:
-                                       case OBJECT_DOMAIN:
-                                               RemoveTypes(stmt);
-                                               break;
+                               PreventCommandDuringRecovery("NOTIFY");
+                               Async_Notify(stmt->conditionname, stmt->payload);
+                       }
+                       break;
 
-                                       case OBJECT_COLLATION:
-                                               DropCollationsCommand(stmt);
-                                               break;
+               case T_ListenStmt:
+                       {
+                               ListenStmt *stmt = (ListenStmt *) parsetree;
 
-                                       case OBJECT_CONVERSION:
-                                               DropConversionsCommand(stmt);
-                                               break;
+                               PreventCommandDuringRecovery("LISTEN");
+                               CheckRestrictedOperation("LISTEN");
+                               Async_Listen(stmt->conditionname);
+                       }
+                       break;
 
-                                       case OBJECT_SCHEMA:
-                                               RemoveSchemas(stmt);
-                                               break;
+               case T_UnlistenStmt:
+                       {
+                               UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
 
-                                       case OBJECT_TSPARSER:
-                                               RemoveTSParsers(stmt);
-                                               break;
+                               PreventCommandDuringRecovery("UNLISTEN");
+                               CheckRestrictedOperation("UNLISTEN");
+                               if (stmt->conditionname)
+                                       Async_Unlisten(stmt->conditionname);
+                               else
+                                       Async_UnlistenAll();
+                       }
+                       break;
 
-                                       case OBJECT_TSDICTIONARY:
-                                               RemoveTSDictionaries(stmt);
-                                               break;
+               case T_LoadStmt:
+                       {
+                               LoadStmt   *stmt = (LoadStmt *) parsetree;
 
-                                       case OBJECT_TSTEMPLATE:
-                                               RemoveTSTemplates(stmt);
-                                               break;
+                               closeAllVfds(); /* probably not necessary... */
+                               /* Allowed names are restricted if you're not superuser */
+                               load_file(stmt->filename, !superuser());
+                       }
+                       break;
 
-                                       case OBJECT_TSCONFIGURATION:
-                                               RemoveTSConfigurations(stmt);
-                                               break;
+               case T_ClusterStmt:
+                       /* we choose to allow this during "read only" transactions */
+                       PreventCommandDuringRecovery("CLUSTER");
+                       /* forbidden in parallel mode due to CommandIsReadOnly */
+                       cluster((ClusterStmt *) parsetree, isTopLevel);
+                       break;
 
-                                       case OBJECT_EXTENSION:
-                                               RemoveExtensions(stmt);
-                                               break;
+               case T_VacuumStmt:
+                       {
+                               VacuumStmt *stmt = (VacuumStmt *) parsetree;
 
-                                       default:
-                                               elog(ERROR, "unrecognized drop object type: %d",
-                                                        (int) stmt->removeType);
-                                               break;
-                               }
+                               /* we choose to allow this during "read only" transactions */
+                               PreventCommandDuringRecovery((stmt->options & VACOPT_VACUUM) ?
+                                                                                        "VACUUM" : "ANALYZE");
+                               /* forbidden in parallel mode due to CommandIsReadOnly */
+                               ExecVacuum(stmt, isTopLevel);
                        }
                        break;
 
-               case T_TruncateStmt:
-                       ExecuteTruncate((TruncateStmt *) parsetree);
+               case T_ExplainStmt:
+                       ExplainQuery(pstate, (ExplainStmt *) parsetree, queryString, params, dest);
                        break;
 
-               case T_CommentStmt:
-                       CommentObject((CommentStmt *) parsetree);
+               case T_AlterSystemStmt:
+                       PreventTransactionChain(isTopLevel, "ALTER SYSTEM");
+                       AlterSystemSetConfigFile((AlterSystemStmt *) parsetree);
                        break;
 
-               case T_SecLabelStmt:
-                       ExecSecLabelStmt((SecLabelStmt *) parsetree);
+               case T_VariableSetStmt:
+                       ExecSetVariableStmt((VariableSetStmt *) parsetree, isTopLevel);
                        break;
 
-               case T_CopyStmt:
+               case T_VariableShowStmt:
                        {
-                               uint64          processed;
+                               VariableShowStmt *n = (VariableShowStmt *) parsetree;
 
-                               processed = DoCopy((CopyStmt *) parsetree, queryString);
-                               if (completionTag)
-                                       snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-                                                        "COPY " UINT64_FORMAT, processed);
+                               GetPGVariable(n->name, dest);
                        }
                        break;
 
-               case T_PrepareStmt:
-                       CheckRestrictedOperation("PREPARE");
-                       PrepareQuery((PrepareStmt *) parsetree, queryString);
+               case T_DiscardStmt:
+                       /* should we allow DISCARD PLANS? */
+                       CheckRestrictedOperation("DISCARD");
+                       DiscardCommand((DiscardStmt *) parsetree, isTopLevel);
                        break;
 
-               case T_ExecuteStmt:
-                       ExecuteQuery((ExecuteStmt *) parsetree, queryString, params,
-                                                dest, completionTag);
+               case T_CreateEventTrigStmt:
+                       /* no event triggers on event triggers */
+                       CreateEventTrigger((CreateEventTrigStmt *) parsetree);
                        break;
 
-               case T_DeallocateStmt:
-                       CheckRestrictedOperation("DEALLOCATE");
-                       DeallocateQuery((DeallocateStmt *) parsetree);
+               case T_AlterEventTrigStmt:
+                       /* no event triggers on event triggers */
+                       AlterEventTrigger((AlterEventTrigStmt *) parsetree);
                        break;
 
                        /*
-                        * schema
+                        * ******************************** ROLE statements ****
                         */
-               case T_RenameStmt:
-                       ExecRenameStmt((RenameStmt *) parsetree);
+               case T_CreateRoleStmt:
+                       /* no event triggers for global objects */
+                       CreateRole(pstate, (CreateRoleStmt *) parsetree);
                        break;
 
-               case T_AlterObjectSchemaStmt:
-                       ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree);
+               case T_AlterRoleStmt:
+                       /* no event triggers for global objects */
+                       AlterRole((AlterRoleStmt *) parsetree);
                        break;
 
-               case T_AlterOwnerStmt:
-                       ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
+               case T_AlterRoleSetStmt:
+                       /* no event triggers for global objects */
+                       AlterRoleSet((AlterRoleSetStmt *) parsetree);
                        break;
 
-               case T_AlterTableStmt:
-                       {
-                               List       *stmts;
-                               ListCell   *l;
+               case T_DropRoleStmt:
+                       /* no event triggers for global objects */
+                       DropRole((DropRoleStmt *) parsetree);
+                       break;
 
-                               /* Run parse analysis ... */
-                               stmts = transformAlterTableStmt((AlterTableStmt *) parsetree,
-                                                                                               queryString);
+               case T_ReassignOwnedStmt:
+                       /* no event triggers for global objects */
+                       ReassignOwnedObjects((ReassignOwnedStmt *) parsetree);
+                       break;
 
-                               /* ... and do it */
-                               foreach(l, stmts)
-                               {
-                                       Node       *stmt = (Node *) lfirst(l);
+               case T_LockStmt:
 
-                                       if (IsA(stmt, AlterTableStmt))
-                                       {
-                                               /* Do the table alteration proper */
-                                               AlterTable((AlterTableStmt *) stmt);
-                                       }
-                                       else
-                                       {
-                                               /* Recurse for anything else */
-                                               ProcessUtility(stmt,
-                                                                          queryString,
-                                                                          params,
-                                                                          false,
-                                                                          None_Receiver,
-                                                                          NULL);
-                                       }
+                       /*
+                        * Since the lock would just get dropped immediately, LOCK TABLE
+                        * outside a transaction block is presumed to be user error.
+                        */
+                       RequireTransactionChain(isTopLevel, "LOCK TABLE");
+                       /* forbidden in parallel mode due to CommandIsReadOnly */
+                       LockTableCommand((LockStmt *) parsetree);
+                       break;
 
-                                       /* Need CCI between commands */
-                                       if (lnext(l) != NULL)
-                                               CommandCounterIncrement();
-                               }
-                       }
+               case T_ConstraintsSetStmt:
+                       WarnNoTransactionChain(isTopLevel, "SET CONSTRAINTS");
+                       AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
                        break;
 
-               case T_AlterDomainStmt:
-                       {
-                               AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
+               case T_CheckPointStmt:
+                       if (!superuser())
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                                errmsg("must be superuser to do CHECKPOINT")));
 
-                               /*
-                                * Some or all of these functions are recursive to cover
-                                * inherited things, so permission checks are done there.
-                                */
-                               switch (stmt->subtype)
+                       /*
+                        * You might think we should have a PreventCommandDuringRecovery()
+                        * here, but we interpret a CHECKPOINT command during recovery as
+                        * a request for a restartpoint instead. We allow this since it
+                        * can be a useful way of reducing switchover time when using
+                        * various forms of replication.
+                        */
+                       RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT |
+                                                         (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
+                       break;
+
+               case T_ReindexStmt:
+                       {
+                               ReindexStmt *stmt = (ReindexStmt *) parsetree;
+
+                               /* we choose to allow this during "read only" transactions */
+                               PreventCommandDuringRecovery("REINDEX");
+                               /* forbidden in parallel mode due to CommandIsReadOnly */
+                               switch (stmt->kind)
                                {
-                                       case 'T':       /* ALTER DOMAIN DEFAULT */
+                                       case REINDEX_OBJECT_INDEX:
+                                               ReindexIndex(stmt->relation, stmt->options);
+                                               break;
+                                       case REINDEX_OBJECT_TABLE:
+                                               ReindexTable(stmt->relation, stmt->options);
+                                               break;
+                                       case REINDEX_OBJECT_SCHEMA:
+                                       case REINDEX_OBJECT_SYSTEM:
+                                       case REINDEX_OBJECT_DATABASE:
 
                                                /*
-                                                * Recursively alter column default for table and, if
-                                                * requested, for descendants
+                                                * This cannot run inside a user transaction block; if
+                                                * we were inside a transaction, then its commit- and
+                                                * start-transaction-command calls would not have the
+                                                * intended effect!
                                                 */
-                                               AlterDomainDefault(stmt->typeName,
-                                                                                  stmt->def);
-                                               break;
-                                       case 'N':       /* ALTER DOMAIN DROP NOT NULL */
-                                               AlterDomainNotNull(stmt->typeName,
-                                                                                  false);
-                                               break;
-                                       case 'O':       /* ALTER DOMAIN SET NOT NULL */
-                                               AlterDomainNotNull(stmt->typeName,
-                                                                                  true);
-                                               break;
-                                       case 'C':       /* ADD CONSTRAINT */
-                                               AlterDomainAddConstraint(stmt->typeName,
-                                                                                                stmt->def);
-                                               break;
-                                       case 'X':       /* DROP CONSTRAINT */
-                                               AlterDomainDropConstraint(stmt->typeName,
-                                                                                                 stmt->name,
-                                                                                                 stmt->behavior);
-                                               break;
-                                       case 'V':       /* VALIDATE CONSTRAINT */
-                                               AlterDomainValidateConstraint(stmt->typeName,
-                                                                                                         stmt->name);
+                                               PreventTransactionChain(isTopLevel,
+                                                                                               (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
+                                                                                               (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
+                                                                                               "REINDEX DATABASE");
+                                               ReindexMultipleTables(stmt->name, stmt->kind, stmt->options);
                                                break;
-                                       default:        /* oops */
-                                               elog(ERROR, "unrecognized alter domain type: %d",
-                                                        (int) stmt->subtype);
+                                       default:
+                                               elog(ERROR, "unrecognized object type: %d",
+                                                        (int) stmt->kind);
                                                break;
                                }
                        }
                        break;
 
-               case T_GrantStmt:
-                       ExecuteGrantStmt((GrantStmt *) parsetree);
-                       break;
+                       /*
+                        * The following statements are supported by Event Triggers only
+                        * in some cases, so we "fast path" them in the other cases.
+                        */
 
-               case T_GrantRoleStmt:
-                       GrantRole((GrantRoleStmt *) parsetree);
-                       break;
+               case T_GrantStmt:
+                       {
+                               GrantStmt  *stmt = (GrantStmt *) parsetree;
 
-               case T_AlterDefaultPrivilegesStmt:
-                       ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree);
+                               if (EventTriggerSupportsGrantObjectType(stmt->objtype))
+                                       ProcessUtilitySlow(pstate, pstmt, queryString,
+                                                                          context, params,
+                                                                          dest, completionTag);
+                               else
+                                       ExecuteGrantStmt(stmt);
+                       }
                        break;
 
-                       /*
-                        * **************** object creation / destruction *****************
-                        */
-               case T_DefineStmt:
+               case T_DropStmt:
                        {
-                               DefineStmt *stmt = (DefineStmt *) parsetree;
+                               DropStmt   *stmt = (DropStmt *) parsetree;
 
-                               switch (stmt->kind)
-                               {
-                                       case OBJECT_AGGREGATE:
-                                               DefineAggregate(stmt->defnames, stmt->args,
-                                                                               stmt->oldstyle, stmt->definition);
-                                               break;
-                                       case OBJECT_OPERATOR:
-                                               Assert(stmt->args == NIL);
-                                               DefineOperator(stmt->defnames, stmt->definition);
-                                               break;
-                                       case OBJECT_TYPE:
-                                               Assert(stmt->args == NIL);
-                                               DefineType(stmt->defnames, stmt->definition);
-                                               break;
-                                       case OBJECT_TSPARSER:
-                                               Assert(stmt->args == NIL);
-                                               DefineTSParser(stmt->defnames, stmt->definition);
-                                               break;
-                                       case OBJECT_TSDICTIONARY:
-                                               Assert(stmt->args == NIL);
-                                               DefineTSDictionary(stmt->defnames, stmt->definition);
-                                               break;
-                                       case OBJECT_TSTEMPLATE:
-                                               Assert(stmt->args == NIL);
-                                               DefineTSTemplate(stmt->defnames, stmt->definition);
-                                               break;
-                                       case OBJECT_TSCONFIGURATION:
-                                               Assert(stmt->args == NIL);
-                                               DefineTSConfiguration(stmt->defnames, stmt->definition);
-                                               break;
-                                       case OBJECT_COLLATION:
-                                               Assert(stmt->args == NIL);
-                                               DefineCollation(stmt->defnames, stmt->definition);
-                                               break;
-                                       default:
-                                               elog(ERROR, "unrecognized define stmt type: %d",
-                                                        (int) stmt->kind);
-                                               break;
-                               }
+                               if (EventTriggerSupportsObjectType(stmt->removeType))
+                                       ProcessUtilitySlow(pstate, pstmt, queryString,
+                                                                          context, params,
+                                                                          dest, completionTag);
+                               else
+                                       ExecDropStmt(stmt, isTopLevel);
                        }
                        break;
 
-               case T_CompositeTypeStmt:               /* CREATE TYPE (composite) */
+               case T_RenameStmt:
                        {
-                               CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
+                               RenameStmt *stmt = (RenameStmt *) parsetree;
 
-                               DefineCompositeType(stmt->typevar, stmt->coldeflist);
+                               if (EventTriggerSupportsObjectType(stmt->renameType))
+                                       ProcessUtilitySlow(pstate, pstmt, queryString,
+                                                                          context, params,
+                                                                          dest, completionTag);
+                               else
+                                       ExecRenameStmt(stmt);
                        }
                        break;
 
-               case T_CreateEnumStmt:  /* CREATE TYPE (enum) */
-                       DefineEnum((CreateEnumStmt *) parsetree);
+               case T_AlterObjectDependsStmt:
+                       {
+                               AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree;
+
+                               if (EventTriggerSupportsObjectType(stmt->objectType))
+                                       ProcessUtilitySlow(pstate, pstmt, queryString,
+                                                                          context, params,
+                                                                          dest, completionTag);
+                               else
+                                       ExecAlterObjectDependsStmt(stmt, NULL);
+                       }
                        break;
 
-               case T_AlterEnumStmt:   /* ALTER TYPE (enum) */
+               case T_AlterObjectSchemaStmt:
+                       {
+                               AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree;
 
-                       /*
-                        * We disallow this in transaction blocks, because we can't cope
-                        * with enum OID values getting into indexes and then having their
-                        * defining pg_enum entries go away.
-                        */
-                       PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
-                       AlterEnum((AlterEnumStmt *) parsetree);
+                               if (EventTriggerSupportsObjectType(stmt->objectType))
+                                       ProcessUtilitySlow(pstate, pstmt, queryString,
+                                                                          context, params,
+                                                                          dest, completionTag);
+                               else
+                                       ExecAlterObjectSchemaStmt(stmt, NULL);
+                       }
                        break;
 
-               case T_ViewStmt:                /* CREATE VIEW */
-                       DefineView((ViewStmt *) parsetree, queryString);
-                       break;
+               case T_AlterOwnerStmt:
+                       {
+                               AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree;
 
-               case T_CreateFunctionStmt:              /* CREATE FUNCTION */
-                       CreateFunction((CreateFunctionStmt *) parsetree, queryString);
+                               if (EventTriggerSupportsObjectType(stmt->objectType))
+                                       ProcessUtilitySlow(pstate, pstmt, queryString,
+                                                                          context, params,
+                                                                          dest, completionTag);
+                               else
+                                       ExecAlterOwnerStmt(stmt);
+                       }
                        break;
 
-               case T_AlterFunctionStmt:               /* ALTER FUNCTION */
-                       AlterFunction((AlterFunctionStmt *) parsetree);
-                       break;
+               case T_CommentStmt:
+                       {
+                               CommentStmt *stmt = (CommentStmt *) parsetree;
+
+                               if (EventTriggerSupportsObjectType(stmt->objtype))
+                                       ProcessUtilitySlow(pstate, pstmt, queryString,
+                                                                          context, params,
+                                                                          dest, completionTag);
+                               else
+                                       CommentObject(stmt);
+                               break;
+                       }
 
-               case T_IndexStmt:               /* CREATE INDEX */
+               case T_SecLabelStmt:
                        {
-                               IndexStmt  *stmt = (IndexStmt *) parsetree;
-
-                               if (stmt->concurrent)
-                                       PreventTransactionChain(isTopLevel,
-                                                                                       "CREATE INDEX CONCURRENTLY");
-
-                               CheckRelationOwnership(stmt->relation, true);
-
-                               /* Run parse analysis ... */
-                               stmt = transformIndexStmt(stmt, queryString);
-
-                               /* ... and do it */
-                               DefineIndex(stmt->relation,             /* relation */
-                                                       stmt->idxname,          /* index name */
-                                                       InvalidOid, /* no predefined OID */
-                                                       stmt->accessMethod, /* am name */
-                                                       stmt->tableSpace,
-                                                       stmt->indexParams,      /* parameters */
-                                                       (Expr *) stmt->whereClause,
-                                                       stmt->options,
-                                                       stmt->excludeOpNames,
-                                                       stmt->unique,
-                                                       stmt->primary,
-                                                       stmt->isconstraint,
-                                                       stmt->deferrable,
-                                                       stmt->initdeferred,
-                                                       false,          /* is_alter_table */
-                                                       true,           /* check_rights */
-                                                       false,          /* skip_build */
-                                                       false,          /* quiet */
-                                                       stmt->concurrent);      /* concurrent */
+                               SecLabelStmt *stmt = (SecLabelStmt *) parsetree;
+
+                               if (EventTriggerSupportsObjectType(stmt->objtype))
+                                       ProcessUtilitySlow(pstate, pstmt, queryString,
+                                                                          context, params,
+                                                                          dest, completionTag);
+                               else
+                                       ExecSecLabelStmt(stmt);
+                               break;
                        }
-                       break;
 
-               case T_RuleStmt:                /* CREATE RULE */
-                       DefineRule((RuleStmt *) parsetree, queryString);
+               default:
+                       /* All other statement types have event trigger support */
+                       ProcessUtilitySlow(pstate, pstmt, queryString,
+                                                          context, params,
+                                                          dest, completionTag);
                        break;
+       }
 
-               case T_CreateSeqStmt:
-                       DefineSequence((CreateSeqStmt *) parsetree);
-                       break;
+       free_parsestate(pstate);
+}
 
-               case T_AlterSeqStmt:
-                       AlterSequence((AlterSeqStmt *) parsetree);
-                       break;
+/*
+ * The "Slow" variant of ProcessUtility should only receive statements
+ * supported by the event triggers facility.  Therefore, we always
+ * perform the trigger support calls if the context allows it.
+ */
+static void
+ProcessUtilitySlow(ParseState *pstate,
+                                  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;
+       bool            commandCollected = false;
+       ObjectAddress address;
+       ObjectAddress secondaryObject = InvalidObjectAddress;
+
+       /* All event trigger calls are done only when isCompleteQuery is true */
+       needCleanup = isCompleteQuery && EventTriggerBeginCompleteQuery();
+
+       /* PG_TRY block is to ensure we call EventTriggerEndCompleteQuery */
+       PG_TRY();
+       {
+               if (isCompleteQuery)
+                       EventTriggerDDLCommandStart(parsetree);
 
-               case T_RemoveFuncStmt:
-                       {
-                               RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
+               switch (nodeTag(parsetree))
+               {
+                               /*
+                                * relation and attribute manipulation
+                                */
+                       case T_CreateSchemaStmt:
+                               CreateSchemaCommand((CreateSchemaStmt *) parsetree,
+                                                                       queryString,
+                                                                       pstmt->stmt_location,
+                                                                       pstmt->stmt_len);
 
-                               switch (stmt->kind)
+                               /*
+                                * EventTriggerCollectSimpleCommand called by
+                                * CreateSchemaCommand
+                                */
+                               commandCollected = true;
+                               break;
+
+                       case T_CreateStmt:
+                       case T_CreateForeignTableStmt:
                                {
-                                       case OBJECT_FUNCTION:
-                                               RemoveFunction(stmt);
-                                               break;
-                                       case OBJECT_AGGREGATE:
-                                               RemoveAggregate(stmt);
-                                               break;
-                                       case OBJECT_OPERATOR:
-                                               RemoveOperator(stmt);
-                                               break;
-                                       default:
-                                               elog(ERROR, "unrecognized object type: %d",
-                                                        (int) stmt->kind);
-                                               break;
+                                       List       *stmts;
+                                       ListCell   *l;
+
+                                       /* Run parse analysis ... */
+                                       stmts = transformCreateStmt((CreateStmt *) parsetree,
+                                                                                               queryString);
+
+                                       /* ... and do it */
+                                       foreach(l, stmts)
+                                       {
+                                               Node       *stmt = (Node *) lfirst(l);
+
+                                               if (IsA(stmt, CreateStmt))
+                                               {
+                                                       Datum           toast_options;
+                                                       static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
+
+                                                       /* Create the table itself */
+                                                       address = DefineRelation((CreateStmt *) stmt,
+                                                                                                        RELKIND_RELATION,
+                                                                                                        InvalidOid, NULL,
+                                                                                                        queryString);
+                                                       EventTriggerCollectSimpleCommand(address,
+                                                                                                                        secondaryObject,
+                                                                                                                        stmt);
+
+                                                       /*
+                                                        * Let NewRelationCreateToastTable decide if this
+                                                        * one needs a secondary relation too.
+                                                        */
+                                                       CommandCounterIncrement();
+
+                                                       /*
+                                                        * parse and validate reloptions for the toast
+                                                        * table
+                                                        */
+                                                       toast_options = transformRelOptions((Datum) 0,
+                                                                                         ((CreateStmt *) stmt)->options,
+                                                                                                                               "toast",
+                                                                                                                               validnsps,
+                                                                                                                               true,
+                                                                                                                               false);
+                                                       (void) heap_reloptions(RELKIND_TOASTVALUE,
+                                                                                                  toast_options,
+                                                                                                  true);
+
+                                                       NewRelationCreateToastTable(address.objectId,
+                                                                                                               toast_options);
+                                               }
+                                               else if (IsA(stmt, CreateForeignTableStmt))
+                                               {
+                                                       /* Create the table itself */
+                                                       address = DefineRelation((CreateStmt *) stmt,
+                                                                                                        RELKIND_FOREIGN_TABLE,
+                                                                                                        InvalidOid, NULL,
+                                                                                                        queryString);
+                                                       CreateForeignTable((CreateForeignTableStmt *) stmt,
+                                                                                          address.objectId);
+                                                       EventTriggerCollectSimpleCommand(address,
+                                                                                                                        secondaryObject,
+                                                                                                                        stmt);
+                                               }
+                                               else
+                                               {
+                                                       /*
+                                                        * Recurse for anything else.  Note the recursive
+                                                        * call will stash the objects so created into our
+                                                        * event trigger context.
+                                                        */
+                                                       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,
+                                                                                  None_Receiver,
+                                                                                  NULL);
+                                               }
+
+                                               /* Need CCI between commands */
+                                               if (lnext(l) != NULL)
+                                                       CommandCounterIncrement();
+                                       }
+
+                                       /*
+                                        * The multiple commands generated here are stashed
+                                        * individually, so disable collection below.
+                                        */
+                                       commandCollected = true;
                                }
-                       }
-                       break;
+                               break;
 
-               case T_DoStmt:
-                       ExecuteDoStmt((DoStmt *) parsetree);
-                       break;
+                       case T_AlterTableStmt:
+                               {
+                                       AlterTableStmt *atstmt = (AlterTableStmt *) parsetree;
+                                       Oid                     relid;
+                                       List       *stmts;
+                                       ListCell   *l;
+                                       LOCKMODE        lockmode;
+
+                                       /*
+                                        * Figure out lock mode, and acquire lock.  This also does
+                                        * basic permissions checks, so that we won't wait for a
+                                        * lock on (for example) a relation on which we have no
+                                        * permissions.
+                                        */
+                                       lockmode = AlterTableGetLockLevel(atstmt->cmds);
+                                       relid = AlterTableLookupRelation(atstmt, lockmode);
+
+                                       if (OidIsValid(relid))
+                                       {
+                                               /* Run parse analysis ... */
+                                               stmts = transformAlterTableStmt(relid, atstmt,
+                                                                                                               queryString);
 
-               case T_CreatedbStmt:
-                       PreventTransactionChain(isTopLevel, "CREATE DATABASE");
-                       createdb((CreatedbStmt *) parsetree);
-                       break;
+                                               /* ... ensure we have an event trigger context ... */
+                                               EventTriggerAlterTableStart(parsetree);
+                                               EventTriggerAlterTableRelid(relid);
 
-               case T_AlterDatabaseStmt:
-                       AlterDatabase((AlterDatabaseStmt *) parsetree, isTopLevel);
-                       break;
+                                               /* ... and do it */
+                                               foreach(l, stmts)
+                                               {
+                                                       Node       *stmt = (Node *) lfirst(l);
 
-               case T_AlterDatabaseSetStmt:
-                       AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
-                       break;
+                                                       if (IsA(stmt, AlterTableStmt))
+                                                       {
+                                                               /* Do the table alteration proper */
+                                                               AlterTable(relid, lockmode,
+                                                                                  (AlterTableStmt *) stmt);
+                                                       }
+                                                       else
+                                                       {
+                                                               /*
+                                                                * Recurse for anything else.  If we need to
+                                                                * do so, "close" the current complex-command
+                                                                * set, and start a new one at the bottom;
+                                                                * this is needed to ensure the ordering of
+                                                                * queued commands is consistent with the way
+                                                                * they are executed here.
+                                                                */
+                                                               PlannedStmt *wrapper;
+
+                                                               EventTriggerAlterTableEnd();
+                                                               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,
+                                                                                          None_Receiver,
+                                                                                          NULL);
+                                                               EventTriggerAlterTableStart(parsetree);
+                                                               EventTriggerAlterTableRelid(relid);
+                                                       }
 
-               case T_DropdbStmt:
-                       {
-                               DropdbStmt *stmt = (DropdbStmt *) parsetree;
+                                                       /* Need CCI between commands */
+                                                       if (lnext(l) != NULL)
+                                                               CommandCounterIncrement();
+                                               }
 
-                               PreventTransactionChain(isTopLevel, "DROP DATABASE");
-                               dropdb(stmt->dbname, stmt->missing_ok);
-                       }
-                       break;
+                                               /* done */
+                                               EventTriggerAlterTableEnd();
+                                       }
+                                       else
+                                               ereport(NOTICE,
+                                                 (errmsg("relation \"%s\" does not exist, skipping",
+                                                                 atstmt->relation->relname)));
+                               }
 
-                       /* Query-level asynchronous notification */
-               case T_NotifyStmt:
-                       {
-                               NotifyStmt *stmt = (NotifyStmt *) parsetree;
+                               /* ALTER TABLE stashes commands internally */
+                               commandCollected = true;
+                               break;
 
-                               PreventCommandDuringRecovery("NOTIFY");
-                               Async_Notify(stmt->conditionname, stmt->payload);
-                       }
-                       break;
+                       case T_AlterDomainStmt:
+                               {
+                                       AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
 
-               case T_ListenStmt:
-                       {
-                               ListenStmt *stmt = (ListenStmt *) parsetree;
+                                       /*
+                                        * Some or all of these functions are recursive to cover
+                                        * inherited things, so permission checks are done there.
+                                        */
+                                       switch (stmt->subtype)
+                                       {
+                                               case 'T':               /* ALTER DOMAIN DEFAULT */
+
+                                                       /*
+                                                        * Recursively alter column default for table and,
+                                                        * if requested, for descendants
+                                                        */
+                                                       address =
+                                                               AlterDomainDefault(stmt->typeName,
+                                                                                                  stmt->def);
+                                                       break;
+                                               case 'N':               /* ALTER DOMAIN DROP NOT NULL */
+                                                       address =
+                                                               AlterDomainNotNull(stmt->typeName,
+                                                                                                  false);
+                                                       break;
+                                               case 'O':               /* ALTER DOMAIN SET NOT NULL */
+                                                       address =
+                                                               AlterDomainNotNull(stmt->typeName,
+                                                                                                  true);
+                                                       break;
+                                               case 'C':               /* ADD CONSTRAINT */
+                                                       address =
+                                                               AlterDomainAddConstraint(stmt->typeName,
+                                                                                                                stmt->def,
+                                                                                                                &secondaryObject);
+                                                       break;
+                                               case 'X':               /* DROP CONSTRAINT */
+                                                       address =
+                                                               AlterDomainDropConstraint(stmt->typeName,
+                                                                                                                 stmt->name,
+                                                                                                                 stmt->behavior,
+                                                                                                                 stmt->missing_ok);
+                                                       break;
+                                               case 'V':               /* VALIDATE CONSTRAINT */
+                                                       address =
+                                                               AlterDomainValidateConstraint(stmt->typeName,
+                                                                                                                         stmt->name);
+                                                       break;
+                                               default:                /* oops */
+                                                       elog(ERROR, "unrecognized alter domain type: %d",
+                                                                (int) stmt->subtype);
+                                                       break;
+                                       }
+                               }
+                               break;
 
-                               PreventCommandDuringRecovery("LISTEN");
-                               CheckRestrictedOperation("LISTEN");
-                               Async_Listen(stmt->conditionname);
-                       }
-                       break;
+                               /*
+                                * ************* object creation / destruction **************
+                                */
+                       case T_DefineStmt:
+                               {
+                                       DefineStmt *stmt = (DefineStmt *) parsetree;
 
-               case T_UnlistenStmt:
-                       {
-                               UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
+                                       switch (stmt->kind)
+                                       {
+                                               case OBJECT_AGGREGATE:
+                                                       address =
+                                                               DefineAggregate(pstate, stmt->defnames, stmt->args,
+                                                                                               stmt->oldstyle,
+                                                                                               stmt->definition);
+                                                       break;
+                                               case OBJECT_OPERATOR:
+                                                       Assert(stmt->args == NIL);
+                                                       address = DefineOperator(stmt->defnames,
+                                                                                                        stmt->definition);
+                                                       break;
+                                               case OBJECT_TYPE:
+                                                       Assert(stmt->args == NIL);
+                                                       address = DefineType(pstate,
+                                                                                                stmt->defnames,
+                                                                                                stmt->definition);
+                                                       break;
+                                               case OBJECT_TSPARSER:
+                                                       Assert(stmt->args == NIL);
+                                                       address = DefineTSParser(stmt->defnames,
+                                                                                                        stmt->definition);
+                                                       break;
+                                               case OBJECT_TSDICTIONARY:
+                                                       Assert(stmt->args == NIL);
+                                                       address = DefineTSDictionary(stmt->defnames,
+                                                                                                                stmt->definition);
+                                                       break;
+                                               case OBJECT_TSTEMPLATE:
+                                                       Assert(stmt->args == NIL);
+                                                       address = DefineTSTemplate(stmt->defnames,
+                                                                                                          stmt->definition);
+                                                       break;
+                                               case OBJECT_TSCONFIGURATION:
+                                                       Assert(stmt->args == NIL);
+                                                       address = DefineTSConfiguration(stmt->defnames,
+                                                                                                                       stmt->definition,
+                                                                                                                       &secondaryObject);
+                                                       break;
+                                               case OBJECT_COLLATION:
+                                                       Assert(stmt->args == NIL);
+                                                       address = DefineCollation(pstate,
+                                                                                                         stmt->defnames,
+                                                                                                         stmt->definition);
+                                                       break;
+                                               default:
+                                                       elog(ERROR, "unrecognized define stmt type: %d",
+                                                                (int) stmt->kind);
+                                                       break;
+                                       }
+                               }
+                               break;
 
-                               PreventCommandDuringRecovery("UNLISTEN");
-                               CheckRestrictedOperation("UNLISTEN");
-                               if (stmt->conditionname)
-                                       Async_Unlisten(stmt->conditionname);
-                               else
-                                       Async_UnlistenAll();
-                       }
-                       break;
+                       case T_IndexStmt:       /* CREATE INDEX */
+                               {
+                                       IndexStmt  *stmt = (IndexStmt *) parsetree;
+                                       Oid                     relid;
+                                       LOCKMODE        lockmode;
 
-               case T_LoadStmt:
-                       {
-                               LoadStmt   *stmt = (LoadStmt *) parsetree;
+                                       if (stmt->concurrent)
+                                               PreventTransactionChain(isTopLevel,
+                                                                                               "CREATE INDEX CONCURRENTLY");
+
+                                       /*
+                                        * Look up the relation OID just once, right here at the
+                                        * beginning, so that we don't end up repeating the name
+                                        * lookup later and latching onto a different relation
+                                        * partway through.  To avoid lock upgrade hazards, it's
+                                        * important that we take the strongest lock that will
+                                        * eventually be needed here, so the lockmode calculation
+                                        * needs to match what DefineIndex() does.
+                                        */
+                                       lockmode = stmt->concurrent ? ShareUpdateExclusiveLock
+                                               : ShareLock;
+                                       relid =
+                                               RangeVarGetRelidExtended(stmt->relation, lockmode,
+                                                                                                false, false,
+                                                                                                RangeVarCallbackOwnsRelation,
+                                                                                                NULL);
+
+                                       /* Run parse analysis ... */
+                                       stmt = transformIndexStmt(relid, stmt, queryString);
+
+                                       /* ... and do it */
+                                       EventTriggerAlterTableStart(parsetree);
+                                       address =
+                                               DefineIndex(relid,              /* OID of heap relation */
+                                                                       stmt,
+                                                                       InvalidOid, /* no predefined OID */
+                                                                       false,          /* is_alter_table */
+                                                                       true,           /* check_rights */
+                                                                       false,          /* skip_build */
+                                                                       false);         /* quiet */
+
+                                       /*
+                                        * Add the CREATE INDEX node itself to stash right away;
+                                        * if there were any commands stashed in the ALTER TABLE
+                                        * code, we need them to appear after this one.
+                                        */
+                                       EventTriggerCollectSimpleCommand(address, secondaryObject,
+                                                                                                        parsetree);
+                                       commandCollected = true;
+                                       EventTriggerAlterTableEnd();
+                               }
+                               break;
 
-                               closeAllVfds(); /* probably not necessary... */
-                               /* Allowed names are restricted if you're not superuser */
-                               load_file(stmt->filename, !superuser());
-                       }
-                       break;
+                       case T_CreateExtensionStmt:
+                               address = CreateExtension(pstate, (CreateExtensionStmt *) parsetree);
+                               break;
 
-               case T_ClusterStmt:
-                       /* we choose to allow this during "read only" transactions */
-                       PreventCommandDuringRecovery("CLUSTER");
-                       cluster((ClusterStmt *) parsetree, isTopLevel);
-                       break;
+                       case T_AlterExtensionStmt:
+                               address = ExecAlterExtensionStmt(pstate, (AlterExtensionStmt *) parsetree);
+                               break;
 
-               case T_VacuumStmt:
-                       /* we choose to allow this during "read only" transactions */
-                       PreventCommandDuringRecovery("VACUUM");
-                       vacuum((VacuumStmt *) parsetree, InvalidOid, true, NULL, false,
-                                  isTopLevel);
-                       break;
+                       case T_AlterExtensionContentsStmt:
+                               address = ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree,
+                                                                                                                &secondaryObject);
+                               break;
 
-               case T_ExplainStmt:
-                       ExplainQuery((ExplainStmt *) parsetree, queryString, params, dest);
-                       break;
+                       case T_CreateFdwStmt:
+                               address = CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
+                               break;
 
-               case T_VariableSetStmt:
-                       ExecSetVariableStmt((VariableSetStmt *) parsetree);
-                       break;
+                       case T_AlterFdwStmt:
+                               address = AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
+                               break;
 
-               case T_VariableShowStmt:
-                       {
-                               VariableShowStmt *n = (VariableShowStmt *) parsetree;
+                       case T_CreateForeignServerStmt:
+                               address = CreateForeignServer((CreateForeignServerStmt *) parsetree);
+                               break;
 
-                               GetPGVariable(n->name, dest);
-                       }
-                       break;
+                       case T_AlterForeignServerStmt:
+                               address = AlterForeignServer((AlterForeignServerStmt *) parsetree);
+                               break;
 
-               case T_DiscardStmt:
-                       /* should we allow DISCARD PLANS? */
-                       CheckRestrictedOperation("DISCARD");
-                       DiscardCommand((DiscardStmt *) parsetree, isTopLevel);
-                       break;
+                       case T_CreateUserMappingStmt:
+                               address = CreateUserMapping((CreateUserMappingStmt *) parsetree);
+                               break;
 
-               case T_CreateTrigStmt:
-                       (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
-                                                                InvalidOid, InvalidOid, false);
-                       break;
+                       case T_AlterUserMappingStmt:
+                               address = AlterUserMapping((AlterUserMappingStmt *) parsetree);
+                               break;
 
-               case T_DropPropertyStmt:
-                       {
-                               DropPropertyStmt *stmt = (DropPropertyStmt *) parsetree;
+                       case T_DropUserMappingStmt:
+                               RemoveUserMapping((DropUserMappingStmt *) parsetree);
+                               /* no commands stashed for DROP */
+                               commandCollected = true;
+                               break;
+
+                       case T_ImportForeignSchemaStmt:
+                               ImportForeignSchema((ImportForeignSchemaStmt *) parsetree);
+                               /* commands are stashed inside ImportForeignSchema */
+                               commandCollected = true;
+                               break;
 
-                               switch (stmt->removeType)
+                       case T_CompositeTypeStmt:       /* CREATE TYPE (composite) */
                                {
-                                       case OBJECT_RULE:
-                                               /* RemoveRewriteRule checks permissions */
-                                               RemoveRewriteRule(stmt->relation, stmt->property,
-                                                                                 stmt->behavior, stmt->missing_ok);
-                                               break;
-                                       case OBJECT_TRIGGER:
-                                               /* DropTrigger checks permissions */
-                                               DropTrigger(stmt->relation, stmt->property,
-                                                                       stmt->behavior, stmt->missing_ok);
-                                               break;
-                                       default:
-                                               elog(ERROR, "unrecognized object type: %d",
-                                                        (int) stmt->removeType);
-                                               break;
+                                       CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
+
+                                       address = DefineCompositeType(stmt->typevar,
+                                                                                                 stmt->coldeflist);
                                }
-                       }
-                       break;
+                               break;
 
-               case T_CreatePLangStmt:
-                       CreateProceduralLanguage((CreatePLangStmt *) parsetree);
-                       break;
+                       case T_CreateEnumStmt:          /* CREATE TYPE AS ENUM */
+                               address = DefineEnum((CreateEnumStmt *) parsetree);
+                               break;
 
-               case T_DropPLangStmt:
-                       DropProceduralLanguage((DropPLangStmt *) parsetree);
-                       break;
+                       case T_CreateRangeStmt:         /* CREATE TYPE AS RANGE */
+                               address = DefineRange((CreateRangeStmt *) parsetree);
+                               break;
 
-                       /*
-                        * ******************************** DOMAIN statements ****
-                        */
-               case T_CreateDomainStmt:
-                       DefineDomain((CreateDomainStmt *) parsetree);
-                       break;
+                       case T_AlterEnumStmt:           /* ALTER TYPE (enum) */
+                               address = AlterEnum((AlterEnumStmt *) parsetree);
+                               break;
 
-                       /*
-                        * ******************************** ROLE statements ****
-                        */
-               case T_CreateRoleStmt:
-                       CreateRole((CreateRoleStmt *) parsetree);
-                       break;
+                       case T_ViewStmt:        /* CREATE VIEW */
+                               EventTriggerAlterTableStart(parsetree);
+                               address = DefineView((ViewStmt *) parsetree, queryString,
+                                                                        pstmt->stmt_location, pstmt->stmt_len);
+                               EventTriggerCollectSimpleCommand(address, secondaryObject,
+                                                                                                parsetree);
+                               /* stashed internally */
+                               commandCollected = true;
+                               EventTriggerAlterTableEnd();
+                               break;
 
-               case T_AlterRoleStmt:
-                       AlterRole((AlterRoleStmt *) parsetree);
-                       break;
+                       case T_CreateFunctionStmt:      /* CREATE FUNCTION */
+                               address = CreateFunction(pstate, (CreateFunctionStmt *) parsetree);
+                               break;
 
-               case T_AlterRoleSetStmt:
-                       AlterRoleSet((AlterRoleSetStmt *) parsetree);
-                       break;
+                       case T_AlterFunctionStmt:       /* ALTER FUNCTION */
+                               address = AlterFunction(pstate, (AlterFunctionStmt *) parsetree);
+                               break;
 
-               case T_DropRoleStmt:
-                       DropRole((DropRoleStmt *) parsetree);
-                       break;
+                       case T_RuleStmt:        /* CREATE RULE */
+                               address = DefineRule((RuleStmt *) parsetree, queryString);
+                               break;
 
-               case T_DropOwnedStmt:
-                       DropOwnedObjects((DropOwnedStmt *) parsetree);
-                       break;
+                       case T_CreateSeqStmt:
+                               address = DefineSequence(pstate, (CreateSeqStmt *) parsetree);
+                               break;
 
-               case T_ReassignOwnedStmt:
-                       ReassignOwnedObjects((ReassignOwnedStmt *) parsetree);
-                       break;
+                       case T_AlterSeqStmt:
+                               address = AlterSequence(pstate, (AlterSeqStmt *) parsetree);
+                               break;
 
-               case T_LockStmt:
+                       case T_CreateTableAsStmt:
+                               address = ExecCreateTableAs((CreateTableAsStmt *) parsetree,
+                                                                                queryString, params, completionTag);
+                               break;
 
-                       /*
-                        * Since the lock would just get dropped immediately, LOCK TABLE
-                        * outside a transaction block is presumed to be user error.
-                        */
-                       RequireTransactionChain(isTopLevel, "LOCK TABLE");
-                       LockTableCommand((LockStmt *) parsetree);
-                       break;
+                       case T_RefreshMatViewStmt:
 
-               case T_ConstraintsSetStmt:
-                       AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
-                       break;
+                               /*
+                                * REFRSH CONCURRENTLY executes some DDL commands internally.
+                                * Inhibit DDL command collection here to avoid those commands
+                                * from showing up in the deparsed command queue.  The refresh
+                                * command itself is queued, which is enough.
+                                */
+                               EventTriggerInhibitCommandCollection();
+                               PG_TRY();
+                               {
+                                       address = ExecRefreshMatView((RefreshMatViewStmt *) parsetree,
+                                                                                queryString, params, completionTag);
+                               }
+                               PG_CATCH();
+                               {
+                                       EventTriggerUndoInhibitCommandCollection();
+                                       PG_RE_THROW();
+                               }
+                               PG_END_TRY();
+                               EventTriggerUndoInhibitCommandCollection();
+                               break;
 
-               case T_CheckPointStmt:
-                       if (!superuser())
-                               ereport(ERROR,
-                                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                                errmsg("must be superuser to do CHECKPOINT")));
+                       case T_CreateTrigStmt:
+                               address = CreateTrigger((CreateTrigStmt *) parsetree,
+                                                                               queryString, InvalidOid, InvalidOid,
+                                                                               InvalidOid, InvalidOid, false);
+                               break;
 
-                       /*
-                        * You might think we should have a PreventCommandDuringRecovery()
-                        * here, but we interpret a CHECKPOINT command during recovery as
-                        * a request for a restartpoint instead. We allow this since it
-                        * can be a useful way of reducing switchover time when using
-                        * various forms of replication.
-                        */
-                       RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT |
-                                                         (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
-                       break;
+                       case T_CreatePLangStmt:
+                               address = CreateProceduralLanguage((CreatePLangStmt *) parsetree);
+                               break;
+
+                       case T_CreateDomainStmt:
+                               address = DefineDomain((CreateDomainStmt *) parsetree);
+                               break;
+
+                       case T_CreateConversionStmt:
+                               address = CreateConversionCommand((CreateConversionStmt *) parsetree);
+                               break;
+
+                       case T_CreateCastStmt:
+                               address = CreateCast((CreateCastStmt *) parsetree);
+                               break;
+
+                       case T_CreateOpClassStmt:
+                               DefineOpClass((CreateOpClassStmt *) parsetree);
+                               /* command is stashed in DefineOpClass */
+                               commandCollected = true;
+                               break;
+
+                       case T_CreateOpFamilyStmt:
+                               address = DefineOpFamily((CreateOpFamilyStmt *) parsetree);
+                               break;
+
+                       case T_CreateTransformStmt:
+                               address = CreateTransform((CreateTransformStmt *) parsetree);
+                               break;
+
+                       case T_AlterOpFamilyStmt:
+                               AlterOpFamily((AlterOpFamilyStmt *) parsetree);
+                               /* commands are stashed in AlterOpFamily */
+                               commandCollected = true;
+                               break;
+
+                       case T_AlterTSDictionaryStmt:
+                               address = AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
+                               break;
+
+                       case T_AlterTSConfigurationStmt:
+                               AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
+
+                               /*
+                                * Commands are stashed in MakeConfigurationMapping and
+                                * DropConfigurationMapping, which are called from
+                                * AlterTSConfiguration
+                                */
+                               commandCollected = true;
+                               break;
+
+                       case T_AlterTableMoveAllStmt:
+                               AlterTableMoveAll((AlterTableMoveAllStmt *) parsetree);
+                               /* commands are stashed in AlterTableMoveAll */
+                               commandCollected = true;
+                               break;
+
+                       case T_DropStmt:
+                               ExecDropStmt((DropStmt *) parsetree, isTopLevel);
+                               /* no commands stashed for DROP */
+                               commandCollected = true;
+                               break;
+
+                       case T_RenameStmt:
+                               address = ExecRenameStmt((RenameStmt *) parsetree);
+                               break;
 
-               case T_ReindexStmt:
-                       {
-                               ReindexStmt *stmt = (ReindexStmt *) parsetree;
+                       case T_AlterObjectDependsStmt:
+                               address =
+                                       ExecAlterObjectDependsStmt((AlterObjectDependsStmt *) parsetree,
+                                                                                          &secondaryObject);
+                               break;
 
-                               /* we choose to allow this during "read only" transactions */
-                               PreventCommandDuringRecovery("REINDEX");
-                               switch (stmt->kind)
-                               {
-                                       case OBJECT_INDEX:
-                                               ReindexIndex(stmt->relation);
-                                               break;
-                                       case OBJECT_TABLE:
-                                               ReindexTable(stmt->relation);
-                                               break;
-                                       case OBJECT_DATABASE:
+                       case T_AlterObjectSchemaStmt:
+                               address =
+                                       ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree,
+                                                                                         &secondaryObject);
+                               break;
 
-                                               /*
-                                                * This cannot run inside a user transaction block; if
-                                                * we were inside a transaction, then its commit- and
-                                                * start-transaction-command calls would not have the
-                                                * intended effect!
-                                                */
-                                               PreventTransactionChain(isTopLevel,
-                                                                                               "REINDEX DATABASE");
-                                               ReindexDatabase(stmt->name,
-                                                                               stmt->do_system, stmt->do_user);
-                                               break;
-                                       default:
-                                               elog(ERROR, "unrecognized object type: %d",
-                                                        (int) stmt->kind);
-                                               break;
-                               }
+                       case T_AlterOwnerStmt:
+                               address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
                                break;
-                       }
-                       break;
 
-               case T_CreateConversionStmt:
-                       CreateConversionCommand((CreateConversionStmt *) parsetree);
-                       break;
+                       case T_AlterOperatorStmt:
+                               address = AlterOperator((AlterOperatorStmt *) parsetree);
+                               break;
 
-               case T_CreateCastStmt:
-                       CreateCast((CreateCastStmt *) parsetree);
-                       break;
+                       case T_CommentStmt:
+                               address = CommentObject((CommentStmt *) parsetree);
+                               break;
 
-               case T_DropCastStmt:
-                       DropCast((DropCastStmt *) parsetree);
-                       break;
+                       case T_GrantStmt:
+                               ExecuteGrantStmt((GrantStmt *) parsetree);
+                               /* commands are stashed in ExecGrantStmt_oids */
+                               commandCollected = true;
+                               break;
 
-               case T_CreateOpClassStmt:
-                       DefineOpClass((CreateOpClassStmt *) parsetree);
-                       break;
+                       case T_DropOwnedStmt:
+                               DropOwnedObjects((DropOwnedStmt *) parsetree);
+                               /* no commands stashed for DROP */
+                               commandCollected = true;
+                               break;
 
-               case T_CreateOpFamilyStmt:
-                       DefineOpFamily((CreateOpFamilyStmt *) parsetree);
-                       break;
+                       case T_AlterDefaultPrivilegesStmt:
+                               ExecAlterDefaultPrivilegesStmt(pstate, (AlterDefaultPrivilegesStmt *) parsetree);
+                               EventTriggerCollectAlterDefPrivs((AlterDefaultPrivilegesStmt *) parsetree);
+                               commandCollected = true;
+                               break;
 
-               case T_AlterOpFamilyStmt:
-                       AlterOpFamily((AlterOpFamilyStmt *) parsetree);
-                       break;
+                       case T_CreatePolicyStmt:        /* CREATE POLICY */
+                               address = CreatePolicy((CreatePolicyStmt *) parsetree);
+                               break;
 
-               case T_RemoveOpClassStmt:
-                       RemoveOpClass((RemoveOpClassStmt *) parsetree);
-                       break;
+                       case T_AlterPolicyStmt:         /* ALTER POLICY */
+                               address = AlterPolicy((AlterPolicyStmt *) parsetree);
+                               break;
 
-               case T_RemoveOpFamilyStmt:
-                       RemoveOpFamily((RemoveOpFamilyStmt *) parsetree);
-                       break;
+                       case T_SecLabelStmt:
+                               address = ExecSecLabelStmt((SecLabelStmt *) parsetree);
+                               break;
 
-               case T_AlterTSDictionaryStmt:
-                       AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
-                       break;
+                       case T_CreateAmStmt:
+                               address = CreateAccessMethod((CreateAmStmt *) parsetree);
+                               break;
 
-               case T_AlterTSConfigurationStmt:
-                       AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
-                       break;
+                       default:
+                               elog(ERROR, "unrecognized node type: %d",
+                                        (int) nodeTag(parsetree));
+                               break;
+               }
+
+               /*
+                * Remember the object so that ddl_command_end event triggers have
+                * access to it.
+                */
+               if (!commandCollected)
+                       EventTriggerCollectSimpleCommand(address, secondaryObject,
+                                                                                        parsetree);
+
+               if (isCompleteQuery)
+               {
+                       EventTriggerSQLDrop(parsetree);
+                       EventTriggerDDLCommandEnd(parsetree);
+               }
+       }
+       PG_CATCH();
+       {
+               if (needCleanup)
+                       EventTriggerEndCompleteQuery();
+               PG_RE_THROW();
+       }
+       PG_END_TRY();
+
+       if (needCleanup)
+               EventTriggerEndCompleteQuery();
+}
+
+/*
+ * Dispatch function for DropStmt
+ */
+static void
+ExecDropStmt(DropStmt *stmt, bool isTopLevel)
+{
+       switch (stmt->removeType)
+       {
+               case OBJECT_INDEX:
+                       if (stmt->concurrent)
+                               PreventTransactionChain(isTopLevel,
+                                                                               "DROP INDEX CONCURRENTLY");
+                       /* fall through */
 
+               case OBJECT_TABLE:
+               case OBJECT_SEQUENCE:
+               case OBJECT_VIEW:
+               case OBJECT_MATVIEW:
+               case OBJECT_FOREIGN_TABLE:
+                       RemoveRelations(stmt);
+                       break;
                default:
-                       elog(ERROR, "unrecognized node type: %d",
-                                (int) nodeTag(parsetree));
+                       RemoveObjects(stmt);
                        break;
        }
 }
 
+
 /*
  * UtilityReturnsTuples
  *             Return "true" if this utility statement will send output to the
@@ -1327,8 +1669,6 @@ UtilityReturnsTuples(Node *parsetree)
                                ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
                                PreparedStatement *entry;
 
-                               if (stmt->into)
-                                       return false;
                                entry = FetchPreparedStatement(stmt->name, false);
                                if (!entry)
                                        return false;           /* not our business to raise error */
@@ -1379,8 +1719,6 @@ UtilityTupleDescriptor(Node *parsetree)
                                ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
                                PreparedStatement *entry;
 
-                               if (stmt->into)
-                                       return NULL;
                                entry = FetchPreparedStatement(stmt->name, false);
                                if (!entry)
                                        return NULL;    /* not our business to raise error */
@@ -1414,11 +1752,8 @@ QueryReturnsTuples(Query *parsetree)
        switch (parsetree->commandType)
        {
                case CMD_SELECT:
-                       /* returns tuples ... unless it's DECLARE CURSOR or SELECT INTO */
-                       if (parsetree->utilityStmt == NULL &&
-                               parsetree->intoClause == NULL)
-                               return true;
-                       break;
+                       /* returns tuples */
+                       return true;
                case CMD_INSERT:
                case CMD_UPDATE:
                case CMD_DELETE:
@@ -1438,6 +1773,54 @@ QueryReturnsTuples(Query *parsetree)
 #endif
 
 
+/*
+ * UtilityContainsQuery
+ *             Return the contained Query, or NULL if there is none
+ *
+ * Certain utility statements, such as EXPLAIN, contain a plannable Query.
+ * This function encapsulates knowledge of exactly which ones do.
+ * We assume it is invoked only on already-parse-analyzed statements
+ * (else the contained parsetree isn't a Query yet).
+ *
+ * In some cases (currently, only EXPLAIN of CREATE TABLE AS/SELECT INTO and
+ * CREATE MATERIALIZED VIEW), potentially Query-containing utility statements
+ * can be nested.  This function will drill down to a non-utility Query, or
+ * return NULL if none.
+ */
+Query *
+UtilityContainsQuery(Node *parsetree)
+{
+       Query      *qry;
+
+       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));
+                       if (qry->commandType == CMD_UTILITY)
+                               return UtilityContainsQuery(qry->utilityStmt);
+                       return qry;
+
+               case T_CreateTableAsStmt:
+                       qry = (Query *) ((CreateTableAsStmt *) parsetree)->query;
+                       Assert(IsA(qry, Query));
+                       if (qry->commandType == CMD_UTILITY)
+                               return UtilityContainsQuery(qry->utilityStmt);
+                       return qry;
+
+               default:
+                       return NULL;
+       }
+}
+
+
 /*
  * AlterObjectTypeCommandTag
  *             helper function for CreateCommandTag
@@ -1466,9 +1849,6 @@ AlterObjectTypeCommandTag(ObjectType objtype)
                case OBJECT_COLUMN:
                        tag = "ALTER TABLE";
                        break;
-               case OBJECT_CONSTRAINT:
-                       tag = "ALTER TABLE";
-                       break;
                case OBJECT_CONVERSION:
                        tag = "ALTER CONVERSION";
                        break;
@@ -1476,6 +1856,7 @@ AlterObjectTypeCommandTag(ObjectType objtype)
                        tag = "ALTER DATABASE";
                        break;
                case OBJECT_DOMAIN:
+               case OBJECT_DOMCONSTRAINT:
                        tag = "ALTER DOMAIN";
                        break;
                case OBJECT_EXTENSION:
@@ -1511,6 +1892,9 @@ AlterObjectTypeCommandTag(ObjectType objtype)
                case OBJECT_OPFAMILY:
                        tag = "ALTER OPERATOR FAMILY";
                        break;
+               case OBJECT_POLICY:
+                       tag = "ALTER POLICY";
+                       break;
                case OBJECT_ROLE:
                        tag = "ALTER ROLE";
                        break;
@@ -1524,6 +1908,7 @@ AlterObjectTypeCommandTag(ObjectType objtype)
                        tag = "ALTER SEQUENCE";
                        break;
                case OBJECT_TABLE:
+               case OBJECT_TABCONSTRAINT:
                        tag = "ALTER TABLE";
                        break;
                case OBJECT_TABLESPACE:
@@ -1532,6 +1917,9 @@ AlterObjectTypeCommandTag(ObjectType objtype)
                case OBJECT_TRIGGER:
                        tag = "ALTER TRIGGER";
                        break;
+               case OBJECT_EVENT_TRIGGER:
+                       tag = "ALTER EVENT TRIGGER";
+                       break;
                case OBJECT_TSCONFIGURATION:
                        tag = "ALTER TEXT SEARCH CONFIGURATION";
                        break;
@@ -1550,6 +1938,9 @@ AlterObjectTypeCommandTag(ObjectType objtype)
                case OBJECT_VIEW:
                        tag = "ALTER VIEW";
                        break;
+               case OBJECT_MATVIEW:
+                       tag = "ALTER MATERIALIZED VIEW";
+                       break;
                default:
                        tag = "???";
                        break;
@@ -1561,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.
@@ -1576,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";
@@ -1711,10 +2108,6 @@ CreateCommandTag(Node *parsetree)
                        tag = "ALTER FOREIGN DATA WRAPPER";
                        break;
 
-               case T_DropFdwStmt:
-                       tag = "DROP FOREIGN DATA WRAPPER";
-                       break;
-
                case T_CreateForeignServerStmt:
                        tag = "CREATE SERVER";
                        break;
@@ -1723,10 +2116,6 @@ CreateCommandTag(Node *parsetree)
                        tag = "ALTER SERVER";
                        break;
 
-               case T_DropForeignServerStmt:
-                       tag = "DROP SERVER";
-                       break;
-
                case T_CreateUserMappingStmt:
                        tag = "CREATE USER MAPPING";
                        break;
@@ -1743,6 +2132,10 @@ CreateCommandTag(Node *parsetree)
                        tag = "CREATE FOREIGN TABLE";
                        break;
 
+               case T_ImportForeignSchemaStmt:
+                       tag = "IMPORT FOREIGN SCHEMA";
+                       break;
+
                case T_DropStmt:
                        switch (((DropStmt *) parsetree)->removeType)
                        {
@@ -1755,6 +2148,9 @@ CreateCommandTag(Node *parsetree)
                                case OBJECT_VIEW:
                                        tag = "DROP VIEW";
                                        break;
+                               case OBJECT_MATVIEW:
+                                       tag = "DROP MATERIALIZED VIEW";
+                                       break;
                                case OBJECT_INDEX:
                                        tag = "DROP INDEX";
                                        break;
@@ -1791,6 +2187,51 @@ CreateCommandTag(Node *parsetree)
                                case OBJECT_EXTENSION:
                                        tag = "DROP EXTENSION";
                                        break;
+                               case OBJECT_FUNCTION:
+                                       tag = "DROP FUNCTION";
+                                       break;
+                               case OBJECT_AGGREGATE:
+                                       tag = "DROP AGGREGATE";
+                                       break;
+                               case OBJECT_OPERATOR:
+                                       tag = "DROP OPERATOR";
+                                       break;
+                               case OBJECT_LANGUAGE:
+                                       tag = "DROP LANGUAGE";
+                                       break;
+                               case OBJECT_CAST:
+                                       tag = "DROP CAST";
+                                       break;
+                               case OBJECT_TRIGGER:
+                                       tag = "DROP TRIGGER";
+                                       break;
+                               case OBJECT_EVENT_TRIGGER:
+                                       tag = "DROP EVENT TRIGGER";
+                                       break;
+                               case OBJECT_RULE:
+                                       tag = "DROP RULE";
+                                       break;
+                               case OBJECT_FDW:
+                                       tag = "DROP FOREIGN DATA WRAPPER";
+                                       break;
+                               case OBJECT_FOREIGN_SERVER:
+                                       tag = "DROP SERVER";
+                                       break;
+                               case OBJECT_OPCLASS:
+                                       tag = "DROP OPERATOR CLASS";
+                                       break;
+                               case OBJECT_OPFAMILY:
+                                       tag = "DROP OPERATOR FAMILY";
+                                       break;
+                               case OBJECT_POLICY:
+                                       tag = "DROP POLICY";
+                                       break;
+                               case OBJECT_TRANSFORM:
+                                       tag = "DROP TRANSFORM";
+                                       break;
+                               case OBJECT_ACCESS_METHOD:
+                                       tag = "DROP ACCESS METHOD";
+                                       break;
                                default:
                                        tag = "???";
                        }
@@ -1816,6 +2257,10 @@ CreateCommandTag(Node *parsetree)
                        tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType);
                        break;
 
+               case T_AlterObjectDependsStmt:
+                       tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType);
+                       break;
+
                case T_AlterObjectSchemaStmt:
                        tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType);
                        break;
@@ -1824,6 +2269,10 @@ CreateCommandTag(Node *parsetree)
                        tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType);
                        break;
 
+               case T_AlterTableMoveAllStmt:
+                       tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype);
+                       break;
+
                case T_AlterTableStmt:
                        tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);
                        break;
@@ -1883,6 +2332,9 @@ CreateCommandTag(Node *parsetree)
                                case OBJECT_COLLATION:
                                        tag = "CREATE COLLATION";
                                        break;
+                               case OBJECT_ACCESS_METHOD:
+                                       tag = "CREATE ACCESS METHOD";
+                                       break;
                                default:
                                        tag = "???";
                        }
@@ -1896,6 +2348,10 @@ CreateCommandTag(Node *parsetree)
                        tag = "CREATE TYPE";
                        break;
 
+               case T_CreateRangeStmt:
+                       tag = "CREATE TYPE";
+                       break;
+
                case T_AlterEnumStmt:
                        tag = "ALTER TYPE";
                        break;
@@ -1924,23 +2380,6 @@ CreateCommandTag(Node *parsetree)
                        tag = "ALTER SEQUENCE";
                        break;
 
-               case T_RemoveFuncStmt:
-                       switch (((RemoveFuncStmt *) parsetree)->kind)
-                       {
-                               case OBJECT_FUNCTION:
-                                       tag = "DROP FUNCTION";
-                                       break;
-                               case OBJECT_AGGREGATE:
-                                       tag = "DROP AGGREGATE";
-                                       break;
-                               case OBJECT_OPERATOR:
-                                       tag = "DROP OPERATOR";
-                                       break;
-                               default:
-                                       tag = "???";
-                       }
-                       break;
-
                case T_DoStmt:
                        tag = "DO";
                        break;
@@ -1992,6 +2431,31 @@ CreateCommandTag(Node *parsetree)
                        tag = "EXPLAIN";
                        break;
 
+               case T_CreateTableAsStmt:
+                       switch (((CreateTableAsStmt *) parsetree)->relkind)
+                       {
+                               case OBJECT_TABLE:
+                                       if (((CreateTableAsStmt *) parsetree)->is_select_into)
+                                               tag = "SELECT INTO";
+                                       else
+                                               tag = "CREATE TABLE AS";
+                                       break;
+                               case OBJECT_MATVIEW:
+                                       tag = "CREATE MATERIALIZED VIEW";
+                                       break;
+                               default:
+                                       tag = "???";
+                       }
+                       break;
+
+               case T_RefreshMatViewStmt:
+                       tag = "REFRESH MATERIALIZED VIEW";
+                       break;
+
+               case T_AlterSystemStmt:
+                       tag = "ALTER SYSTEM";
+                       break;
+
                case T_VariableSetStmt:
                        switch (((VariableSetStmt *) parsetree)->kind)
                        {
@@ -2026,35 +2490,32 @@ CreateCommandTag(Node *parsetree)
                                case DISCARD_TEMP:
                                        tag = "DISCARD TEMP";
                                        break;
+                               case DISCARD_SEQUENCES:
+                                       tag = "DISCARD SEQUENCES";
+                                       break;
                                default:
                                        tag = "???";
                        }
                        break;
 
+               case T_CreateTransformStmt:
+                       tag = "CREATE TRANSFORM";
+                       break;
+
                case T_CreateTrigStmt:
                        tag = "CREATE TRIGGER";
                        break;
 
-               case T_DropPropertyStmt:
-                       switch (((DropPropertyStmt *) parsetree)->removeType)
-                       {
-                               case OBJECT_TRIGGER:
-                                       tag = "DROP TRIGGER";
-                                       break;
-                               case OBJECT_RULE:
-                                       tag = "DROP RULE";
-                                       break;
-                               default:
-                                       tag = "???";
-                       }
+               case T_CreateEventTrigStmt:
+                       tag = "CREATE EVENT TRIGGER";
                        break;
 
-               case T_CreatePLangStmt:
-                       tag = "CREATE LANGUAGE";
+               case T_AlterEventTrigStmt:
+                       tag = "ALTER EVENT TRIGGER";
                        break;
 
-               case T_DropPLangStmt:
-                       tag = "DROP LANGUAGE";
+               case T_CreatePLangStmt:
+                       tag = "CREATE LANGUAGE";
                        break;
 
                case T_CreateRoleStmt:
@@ -2105,10 +2566,6 @@ CreateCommandTag(Node *parsetree)
                        tag = "CREATE CAST";
                        break;
 
-               case T_DropCastStmt:
-                       tag = "DROP CAST";
-                       break;
-
                case T_CreateOpClassStmt:
                        tag = "CREATE OPERATOR CLASS";
                        break;
@@ -2121,12 +2578,8 @@ CreateCommandTag(Node *parsetree)
                        tag = "ALTER OPERATOR FAMILY";
                        break;
 
-               case T_RemoveOpClassStmt:
-                       tag = "DROP OPERATOR CLASS";
-                       break;
-
-               case T_RemoveOpFamilyStmt:
-                       tag = "DROP OPERATOR FAMILY";
+               case T_AlterOperatorStmt:
+                       tag = "ALTER OPERATOR";
                        break;
 
                case T_AlterTSDictionaryStmt:
@@ -2137,6 +2590,18 @@ CreateCommandTag(Node *parsetree)
                        tag = "ALTER TEXT SEARCH CONFIGURATION";
                        break;
 
+               case T_CreatePolicyStmt:
+                       tag = "CREATE POLICY";
+                       break;
+
+               case T_AlterPolicyStmt:
+                       tag = "ALTER POLICY";
+                       break;
+
+               case T_CreateAmStmt:
+                       tag = "CREATE ACCESS METHOD";
+                       break;
+
                case T_PrepareStmt:
                        tag = "PREPARE";
                        break;
@@ -2170,20 +2635,27 @@ 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->intoClause != NULL)
-                                                       tag = "SELECT INTO";
-                                               else if (stmt->rowMarks != NIL)
+                                               if (stmt->rowMarks != NIL)
                                                {
                                                        /* not 100% but probably close enough */
-                                                       if (((PlanRowMark *) linitial(stmt->rowMarks))->markType == ROW_MARK_EXCLUSIVE)
-                                                               tag = "SELECT FOR UPDATE";
-                                                       else
-                                                               tag = "SELECT FOR SHARE";
+                                                       switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength)
+                                                       {
+                                                               case LCS_FORKEYSHARE:
+                                                                       tag = "SELECT FOR KEY SHARE";
+                                                                       break;
+                                                               case LCS_FORSHARE:
+                                                                       tag = "SELECT FOR SHARE";
+                                                                       break;
+                                                               case LCS_FORNOKEYUPDATE:
+                                                                       tag = "SELECT FOR NO KEY UPDATE";
+                                                                       break;
+                                                               case LCS_FORUPDATE:
+                                                                       tag = "SELECT FOR UPDATE";
+                                                                       break;
+                                                               default:
+                                                                       tag = "SELECT";
+                                                                       break;
+                                                       }
                                                }
                                                else
                                                        tag = "SELECT";
@@ -2197,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);
@@ -2220,20 +2695,27 @@ 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->intoClause != NULL)
-                                                       tag = "SELECT INTO";
-                                               else if (stmt->rowMarks != NIL)
+                                               if (stmt->rowMarks != NIL)
                                                {
                                                        /* not 100% but probably close enough */
-                                                       if (((RowMarkClause *) linitial(stmt->rowMarks))->forUpdate)
-                                                               tag = "SELECT FOR UPDATE";
-                                                       else
-                                                               tag = "SELECT FOR SHARE";
+                                                       switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength)
+                                                       {
+                                                               case LCS_FORKEYSHARE:
+                                                                       tag = "SELECT FOR KEY SHARE";
+                                                                       break;
+                                                               case LCS_FORSHARE:
+                                                                       tag = "SELECT FOR SHARE";
+                                                                       break;
+                                                               case LCS_FORNOKEYUPDATE:
+                                                                       tag = "SELECT FOR NO KEY UPDATE";
+                                                                       break;
+                                                               case LCS_FORUPDATE:
+                                                                       tag = "SELECT FOR UPDATE";
+                                                                       break;
+                                                               default:
+                                                                       tag = "???";
+                                                                       break;
+                                                       }
                                                }
                                                else
                                                        tag = "SELECT";
@@ -2273,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.
@@ -2285,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:
@@ -2294,7 +2782,7 @@ GetCommandLogLevel(Node *parsetree)
 
                case T_SelectStmt:
                        if (((SelectStmt *) parsetree)->intoClause)
-                               lev = LOGSTMT_DDL;              /* CREATE AS, SELECT INTO */
+                               lev = LOGSTMT_DDL;              /* SELECT INTO */
                        else
                                lev = LOGSTMT_ALL;
                        break;
@@ -2339,13 +2827,12 @@ GetCommandLogLevel(Node *parsetree)
 
                case T_CreateFdwStmt:
                case T_AlterFdwStmt:
-               case T_DropFdwStmt:
                case T_CreateForeignServerStmt:
                case T_AlterForeignServerStmt:
-               case T_DropForeignServerStmt:
                case T_CreateUserMappingStmt:
                case T_AlterUserMappingStmt:
                case T_DropUserMappingStmt:
+               case T_ImportForeignSchemaStmt:
                        lev = LOGSTMT_DDL;
                        break;
 
@@ -2388,8 +2875,8 @@ GetCommandLogLevel(Node *parsetree)
 
                                /* Look through an EXECUTE to the referenced stmt */
                                ps = FetchPreparedStatement(stmt->name, false);
-                               if (ps)
-                                       lev = GetCommandLogLevel(ps->plansource->raw_parse_tree);
+                               if (ps && ps->plansource->raw_parse_tree)
+                                       lev = GetCommandLogLevel(ps->plansource->raw_parse_tree->stmt);
                                else
                                        lev = LOGSTMT_ALL;
                        }
@@ -2403,6 +2890,10 @@ GetCommandLogLevel(Node *parsetree)
                        lev = LOGSTMT_DDL;
                        break;
 
+               case T_AlterObjectDependsStmt:
+                       lev = LOGSTMT_DDL;
+                       break;
+
                case T_AlterObjectSchemaStmt:
                        lev = LOGSTMT_DDL;
                        break;
@@ -2411,6 +2902,7 @@ GetCommandLogLevel(Node *parsetree)
                        lev = LOGSTMT_DDL;
                        break;
 
+               case T_AlterTableMoveAllStmt:
                case T_AlterTableStmt:
                        lev = LOGSTMT_DDL;
                        break;
@@ -2443,6 +2935,10 @@ GetCommandLogLevel(Node *parsetree)
                        lev = LOGSTMT_DDL;
                        break;
 
+               case T_CreateRangeStmt:
+                       lev = LOGSTMT_DDL;
+                       break;
+
                case T_AlterEnumStmt:
                        lev = LOGSTMT_DDL;
                        break;
@@ -2475,10 +2971,6 @@ GetCommandLogLevel(Node *parsetree)
                        lev = LOGSTMT_DDL;
                        break;
 
-               case T_RemoveFuncStmt:
-                       lev = LOGSTMT_DDL;
-                       break;
-
                case T_DoStmt:
                        lev = LOGSTMT_ALL;
                        break;
@@ -2546,6 +3038,18 @@ GetCommandLogLevel(Node *parsetree)
                        }
                        break;
 
+               case T_CreateTableAsStmt:
+                       lev = LOGSTMT_DDL;
+                       break;
+
+               case T_RefreshMatViewStmt:
+                       lev = LOGSTMT_DDL;
+                       break;
+
+               case T_AlterSystemStmt:
+                       lev = LOGSTMT_DDL;
+                       break;
+
                case T_VariableSetStmt:
                        lev = LOGSTMT_ALL;
                        break;
@@ -2562,15 +3066,15 @@ GetCommandLogLevel(Node *parsetree)
                        lev = LOGSTMT_DDL;
                        break;
 
-               case T_DropPropertyStmt:
+               case T_CreateEventTrigStmt:
                        lev = LOGSTMT_DDL;
                        break;
 
-               case T_CreatePLangStmt:
+               case T_AlterEventTrigStmt:
                        lev = LOGSTMT_DDL;
                        break;
 
-               case T_DropPLangStmt:
+               case T_CreatePLangStmt:
                        lev = LOGSTMT_DDL;
                        break;
 
@@ -2626,15 +3130,15 @@ GetCommandLogLevel(Node *parsetree)
                        lev = LOGSTMT_DDL;
                        break;
 
-               case T_DropCastStmt:
+               case T_CreateOpClassStmt:
                        lev = LOGSTMT_DDL;
                        break;
 
-               case T_CreateOpClassStmt:
+               case T_CreateOpFamilyStmt:
                        lev = LOGSTMT_DDL;
                        break;
 
-               case T_CreateOpFamilyStmt:
+               case T_CreateTransformStmt:
                        lev = LOGSTMT_DDL;
                        break;
 
@@ -2642,11 +3146,11 @@ GetCommandLogLevel(Node *parsetree)
                        lev = LOGSTMT_DDL;
                        break;
 
-               case T_RemoveOpClassStmt:
+               case T_CreatePolicyStmt:
                        lev = LOGSTMT_DDL;
                        break;
 
-               case T_RemoveOpFamilyStmt:
+               case T_AlterPolicyStmt:
                        lev = LOGSTMT_DDL;
                        break;
 
@@ -2658,6 +3162,10 @@ GetCommandLogLevel(Node *parsetree)
                        lev = LOGSTMT_DDL;
                        break;
 
+               case T_CreateAmStmt:
+                       lev = LOGSTMT_DDL;
+                       break;
+
                        /* already-planned queries */
                case T_PlannedStmt:
                        {
@@ -2666,10 +3174,7 @@ GetCommandLogLevel(Node *parsetree)
                                switch (stmt->commandType)
                                {
                                        case CMD_SELECT:
-                                               if (stmt->intoClause != NULL)
-                                                       lev = LOGSTMT_DDL;      /* CREATE AS, SELECT INTO */
-                                               else
-                                                       lev = LOGSTMT_ALL;      /* SELECT or DECLARE CURSOR */
+                                               lev = LOGSTMT_ALL;
                                                break;
 
                                        case CMD_UPDATE:
@@ -2678,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);
@@ -2695,10 +3204,7 @@ GetCommandLogLevel(Node *parsetree)
                                switch (stmt->commandType)
                                {
                                        case CMD_SELECT:
-                                               if (stmt->intoClause != NULL)
-                                                       lev = LOGSTMT_DDL;      /* CREATE AS, SELECT INTO */
-                                               else
-                                                       lev = LOGSTMT_ALL;      /* SELECT or DECLARE CURSOR */
+                                               lev = LOGSTMT_ALL;
                                                break;
 
                                        case CMD_UPDATE: