deparse: add EventTriggerStashCommand() calls to ProcessUtilitySlow
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 25 Sep 2014 18:50:37 +0000 (15:50 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 7 Apr 2015 17:09:36 +0000 (14:09 -0300)
These calls add each executed command to the event trigger command
stash.

src/backend/commands/schemacmds.c
src/backend/tcop/utility.c

index c090ed220f8ee3d7fc46feec62de249d07e66eef..89ac973419ff7310a6e92bf43426363cdbe808da 100644 (file)
@@ -25,6 +25,7 @@
 #include "catalog/objectaccess.h"
 #include "catalog/pg_namespace.h"
 #include "commands/dbcommands.h"
+#include "commands/event_trigger.h"
 #include "commands/schemacmds.h"
 #include "miscadmin.h"
 #include "parser/parse_utilcmd.h"
@@ -52,6 +53,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
    Oid         saved_uid;
    int         save_sec_context;
    AclResult   aclresult;
+   ObjectAddress address;
 
    GetUserIdAndSecContext(&saved_uid, &save_sec_context);
 
@@ -142,6 +144,18 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
    /* XXX should we clear overridePath->useTemp? */
    PushOverrideSearchPath(overridePath);
 
+   address.classId = NamespaceRelationId;
+   address.objectId = namespaceId;
+   address.objectSubId = 0;
+
+   /*
+    * Report the new schema to possibly interested event triggers.  Note we
+    * must do this here and not in ProcessUtilitySlow because otherwise the
+    * objects created below are reported before the schema, which would be
+    * wrong.
+    */
+   EventTriggerStashCommand(address, InvalidObjectAddress, (Node *) stmt);
+
    /*
     * Examine the list of commands embedded in the CREATE SCHEMA command, and
     * reorganize them into a sequentially executable order with no forward
index 3361436d1faa4e1cfc964cf723541df480420e00..fde1ddbdb878da397486747ddb9c76491d0cc504 100644 (file)
@@ -889,7 +889,9 @@ ProcessUtilitySlow(Node *parsetree,
    bool        isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
    bool        isCompleteQuery = (context <= PROCESS_UTILITY_QUERY);
    bool        needCleanup;
+   bool        commandStashed = false;
    ObjectAddress address;
+   ObjectAddress secondaryObject = InvalidObjectAddress;
 
    /* All event trigger calls are done only when isCompleteQuery is true */
    needCleanup = isCompleteQuery && EventTriggerBeginCompleteQuery();
@@ -908,6 +910,12 @@ ProcessUtilitySlow(Node *parsetree,
            case T_CreateSchemaStmt:
                CreateSchemaCommand((CreateSchemaStmt *) parsetree,
                                    queryString);
+               /*
+                * CreateSchemaCommand calls EventTriggerStashCommand
+                * internally, for reasons explained there, so turn off
+                * command collection below.
+                */
+               commandStashed = true;
                break;
 
            case T_CreateStmt:
@@ -934,6 +942,8 @@ ProcessUtilitySlow(Node *parsetree,
                            address = DefineRelation((CreateStmt *) stmt,
                                                     RELKIND_RELATION,
                                                     InvalidOid, NULL);
+                           EventTriggerStashCommand(address, secondaryObject,
+                                                    stmt);
 
                            /*
                             * Let NewRelationCreateToastTable decide if this
@@ -966,10 +976,16 @@ ProcessUtilitySlow(Node *parsetree,
                                                     InvalidOid, NULL);
                            CreateForeignTable((CreateForeignTableStmt *) stmt,
                                               address.objectId);
+                           EventTriggerStashCommand(address, secondaryObject,
+                                                    stmt);
                        }
                        else
                        {
-                           /* Recurse for anything else */
+                           /*
+                            * Recurse for anything else.  Note the recursive
+                            * call will stash the objects so created into our
+                            * event trigger context.
+                            */
                            ProcessUtility(stmt,
                                           queryString,
                                           PROCESS_UTILITY_SUBCOMMAND,
@@ -982,6 +998,12 @@ ProcessUtilitySlow(Node *parsetree,
                        if (lnext(l) != NULL)
                            CommandCounterIncrement();
                    }
+
+                   /*
+                    * The multiple commands generated here are stashed
+                    * individually, so disable collection below.
+                    */
+                   commandStashed = true;
                }
                break;
 
@@ -1040,6 +1062,9 @@ ProcessUtilitySlow(Node *parsetree,
                          (errmsg("relation \"%s\" does not exist, skipping",
                                  atstmt->relation->relname)));
                }
+
+               /* ALTER TABLE stashes commands internally */
+               commandStashed = true;
                break;
 
            case T_AlterDomainStmt:
@@ -1058,31 +1083,37 @@ ProcessUtilitySlow(Node *parsetree,
                             * Recursively alter column default for table and,
                             * if requested, for descendants
                             */
-                           AlterDomainDefault(stmt->typeName,
-                                              stmt->def);
+                           address =
+                               AlterDomainDefault(stmt->typeName,
+                                                  stmt->def);
                            break;
                        case 'N':       /* ALTER DOMAIN DROP NOT NULL */
-                           AlterDomainNotNull(stmt->typeName,
-                                              false);
+                           address =
+                               AlterDomainNotNull(stmt->typeName,
+                                                  false);
                            break;
                        case 'O':       /* ALTER DOMAIN SET NOT NULL */
-                           AlterDomainNotNull(stmt->typeName,
-                                              true);
+                           address =
+                               AlterDomainNotNull(stmt->typeName,
+                                                  true);
                            break;
                        case 'C':       /* ADD CONSTRAINT */
-                           AlterDomainAddConstraint(stmt->typeName,
-                                                    stmt->def,
-                                                    NULL);
+                           address =
+                               AlterDomainAddConstraint(stmt->typeName,
+                                                        stmt->def,
+                                                        &secondaryObject);
                            break;
                        case 'X':       /* DROP CONSTRAINT */
-                           AlterDomainDropConstraint(stmt->typeName,
-                                                     stmt->name,
-                                                     stmt->behavior,
-                                                     stmt->missing_ok);
+                           address =
+                               AlterDomainDropConstraint(stmt->typeName,
+                                                         stmt->name,
+                                                         stmt->behavior,
+                                                         stmt->missing_ok);
                            break;
                        case 'V':       /* VALIDATE CONSTRAINT */
-                           AlterDomainValidateConstraint(stmt->typeName,
-                                                         stmt->name);
+                           address =
+                               AlterDomainValidateConstraint(stmt->typeName,
+                                                             stmt->name);
                            break;
                        default:        /* oops */
                            elog(ERROR, "unrecognized alter domain type: %d",
@@ -1102,41 +1133,46 @@ ProcessUtilitySlow(Node *parsetree,
                    switch (stmt->kind)
                    {
                        case OBJECT_AGGREGATE:
-                           DefineAggregate(stmt->defnames, stmt->args,
-                                           stmt->oldstyle, stmt->definition,
-                                           queryString);
+                           address =
+                               DefineAggregate(stmt->defnames, stmt->args,
+                                               stmt->oldstyle,
+                                               stmt->definition, queryString);
                            break;
                        case OBJECT_OPERATOR:
                            Assert(stmt->args == NIL);
-                           DefineOperator(stmt->defnames, stmt->definition);
+                           address = DefineOperator(stmt->defnames,
+                                                     stmt->definition);
                            break;
                        case OBJECT_TYPE:
                            Assert(stmt->args == NIL);
-                           DefineType(stmt->defnames, stmt->definition);
+                           address = DefineType(stmt->defnames,
+                                                 stmt->definition);
                            break;
                        case OBJECT_TSPARSER:
                            Assert(stmt->args == NIL);
-                           DefineTSParser(stmt->defnames, stmt->definition);
+                           address = DefineTSParser(stmt->defnames,
+                                                     stmt->definition);
                            break;
                        case OBJECT_TSDICTIONARY:
                            Assert(stmt->args == NIL);
-                           DefineTSDictionary(stmt->defnames,
-                                              stmt->definition);
+                           address = DefineTSDictionary(stmt->defnames,
+                                                         stmt->definition);
                            break;
                        case OBJECT_TSTEMPLATE:
                            Assert(stmt->args == NIL);
-                           DefineTSTemplate(stmt->defnames,
-                                            stmt->definition);
+                           address = DefineTSTemplate(stmt->defnames,
+                                                       stmt->definition);
                            break;
                        case OBJECT_TSCONFIGURATION:
                            Assert(stmt->args == NIL);
-                           DefineTSConfiguration(stmt->defnames,
-                                                 stmt->definition,
-                                                 NULL);
+                           address = DefineTSConfiguration(stmt->defnames,
+                                                            stmt->definition,
+                                                            &secondaryObject);
                            break;
                        case OBJECT_COLLATION:
                            Assert(stmt->args == NIL);
-                           DefineCollation(stmt->defnames, stmt->definition);
+                           address = DefineCollation(stmt->defnames,
+                                                      stmt->definition);
                            break;
                        default:
                            elog(ERROR, "unrecognized define stmt type: %d",
@@ -1177,204 +1213,250 @@ ProcessUtilitySlow(Node *parsetree,
                    stmt = transformIndexStmt(relid, stmt, queryString);
 
                    /* ... and do it */
-                   DefineIndex(relid,  /* OID of heap relation */
-                               stmt,
-                               InvalidOid,     /* no predefined OID */
-                               false,  /* is_alter_table */
-                               true,   /* check_rights */
-                               false,  /* skip_build */
-                               false); /* quiet */
+                   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.
+                    */
+                   EventTriggerStashCommand(address, secondaryObject,
+                                            parsetree);
+                   commandStashed = true;
                }
                break;
 
            case T_CreateExtensionStmt:
-               CreateExtension((CreateExtensionStmt *) parsetree);
+               address = CreateExtension((CreateExtensionStmt *) parsetree);
                break;
 
            case T_AlterExtensionStmt:
-               ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree);
+               address = ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree);
                break;
 
            case T_AlterExtensionContentsStmt:
-               ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree,
-                                              NULL);
+               address = ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree,
+                                                         &secondaryObject);
                break;
 
            case T_CreateFdwStmt:
-               CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
+               address = CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
                break;
 
            case T_AlterFdwStmt:
-               AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
+               address = AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
                break;
 
            case T_CreateForeignServerStmt:
-               CreateForeignServer((CreateForeignServerStmt *) parsetree);
+               address = CreateForeignServer((CreateForeignServerStmt *) parsetree);
                break;
 
            case T_AlterForeignServerStmt:
-               AlterForeignServer((AlterForeignServerStmt *) parsetree);
+               address = AlterForeignServer((AlterForeignServerStmt *) parsetree);
                break;
 
            case T_CreateUserMappingStmt:
-               CreateUserMapping((CreateUserMappingStmt *) parsetree);
+               address = CreateUserMapping((CreateUserMappingStmt *) parsetree);
                break;
 
            case T_AlterUserMappingStmt:
-               AlterUserMapping((AlterUserMappingStmt *) parsetree);
+               address = AlterUserMapping((AlterUserMappingStmt *) parsetree);
                break;
 
            case T_DropUserMappingStmt:
                RemoveUserMapping((DropUserMappingStmt *) parsetree);
+               /* no commands stashed for DROP */
+               commandStashed = true;
                break;
 
            case T_ImportForeignSchemaStmt:
                ImportForeignSchema((ImportForeignSchemaStmt *) parsetree);
+               /* commands are stashed inside ImportForeignSchema */
+               commandStashed = true;
                break;
 
            case T_CompositeTypeStmt:   /* CREATE TYPE (composite) */
                {
                    CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
 
-                   DefineCompositeType(stmt->typevar, stmt->coldeflist);
+                   address = DefineCompositeType(stmt->typevar,
+                                                 stmt->coldeflist);
                }
                break;
 
            case T_CreateEnumStmt:      /* CREATE TYPE AS ENUM */
-               DefineEnum((CreateEnumStmt *) parsetree);
+               address = DefineEnum((CreateEnumStmt *) parsetree);
                break;
 
            case T_CreateRangeStmt:     /* CREATE TYPE AS RANGE */
-               DefineRange((CreateRangeStmt *) parsetree);
+               address = DefineRange((CreateRangeStmt *) parsetree);
                break;
 
            case T_AlterEnumStmt:       /* ALTER TYPE (enum) */
-               AlterEnum((AlterEnumStmt *) parsetree, isTopLevel);
+               address = AlterEnum((AlterEnumStmt *) parsetree, isTopLevel);
                break;
 
            case T_ViewStmt:    /* CREATE VIEW */
-               DefineView((ViewStmt *) parsetree, queryString);
+               address = DefineView((ViewStmt *) parsetree, queryString);
+               EventTriggerStashCommand(address, secondaryObject, parsetree);
+               /* stashed internally */
+               commandStashed = true;
                break;
 
            case T_CreateFunctionStmt:  /* CREATE FUNCTION */
-               CreateFunction((CreateFunctionStmt *) parsetree, queryString);
+               address = CreateFunction((CreateFunctionStmt *) parsetree, queryString);
                break;
 
            case T_AlterFunctionStmt:   /* ALTER FUNCTION */
-               AlterFunction((AlterFunctionStmt *) parsetree);
+               address = AlterFunction((AlterFunctionStmt *) parsetree);
                break;
 
            case T_RuleStmt:    /* CREATE RULE */
-               DefineRule((RuleStmt *) parsetree, queryString);
+               address = DefineRule((RuleStmt *) parsetree, queryString);
                break;
 
            case T_CreateSeqStmt:
-               DefineSequence((CreateSeqStmt *) parsetree);
+               address = DefineSequence((CreateSeqStmt *) parsetree);
                break;
 
            case T_AlterSeqStmt:
-               AlterSequence((AlterSeqStmt *) parsetree);
+               address = AlterSequence((AlterSeqStmt *) parsetree);
                break;
 
            case T_CreateTableAsStmt:
-               ExecCreateTableAs((CreateTableAsStmt *) parsetree,
+               address = ExecCreateTableAs((CreateTableAsStmt *) parsetree,
                                  queryString, params, completionTag);
                break;
 
            case T_RefreshMatViewStmt:
-               ExecRefreshMatView((RefreshMatViewStmt *) parsetree,
-                                  queryString, params, completionTag);
+               /*
+                * 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_CreateTrigStmt:
-               (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
-                                    InvalidOid, InvalidOid, InvalidOid,
-                                    InvalidOid, false);
+               address = CreateTrigger((CreateTrigStmt *) parsetree,
+                                        queryString, InvalidOid, InvalidOid,
+                                        InvalidOid, InvalidOid, false);
                break;
 
            case T_CreatePLangStmt:
-               CreateProceduralLanguage((CreatePLangStmt *) parsetree);
+               address = CreateProceduralLanguage((CreatePLangStmt *) parsetree);
                break;
 
            case T_CreateDomainStmt:
-               DefineDomain((CreateDomainStmt *) parsetree);
+               address = DefineDomain((CreateDomainStmt *) parsetree);
                break;
 
            case T_CreateConversionStmt:
-               CreateConversionCommand((CreateConversionStmt *) parsetree);
+               address = CreateConversionCommand((CreateConversionStmt *) parsetree);
                break;
 
            case T_CreateCastStmt:
-               CreateCast((CreateCastStmt *) parsetree);
+               address = CreateCast((CreateCastStmt *) parsetree);
                break;
 
            case T_CreateOpClassStmt:
-               DefineOpClass((CreateOpClassStmt *) parsetree);
+               address = DefineOpClass((CreateOpClassStmt *) parsetree);
                break;
 
            case T_CreateOpFamilyStmt:
-               DefineOpFamily((CreateOpFamilyStmt *) parsetree);
+               address = DefineOpFamily((CreateOpFamilyStmt *) parsetree);
                break;
 
            case T_AlterOpFamilyStmt:
                AlterOpFamily((AlterOpFamilyStmt *) parsetree);
+               /* commands are stashed in AlterOpFamily */
+               commandStashed = true;
                break;
 
            case T_AlterTSDictionaryStmt:
-               AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
+               address = AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
                break;
 
            case T_AlterTSConfigurationStmt:
-               AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
+               address = AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
                break;
 
            case T_AlterTableMoveAllStmt:
                AlterTableMoveAll((AlterTableMoveAllStmt *) parsetree);
+               /* commands are stashed in AlterTableMoveAll */
+               commandStashed = true;
                break;
 
            case T_DropStmt:
                ExecDropStmt((DropStmt *) parsetree, isTopLevel);
+               /* no commands stashed for DROP */
+               commandStashed = true;
                break;
 
            case T_RenameStmt:
-               ExecRenameStmt((RenameStmt *) parsetree);
+               address = ExecRenameStmt((RenameStmt *) parsetree);
                break;
 
            case T_AlterObjectSchemaStmt:
-               ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree,
-                                         NULL);
+               address =
+                   ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree,
+                                             &secondaryObject);
                break;
 
            case T_AlterOwnerStmt:
-               ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
+               address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
                break;
 
            case T_CommentStmt:
-               CommentObject((CommentStmt *) parsetree);
+               address = CommentObject((CommentStmt *) parsetree);
                break;
 
            case T_GrantStmt:
                ExecuteGrantStmt((GrantStmt *) parsetree);
+               /* commands are stashed in ExecGrantStmt_oids */
+               commandStashed = true;
                break;
 
            case T_DropOwnedStmt:
                DropOwnedObjects((DropOwnedStmt *) parsetree);
+               /* no commands stashed for DROP */
+               commandStashed = true;
                break;
 
            case T_AlterDefaultPrivilegesStmt:
                ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree);
+               /* XXX FIXME WTF? */
                break;
 
            case T_CreatePolicyStmt:    /* CREATE POLICY */
-               CreatePolicy((CreatePolicyStmt *) parsetree);
+               address = CreatePolicy((CreatePolicyStmt *) parsetree);
                break;
 
            case T_AlterPolicyStmt:     /* ALTER POLICY */
-               AlterPolicy((AlterPolicyStmt *) parsetree);
+               address = AlterPolicy((AlterPolicyStmt *) parsetree);
                break;
 
            case T_SecLabelStmt:
-               ExecSecLabelStmt((SecLabelStmt *) parsetree);
+               address = ExecSecLabelStmt((SecLabelStmt *) parsetree);
                break;
 
            default:
@@ -1383,6 +1465,13 @@ ProcessUtilitySlow(Node *parsetree,
                break;
        }
 
+       /*
+        * Remember the object so that ddl_command_end event triggers have
+        * access to it.
+        */
+       if (!commandStashed)
+           EventTriggerStashCommand(address, secondaryObject, parsetree);
+
        if (isCompleteQuery)
        {
            EventTriggerSQLDrop(parsetree);