LCOV - differential code coverage report
Current view: top level - src/backend/commands - event_trigger.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 84.1 % 697 586 7 34 70 17 255 10 304 22 268 2 7
Current Date: 2023-04-08 15:15:32 Functions: 95.2 % 42 40 1 1 30 3 7 1 30
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * event_trigger.c
       4                 :  *    PostgreSQL EVENT TRIGGER support code.
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  * IDENTIFICATION
      10                 :  *    src/backend/commands/event_trigger.c
      11                 :  *
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : #include "postgres.h"
      15                 : 
      16                 : #include "access/htup_details.h"
      17                 : #include "access/table.h"
      18                 : #include "access/xact.h"
      19                 : #include "catalog/catalog.h"
      20                 : #include "catalog/dependency.h"
      21                 : #include "catalog/indexing.h"
      22                 : #include "catalog/objectaccess.h"
      23                 : #include "catalog/pg_event_trigger.h"
      24                 : #include "catalog/pg_namespace.h"
      25                 : #include "catalog/pg_opclass.h"
      26                 : #include "catalog/pg_opfamily.h"
      27                 : #include "catalog/pg_proc.h"
      28                 : #include "catalog/pg_trigger.h"
      29                 : #include "catalog/pg_ts_config.h"
      30                 : #include "catalog/pg_type.h"
      31                 : #include "commands/dbcommands.h"
      32                 : #include "commands/event_trigger.h"
      33                 : #include "commands/extension.h"
      34                 : #include "commands/trigger.h"
      35                 : #include "funcapi.h"
      36                 : #include "lib/ilist.h"
      37                 : #include "miscadmin.h"
      38                 : #include "parser/parse_func.h"
      39                 : #include "pgstat.h"
      40                 : #include "tcop/deparse_utility.h"
      41                 : #include "tcop/utility.h"
      42                 : #include "utils/acl.h"
      43                 : #include "utils/builtins.h"
      44                 : #include "utils/evtcache.h"
      45                 : #include "utils/fmgroids.h"
      46                 : #include "utils/lsyscache.h"
      47                 : #include "utils/memutils.h"
      48                 : #include "utils/rel.h"
      49                 : #include "utils/syscache.h"
      50                 : 
      51                 : typedef struct EventTriggerQueryState
      52                 : {
      53                 :     /* memory context for this state's objects */
      54                 :     MemoryContext cxt;
      55                 : 
      56                 :     /* sql_drop */
      57                 :     slist_head  SQLDropList;
      58                 :     bool        in_sql_drop;
      59                 : 
      60                 :     /* table_rewrite */
      61                 :     Oid         table_rewrite_oid;  /* InvalidOid, or set for table_rewrite
      62                 :                                      * event */
      63                 :     int         table_rewrite_reason;   /* AT_REWRITE reason */
      64                 : 
      65                 :     /* Support for command collection */
      66                 :     bool        commandCollectionInhibited;
      67                 :     CollectedCommand *currentCommand;
      68                 :     List       *commandList;    /* list of CollectedCommand; see
      69                 :                                  * deparse_utility.h */
      70                 :     struct EventTriggerQueryState *previous;
      71                 : } EventTriggerQueryState;
      72                 : 
      73                 : static EventTriggerQueryState *currentEventTriggerState = NULL;
      74                 : 
      75                 : /* Support for dropped objects */
      76                 : typedef struct SQLDropObject
      77                 : {
      78                 :     ObjectAddress address;
      79                 :     const char *schemaname;
      80                 :     const char *objname;
      81                 :     const char *objidentity;
      82                 :     const char *objecttype;
      83                 :     List       *addrnames;
      84                 :     List       *addrargs;
      85                 :     bool        original;
      86                 :     bool        normal;
      87                 :     bool        istemp;
      88                 :     slist_node  next;
      89                 : } SQLDropObject;
      90                 : 
      91                 : static void AlterEventTriggerOwner_internal(Relation rel,
      92                 :                                             HeapTuple tup,
      93                 :                                             Oid newOwnerId);
      94                 : static void error_duplicate_filter_variable(const char *defname);
      95                 : static Datum filter_list_to_array(List *filterlist);
      96                 : static Oid  insert_event_trigger_tuple(const char *trigname, const char *eventname,
      97                 :                                        Oid evtOwner, Oid funcoid, List *taglist);
      98                 : static void validate_ddl_tags(const char *filtervar, List *taglist);
      99                 : static void validate_table_rewrite_tags(const char *filtervar, List *taglist);
     100                 : static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
     101                 : static const char *stringify_grant_objtype(ObjectType objtype);
     102                 : static const char *stringify_adefprivs_objtype(ObjectType objtype);
     103                 : 
     104                 : /*
     105                 :  * Create an event trigger.
     106                 :  */
     107                 : Oid
     108 CBC          80 : CreateEventTrigger(CreateEventTrigStmt *stmt)
     109                 : {
     110                 :     HeapTuple   tuple;
     111                 :     Oid         funcoid;
     112                 :     Oid         funcrettype;
     113              80 :     Oid         evtowner = GetUserId();
     114                 :     ListCell   *lc;
     115              80 :     List       *tags = NULL;
     116                 : 
     117                 :     /*
     118                 :      * It would be nice to allow database owners or even regular users to do
     119                 :      * this, but there are obvious privilege escalation risks which would have
     120                 :      * to somehow be plugged first.
     121                 :      */
     122              80 :     if (!superuser())
     123               3 :         ereport(ERROR,
     124                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     125                 :                  errmsg("permission denied to create event trigger \"%s\"",
     126                 :                         stmt->trigname),
     127                 :                  errhint("Must be superuser to create an event trigger.")));
     128                 : 
     129                 :     /* Validate event name. */
     130              77 :     if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
     131              37 :         strcmp(stmt->eventname, "ddl_command_end") != 0 &&
     132              24 :         strcmp(stmt->eventname, "sql_drop") != 0 &&
     133              11 :         strcmp(stmt->eventname, "table_rewrite") != 0)
     134               3 :         ereport(ERROR,
     135                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
     136                 :                  errmsg("unrecognized event name \"%s\"",
     137                 :                         stmt->eventname)));
     138                 : 
     139                 :     /* Validate filter conditions. */
     140             110 :     foreach(lc, stmt->whenclause)
     141                 :     {
     142              42 :         DefElem    *def = (DefElem *) lfirst(lc);
     143                 : 
     144              42 :         if (strcmp(def->defname, "tag") == 0)
     145                 :         {
     146              39 :             if (tags != NULL)
     147               3 :                 error_duplicate_filter_variable(def->defname);
     148              36 :             tags = (List *) def->arg;
     149                 :         }
     150                 :         else
     151               3 :             ereport(ERROR,
     152                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
     153                 :                      errmsg("unrecognized filter variable \"%s\"", def->defname)));
     154                 :     }
     155                 : 
     156                 :     /* Validate tag list, if any. */
     157              68 :     if ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||
     158              34 :          strcmp(stmt->eventname, "ddl_command_end") == 0 ||
     159              21 :          strcmp(stmt->eventname, "sql_drop") == 0)
     160              60 :         && tags != NULL)
     161              33 :         validate_ddl_tags("tag", tags);
     162              35 :     else if (strcmp(stmt->eventname, "table_rewrite") == 0
     163               8 :              && tags != NULL)
     164 UBC           0 :         validate_table_rewrite_tags("tag", tags);
     165                 : 
     166                 :     /*
     167                 :      * Give user a nice error message if an event trigger of the same name
     168                 :      * already exists.
     169                 :      */
     170 CBC          50 :     tuple = SearchSysCache1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
     171              50 :     if (HeapTupleIsValid(tuple))
     172 UBC           0 :         ereport(ERROR,
     173                 :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     174                 :                  errmsg("event trigger \"%s\" already exists",
     175                 :                         stmt->trigname)));
     176                 : 
     177                 :     /* Find and validate the trigger function. */
     178 CBC          50 :     funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
     179              50 :     funcrettype = get_func_rettype(funcoid);
     180              50 :     if (funcrettype != EVENT_TRIGGEROID)
     181               3 :         ereport(ERROR,
     182                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     183                 :                  errmsg("function %s must return type %s",
     184                 :                         NameListToString(stmt->funcname), "event_trigger")));
     185                 : 
     186                 :     /* Insert catalog entries. */
     187              47 :     return insert_event_trigger_tuple(stmt->trigname, stmt->eventname,
     188                 :                                       evtowner, funcoid, tags);
     189                 : }
     190                 : 
     191                 : /*
     192                 :  * Validate DDL command tags.
     193                 :  */
     194                 : static void
     195              33 : validate_ddl_tags(const char *filtervar, List *taglist)
     196                 : {
     197                 :     ListCell   *lc;
     198                 : 
     199              81 :     foreach(lc, taglist)
     200                 :     {
     201              66 :         const char *tagstr = strVal(lfirst(lc));
     202              66 :         CommandTag  commandTag = GetCommandTagEnum(tagstr);
     203                 : 
     204              66 :         if (commandTag == CMDTAG_UNKNOWN)
     205               6 :             ereport(ERROR,
     206                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
     207                 :                      errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
     208                 :                             tagstr, filtervar)));
     209              60 :         if (!command_tag_event_trigger_ok(commandTag))
     210              12 :             ereport(ERROR,
     211                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     212                 :             /* translator: %s represents an SQL statement name */
     213                 :                      errmsg("event triggers are not supported for %s",
     214                 :                             tagstr)));
     215                 :     }
     216              15 : }
     217                 : 
     218                 : /*
     219                 :  * Validate DDL command tags for event table_rewrite.
     220                 :  */
     221                 : static void
     222 UBC           0 : validate_table_rewrite_tags(const char *filtervar, List *taglist)
     223                 : {
     224                 :     ListCell   *lc;
     225                 : 
     226               0 :     foreach(lc, taglist)
     227                 :     {
     228               0 :         const char *tagstr = strVal(lfirst(lc));
     229               0 :         CommandTag  commandTag = GetCommandTagEnum(tagstr);
     230                 : 
     231               0 :         if (!command_tag_table_rewrite_ok(commandTag))
     232               0 :             ereport(ERROR,
     233                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     234                 :             /* translator: %s represents an SQL statement name */
     235                 :                      errmsg("event triggers are not supported for %s",
     236                 :                             tagstr)));
     237                 :     }
     238               0 : }
     239                 : 
     240                 : /*
     241                 :  * Complain about a duplicate filter variable.
     242                 :  */
     243                 : static void
     244 CBC           3 : error_duplicate_filter_variable(const char *defname)
     245                 : {
     246               3 :     ereport(ERROR,
     247                 :             (errcode(ERRCODE_SYNTAX_ERROR),
     248                 :              errmsg("filter variable \"%s\" specified more than once",
     249                 :                     defname)));
     250                 : }
     251                 : 
     252                 : /*
     253                 :  * Insert the new pg_event_trigger row and record dependencies.
     254                 :  */
     255                 : static Oid
     256              47 : insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtOwner,
     257                 :                            Oid funcoid, List *taglist)
     258                 : {
     259                 :     Relation    tgrel;
     260                 :     Oid         trigoid;
     261                 :     HeapTuple   tuple;
     262                 :     Datum       values[Natts_pg_trigger];
     263                 :     bool        nulls[Natts_pg_trigger];
     264                 :     NameData    evtnamedata,
     265                 :                 evteventdata;
     266                 :     ObjectAddress myself,
     267                 :                 referenced;
     268                 : 
     269                 :     /* Open pg_event_trigger. */
     270              47 :     tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
     271                 : 
     272                 :     /* Build the new pg_trigger tuple. */
     273              47 :     trigoid = GetNewOidWithIndex(tgrel, EventTriggerOidIndexId,
     274                 :                                  Anum_pg_event_trigger_oid);
     275              47 :     values[Anum_pg_event_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
     276              47 :     memset(nulls, false, sizeof(nulls));
     277              47 :     namestrcpy(&evtnamedata, trigname);
     278              47 :     values[Anum_pg_event_trigger_evtname - 1] = NameGetDatum(&evtnamedata);
     279              47 :     namestrcpy(&evteventdata, eventname);
     280              47 :     values[Anum_pg_event_trigger_evtevent - 1] = NameGetDatum(&evteventdata);
     281              47 :     values[Anum_pg_event_trigger_evtowner - 1] = ObjectIdGetDatum(evtOwner);
     282              47 :     values[Anum_pg_event_trigger_evtfoid - 1] = ObjectIdGetDatum(funcoid);
     283              47 :     values[Anum_pg_event_trigger_evtenabled - 1] =
     284              47 :         CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
     285              47 :     if (taglist == NIL)
     286              32 :         nulls[Anum_pg_event_trigger_evttags - 1] = true;
     287                 :     else
     288              15 :         values[Anum_pg_event_trigger_evttags - 1] =
     289              15 :             filter_list_to_array(taglist);
     290                 : 
     291                 :     /* Insert heap tuple. */
     292              47 :     tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
     293              47 :     CatalogTupleInsert(tgrel, tuple);
     294              47 :     heap_freetuple(tuple);
     295                 : 
     296                 :     /* Depend on owner. */
     297              47 :     recordDependencyOnOwner(EventTriggerRelationId, trigoid, evtOwner);
     298                 : 
     299                 :     /* Depend on event trigger function. */
     300              47 :     myself.classId = EventTriggerRelationId;
     301              47 :     myself.objectId = trigoid;
     302              47 :     myself.objectSubId = 0;
     303              47 :     referenced.classId = ProcedureRelationId;
     304              47 :     referenced.objectId = funcoid;
     305              47 :     referenced.objectSubId = 0;
     306              47 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     307                 : 
     308                 :     /* Depend on extension, if any. */
     309              47 :     recordDependencyOnCurrentExtension(&myself, false);
     310                 : 
     311                 :     /* Post creation hook for new event trigger */
     312              47 :     InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
     313                 : 
     314                 :     /* Close pg_event_trigger. */
     315              47 :     table_close(tgrel, RowExclusiveLock);
     316                 : 
     317              47 :     return trigoid;
     318                 : }
     319                 : 
     320                 : /*
     321                 :  * In the parser, a clause like WHEN tag IN ('cmd1', 'cmd2') is represented
     322                 :  * by a DefElem whose value is a List of String nodes; in the catalog, we
     323                 :  * store the list of strings as a text array.  This function transforms the
     324                 :  * former representation into the latter one.
     325                 :  *
     326                 :  * For cleanliness, we store command tags in the catalog as text.  It's
     327                 :  * possible (although not currently anticipated) that we might have
     328                 :  * a case-sensitive filter variable in the future, in which case this would
     329                 :  * need some further adjustment.
     330                 :  */
     331                 : static Datum
     332              15 : filter_list_to_array(List *filterlist)
     333                 : {
     334                 :     ListCell   *lc;
     335                 :     Datum      *data;
     336              15 :     int         i = 0,
     337              15 :                 l = list_length(filterlist);
     338                 : 
     339              15 :     data = (Datum *) palloc(l * sizeof(Datum));
     340                 : 
     341              60 :     foreach(lc, filterlist)
     342                 :     {
     343              45 :         const char *value = strVal(lfirst(lc));
     344                 :         char       *result,
     345                 :                    *p;
     346                 : 
     347              45 :         result = pstrdup(value);
     348             567 :         for (p = result; *p; p++)
     349             522 :             *p = pg_ascii_toupper((unsigned char) *p);
     350              45 :         data[i++] = PointerGetDatum(cstring_to_text(result));
     351              45 :         pfree(result);
     352                 :     }
     353                 : 
     354 GNC          15 :     return PointerGetDatum(construct_array_builtin(data, l, TEXTOID));
     355                 : }
     356                 : 
     357                 : /*
     358                 :  * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
     359                 :  */
     360 ECB             : Oid
     361 GIC          16 : AlterEventTrigger(AlterEventTrigStmt *stmt)
     362                 : {
     363                 :     Relation    tgrel;
     364                 :     HeapTuple   tup;
     365                 :     Oid         trigoid;
     366 ECB             :     Form_pg_event_trigger evtForm;
     367 GIC          16 :     char        tgenabled = stmt->tgenabled;
     368 ECB             : 
     369 GIC          16 :     tgrel = table_open(EventTriggerRelationId, RowExclusiveLock);
     370 ECB             : 
     371 GIC          16 :     tup = SearchSysCacheCopy1(EVENTTRIGGERNAME,
     372 ECB             :                               CStringGetDatum(stmt->trigname));
     373 GBC          16 :     if (!HeapTupleIsValid(tup))
     374 UIC           0 :         ereport(ERROR,
     375                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     376                 :                  errmsg("event trigger \"%s\" does not exist",
     377                 :                         stmt->trigname)));
     378 ECB             : 
     379 CBC          16 :     evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
     380 GIC          16 :     trigoid = evtForm->oid;
     381 ECB             : 
     382 GNC          16 :     if (!object_ownercheck(EventTriggerRelationId, trigoid, GetUserId()))
     383 UBC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EVENT_TRIGGER,
     384 UIC           0 :                        stmt->trigname);
     385                 : 
     386 ECB             :     /* tuple is a copy, so we can modify it below */
     387 GIC          16 :     evtForm->evtenabled = tgenabled;
     388 ECB             : 
     389 GIC          16 :     CatalogTupleUpdate(tgrel, &tup->t_self, tup);
     390 ECB             : 
     391 GIC          16 :     InvokeObjectPostAlterHook(EventTriggerRelationId,
     392                 :                               trigoid, 0);
     393                 : 
     394 ECB             :     /* clean up */
     395 CBC          16 :     heap_freetuple(tup);
     396 GIC          16 :     table_close(tgrel, RowExclusiveLock);
     397 ECB             : 
     398 GIC          16 :     return trigoid;
     399                 : }
     400                 : 
     401                 : /*
     402                 :  * Change event trigger's owner -- by name
     403                 :  */
     404 ECB             : ObjectAddress
     405 GIC           6 : AlterEventTriggerOwner(const char *name, Oid newOwnerId)
     406                 : {
     407                 :     Oid         evtOid;
     408                 :     HeapTuple   tup;
     409                 :     Form_pg_event_trigger evtForm;
     410                 :     Relation    rel;
     411                 :     ObjectAddress address;
     412 ECB             : 
     413 GIC           6 :     rel = table_open(EventTriggerRelationId, RowExclusiveLock);
     414 ECB             : 
     415 GIC           6 :     tup = SearchSysCacheCopy1(EVENTTRIGGERNAME, CStringGetDatum(name));
     416 ECB             : 
     417 GBC           6 :     if (!HeapTupleIsValid(tup))
     418 UIC           0 :         ereport(ERROR,
     419                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     420                 :                  errmsg("event trigger \"%s\" does not exist", name)));
     421 ECB             : 
     422 CBC           6 :     evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
     423 GIC           6 :     evtOid = evtForm->oid;
     424 ECB             : 
     425 GIC           6 :     AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
     426 ECB             : 
     427 GIC           3 :     ObjectAddressSet(address, EventTriggerRelationId, evtOid);
     428 ECB             : 
     429 GIC           3 :     heap_freetuple(tup);
     430 ECB             : 
     431 GIC           3 :     table_close(rel, RowExclusiveLock);
     432 ECB             : 
     433 GIC           3 :     return address;
     434                 : }
     435                 : 
     436                 : /*
     437                 :  * Change event trigger owner, by OID
     438                 :  */
     439 EUB             : void
     440 UIC           0 : AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
     441                 : {
     442                 :     HeapTuple   tup;
     443                 :     Relation    rel;
     444 EUB             : 
     445 UIC           0 :     rel = table_open(EventTriggerRelationId, RowExclusiveLock);
     446 EUB             : 
     447 UIC           0 :     tup = SearchSysCacheCopy1(EVENTTRIGGEROID, ObjectIdGetDatum(trigOid));
     448 EUB             : 
     449 UBC           0 :     if (!HeapTupleIsValid(tup))
     450 UIC           0 :         ereport(ERROR,
     451                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     452                 :                  errmsg("event trigger with OID %u does not exist", trigOid)));
     453 EUB             : 
     454 UIC           0 :     AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
     455 EUB             : 
     456 UIC           0 :     heap_freetuple(tup);
     457 EUB             : 
     458 UBC           0 :     table_close(rel, RowExclusiveLock);
     459 UIC           0 : }
     460                 : 
     461                 : /*
     462                 :  * Internal workhorse for changing an event trigger's owner
     463                 :  */
     464 ECB             : static void
     465 GIC           6 : AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
     466                 : {
     467                 :     Form_pg_event_trigger form;
     468 ECB             : 
     469 GIC           6 :     form = (Form_pg_event_trigger) GETSTRUCT(tup);
     470 ECB             : 
     471 GBC           6 :     if (form->evtowner == newOwnerId)
     472 UIC           0 :         return;
     473 ECB             : 
     474 GNC           6 :     if (!object_ownercheck(EventTriggerRelationId, form->oid, GetUserId()))
     475 UBC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EVENT_TRIGGER,
     476 UIC           0 :                        NameStr(form->evtname));
     477                 : 
     478 ECB             :     /* New owner must be a superuser */
     479 CBC           6 :     if (!superuser_arg(newOwnerId))
     480 GIC           3 :         ereport(ERROR,
     481                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     482                 :                  errmsg("permission denied to change owner of event trigger \"%s\"",
     483                 :                         NameStr(form->evtname)),
     484                 :                  errhint("The owner of an event trigger must be a superuser.")));
     485 ECB             : 
     486 CBC           3 :     form->evtowner = newOwnerId;
     487 GIC           3 :     CatalogTupleUpdate(rel, &tup->t_self, tup);
     488                 : 
     489 ECB             :     /* Update owner dependency reference */
     490 GIC           3 :     changeDependencyOnOwner(EventTriggerRelationId,
     491                 :                             form->oid,
     492                 :                             newOwnerId);
     493 ECB             : 
     494 GIC           3 :     InvokeObjectPostAlterHook(EventTriggerRelationId,
     495                 :                               form->oid, 0);
     496                 : }
     497                 : 
     498                 : /*
     499                 :  * get_event_trigger_oid - Look up an event trigger by name to find its OID.
     500                 :  *
     501                 :  * If missing_ok is false, throw an error if trigger not found.  If
     502                 :  * true, just return InvalidOid.
     503                 :  */
     504 ECB             : Oid
     505 GIC          71 : get_event_trigger_oid(const char *trigname, bool missing_ok)
     506                 : {
     507                 :     Oid         oid;
     508 ECB             : 
     509 GIC          71 :     oid = GetSysCacheOid1(EVENTTRIGGERNAME, Anum_pg_event_trigger_oid,
     510 ECB             :                           CStringGetDatum(trigname));
     511 CBC          71 :     if (!OidIsValid(oid) && !missing_ok)
     512 GIC           6 :         ereport(ERROR,
     513                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     514 ECB             :                  errmsg("event trigger \"%s\" does not exist", trigname)));
     515 GIC          65 :     return oid;
     516                 : }
     517                 : 
     518                 : /*
     519                 :  * Return true when we want to fire given Event Trigger and false otherwise,
     520                 :  * filtering on the session replication role and the event trigger registered
     521                 :  * tags matching.
     522                 :  */
     523 ECB             : static bool
     524 GIC         600 : filter_event_trigger(CommandTag tag, EventTriggerCacheItem *item)
     525                 : {
     526                 :     /*
     527                 :      * Filter by session replication role, knowing that we never see disabled
     528                 :      * items down here.
     529 ECB             :      */
     530 GIC         600 :     if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
     531 ECB             :     {
     532 CBC          27 :         if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
     533 GIC          21 :             return false;
     534                 :     }
     535                 :     else
     536 ECB             :     {
     537 GBC         573 :         if (item->enabled == TRIGGER_FIRES_ON_REPLICA)
     538 UIC           0 :             return false;
     539                 :     }
     540                 : 
     541 ECB             :     /* Filter by tags, if any were specified. */
     542 CBC         579 :     if (!bms_is_empty(item->tagset) && !bms_is_member(tag, item->tagset))
     543 GIC          33 :         return false;
     544                 : 
     545 ECB             :     /* if we reach that point, we're not filtering out this item */
     546 GIC         546 :     return true;
     547                 : }
     548                 : 
     549                 : /*
     550                 :  * Setup for running triggers for the given event.  Return value is an OID list
     551                 :  * of functions to run; if there are any, trigdata is filled with an
     552                 :  * appropriate EventTriggerData for them to receive.
     553                 :  */
     554 ECB             : static List *
     555 GIC       61251 : EventTriggerCommonSetup(Node *parsetree,
     556                 :                         EventTriggerEvent event, const char *eventstr,
     557                 :                         EventTriggerData *trigdata)
     558                 : {
     559                 :     CommandTag  tag;
     560                 :     List       *cachelist;
     561 ECB             :     ListCell   *lc;
     562 GIC       61251 :     List       *runlist = NIL;
     563                 : 
     564                 :     /*
     565                 :      * We want the list of command tags for which this procedure is actually
     566                 :      * invoked to match up exactly with the list that CREATE EVENT TRIGGER
     567                 :      * accepts.  This debugging cross-check will throw an error if this
     568                 :      * function is invoked for a command tag that CREATE EVENT TRIGGER won't
     569                 :      * accept.  (Unfortunately, there doesn't seem to be any simple, automated
     570                 :      * way to verify that CREATE EVENT TRIGGER doesn't accept extra stuff that
     571                 :      * never reaches this control point.)
     572                 :      *
     573                 :      * If this cross-check fails for you, you probably need to either adjust
     574                 :      * standard_ProcessUtility() not to invoke event triggers for the command
     575                 :      * type in question, or you need to adjust event_trigger_ok to accept the
     576                 :      * relevant command tag.
     577                 :      */
     578                 : #ifdef USE_ASSERT_CHECKING
     579                 :     {
     580                 :         CommandTag  dbgtag;
     581 ECB             : 
     582 CBC       61251 :         dbgtag = CreateCommandTag(parsetree);
     583           61251 :         if (event == EVT_DDLCommandStart ||
     584 GIC         216 :             event == EVT_DDLCommandEnd ||
     585                 :             event == EVT_SQLDrop)
     586 ECB             :         {
     587 GBC       61210 :             if (!command_tag_event_trigger_ok(dbgtag))
     588 UIC           0 :                 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
     589 ECB             :         }
     590 GIC          41 :         else if (event == EVT_TableRewrite)
     591 ECB             :         {
     592 GBC          41 :             if (!command_tag_table_rewrite_ok(dbgtag))
     593 UIC           0 :                 elog(ERROR, "unexpected command tag \"%s\"", GetCommandTagName(dbgtag));
     594                 :         }
     595                 :     }
     596                 : #endif
     597                 : 
     598 ECB             :     /* Use cache to find triggers for this event; fast exit if none. */
     599 CBC       61251 :     cachelist = EventCacheLookup(event);
     600           61251 :     if (cachelist == NIL)
     601 GIC       60699 :         return NIL;
     602                 : 
     603 ECB             :     /* Get the command tag. */
     604 GIC         552 :     tag = CreateCommandTag(parsetree);
     605                 : 
     606                 :     /*
     607                 :      * Filter list of event triggers by command tag, and copy them into our
     608                 :      * memory context.  Once we start running the command triggers, or indeed
     609                 :      * once we do anything at all that touches the catalogs, an invalidation
     610                 :      * might leave cachelist pointing at garbage, so we must do this before we
     611                 :      * can do much else.
     612 ECB             :      */
     613 GIC        1152 :     foreach(lc, cachelist)
     614 ECB             :     {
     615 GIC         600 :         EventTriggerCacheItem *item = lfirst(lc);
     616 ECB             : 
     617 GIC         600 :         if (filter_event_trigger(tag, item))
     618                 :         {
     619 ECB             :             /* We must plan to fire this trigger. */
     620 GIC         546 :             runlist = lappend_oid(runlist, item->fnoid);
     621                 :         }
     622                 :     }
     623                 : 
     624 ECB             :     /* don't spend any more time on this if no functions to run */
     625 CBC         552 :     if (runlist == NIL)
     626 GIC          42 :         return NIL;
     627 ECB             : 
     628 CBC         510 :     trigdata->type = T_EventTriggerData;
     629             510 :     trigdata->event = eventstr;
     630             510 :     trigdata->parsetree = parsetree;
     631 GIC         510 :     trigdata->tag = tag;
     632 ECB             : 
     633 GIC         510 :     return runlist;
     634                 : }
     635                 : 
     636                 : /*
     637                 :  * Fire ddl_command_start triggers.
     638                 :  */
     639 ECB             : void
     640 GIC      276916 : EventTriggerDDLCommandStart(Node *parsetree)
     641                 : {
     642                 :     List       *runlist;
     643                 :     EventTriggerData trigdata;
     644                 : 
     645                 :     /*
     646                 :      * Event Triggers are completely disabled in standalone mode.  There are
     647                 :      * (at least) two reasons for this:
     648                 :      *
     649                 :      * 1. A sufficiently broken event trigger might not only render the
     650                 :      * database unusable, but prevent disabling itself to fix the situation.
     651                 :      * In this scenario, restarting in standalone mode provides an escape
     652                 :      * hatch.
     653                 :      *
     654                 :      * 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
     655                 :      * therefore will malfunction if pg_event_trigger's indexes are damaged.
     656                 :      * To allow recovery from a damaged index, we need some operating mode
     657                 :      * wherein event triggers are disabled.  (Or we could implement
     658                 :      * heapscan-and-sort logic for that case, but having disaster recovery
     659                 :      * scenarios depend on code that's otherwise untested isn't appetizing.)
     660 ECB             :      */
     661 CBC      276916 :     if (!IsUnderPostmaster)
     662 GIC      276760 :         return;
     663 ECB             : 
     664 GIC       60271 :     runlist = EventTriggerCommonSetup(parsetree,
     665                 :                                       EVT_DDLCommandStart,
     666                 :                                       "ddl_command_start",
     667 ECB             :                                       &trigdata);
     668 CBC       60271 :     if (runlist == NIL)
     669 GIC       60115 :         return;
     670                 : 
     671 ECB             :     /* Run the triggers. */
     672 GIC         156 :     EventTriggerInvoke(runlist, &trigdata);
     673                 : 
     674 ECB             :     /* Cleanup. */
     675 GIC         156 :     list_free(runlist);
     676                 : 
     677                 :     /*
     678                 :      * Make sure anything the event triggers did will be visible to the main
     679                 :      * command.
     680 ECB             :      */
     681 GIC         156 :     CommandCounterIncrement();
     682                 : }
     683                 : 
     684                 : /*
     685                 :  * Fire ddl_command_end triggers.
     686                 :  */
     687 ECB             : void
     688 GIC      271942 : EventTriggerDDLCommandEnd(Node *parsetree)
     689                 : {
     690                 :     List       *runlist;
     691                 :     EventTriggerData trigdata;
     692                 : 
     693                 :     /*
     694                 :      * See EventTriggerDDLCommandStart for a discussion about why event
     695                 :      * triggers are disabled in single user mode.
     696 ECB             :      */
     697 CBC      271942 :     if (!IsUnderPostmaster)
     698 GIC      271663 :         return;
     699                 : 
     700                 :     /*
     701                 :      * Also do nothing if our state isn't set up, which it won't be if there
     702                 :      * weren't any relevant event triggers at the start of the current DDL
     703                 :      * command.  This test might therefore seem optional, but it's important
     704                 :      * because EventTriggerCommonSetup might find triggers that didn't exist
     705                 :      * at the time the command started.  Although this function itself
     706                 :      * wouldn't crash, the event trigger functions would presumably call
     707                 :      * pg_event_trigger_ddl_commands which would fail.  Better to do nothing
     708                 :      * until the next command.
     709 ECB             :      */
     710 CBC       55297 :     if (!currentEventTriggerState)
     711 GIC       54533 :         return;
     712 ECB             : 
     713 GIC         764 :     runlist = EventTriggerCommonSetup(parsetree,
     714                 :                                       EVT_DDLCommandEnd, "ddl_command_end",
     715 ECB             :                                       &trigdata);
     716 CBC         764 :     if (runlist == NIL)
     717 GIC         485 :         return;
     718                 : 
     719                 :     /*
     720                 :      * Make sure anything the main command did will be visible to the event
     721                 :      * triggers.
     722 ECB             :      */
     723 GIC         279 :     CommandCounterIncrement();
     724                 : 
     725 ECB             :     /* Run the triggers. */
     726 GIC         279 :     EventTriggerInvoke(runlist, &trigdata);
     727                 : 
     728 ECB             :     /* Cleanup. */
     729 GIC         279 :     list_free(runlist);
     730                 : }
     731                 : 
     732                 : /*
     733                 :  * Fire sql_drop triggers.
     734                 :  */
     735 ECB             : void
     736 GIC      271951 : EventTriggerSQLDrop(Node *parsetree)
     737                 : {
     738                 :     List       *runlist;
     739                 :     EventTriggerData trigdata;
     740                 : 
     741                 :     /*
     742                 :      * See EventTriggerDDLCommandStart for a discussion about why event
     743                 :      * triggers are disabled in single user mode.
     744 ECB             :      */
     745 CBC      271951 :     if (!IsUnderPostmaster)
     746 GIC      271903 :         return;
     747                 : 
     748                 :     /*
     749                 :      * Use current state to determine whether this event fires at all.  If
     750                 :      * there are no triggers for the sql_drop event, then we don't have
     751                 :      * anything to do here.  Note that dropped object collection is disabled
     752                 :      * if this is the case, so even if we were to try to run, the list would
     753                 :      * be empty.
     754 ECB             :      */
     755 CBC       55306 :     if (!currentEventTriggerState ||
     756             773 :         slist_is_empty(&currentEventTriggerState->SQLDropList))
     757 GIC       55131 :         return;
     758 ECB             : 
     759 GIC         175 :     runlist = EventTriggerCommonSetup(parsetree,
     760                 :                                       EVT_SQLDrop, "sql_drop",
     761                 :                                       &trigdata);
     762                 : 
     763                 :     /*
     764                 :      * Nothing to do if run list is empty.  Note this typically can't happen,
     765                 :      * because if there are no sql_drop events, then objects-to-drop wouldn't
     766                 :      * have been collected in the first place and we would have quit above.
     767                 :      * But it could occur if event triggers were dropped partway through.
     768 ECB             :      */
     769 CBC         175 :     if (runlist == NIL)
     770 GIC         127 :         return;
     771                 : 
     772                 :     /*
     773                 :      * Make sure anything the main command did will be visible to the event
     774                 :      * triggers.
     775 ECB             :      */
     776 GIC          48 :     CommandCounterIncrement();
     777                 : 
     778                 :     /*
     779                 :      * Make sure pg_event_trigger_dropped_objects only works when running
     780                 :      * these triggers.  Use PG_TRY to ensure in_sql_drop is reset even when
     781                 :      * one trigger fails.  (This is perhaps not necessary, as the currentState
     782                 :      * variable will be removed shortly by our caller, but it seems better to
     783                 :      * play safe.)
     784 ECB             :      */
     785 GIC          48 :     currentEventTriggerState->in_sql_drop = true;
     786                 : 
     787 ECB             :     /* Run the triggers. */
     788 GIC          48 :     PG_TRY();
     789 ECB             :     {
     790 GIC          48 :         EventTriggerInvoke(runlist, &trigdata);
     791 ECB             :     }
     792 GIC           9 :     PG_FINALLY();
     793 ECB             :     {
     794 GIC          48 :         currentEventTriggerState->in_sql_drop = false;
     795 ECB             :     }
     796 GIC          48 :     PG_END_TRY();
     797                 : 
     798 ECB             :     /* Cleanup. */
     799 GIC          39 :     list_free(runlist);
     800                 : }
     801                 : 
     802                 : 
     803                 : /*
     804                 :  * Fire table_rewrite triggers.
     805                 :  */
     806 ECB             : void
     807 GIC         371 : EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
     808                 : {
     809                 :     List       *runlist;
     810                 :     EventTriggerData trigdata;
     811                 : 
     812                 :     /*
     813                 :      * See EventTriggerDDLCommandStart for a discussion about why event
     814                 :      * triggers are disabled in single user mode.
     815 ECB             :      */
     816 CBC         371 :     if (!IsUnderPostmaster)
     817 GIC         344 :         return;
     818                 : 
     819                 :     /*
     820                 :      * Also do nothing if our state isn't set up, which it won't be if there
     821                 :      * weren't any relevant event triggers at the start of the current DDL
     822                 :      * command.  This test might therefore seem optional, but it's
     823                 :      * *necessary*, because EventTriggerCommonSetup might find triggers that
     824                 :      * didn't exist at the time the command started.
     825 ECB             :      */
     826 CBC         371 :     if (!currentEventTriggerState)
     827 GIC         330 :         return;
     828 ECB             : 
     829 GIC          41 :     runlist = EventTriggerCommonSetup(parsetree,
     830                 :                                       EVT_TableRewrite,
     831                 :                                       "table_rewrite",
     832 ECB             :                                       &trigdata);
     833 CBC          41 :     if (runlist == NIL)
     834 GIC          14 :         return;
     835                 : 
     836                 :     /*
     837                 :      * Make sure pg_event_trigger_table_rewrite_oid only works when running
     838                 :      * these triggers. Use PG_TRY to ensure table_rewrite_oid is reset even
     839                 :      * when one trigger fails. (This is perhaps not necessary, as the
     840                 :      * currentState variable will be removed shortly by our caller, but it
     841                 :      * seems better to play safe.)
     842 ECB             :      */
     843 CBC          27 :     currentEventTriggerState->table_rewrite_oid = tableOid;
     844 GIC          27 :     currentEventTriggerState->table_rewrite_reason = reason;
     845                 : 
     846 ECB             :     /* Run the triggers. */
     847 GIC          27 :     PG_TRY();
     848 ECB             :     {
     849 GIC          27 :         EventTriggerInvoke(runlist, &trigdata);
     850 ECB             :     }
     851 GIC           3 :     PG_FINALLY();
     852 ECB             :     {
     853 CBC          27 :         currentEventTriggerState->table_rewrite_oid = InvalidOid;
     854 GIC          27 :         currentEventTriggerState->table_rewrite_reason = 0;
     855 ECB             :     }
     856 GIC          27 :     PG_END_TRY();
     857                 : 
     858 ECB             :     /* Cleanup. */
     859 GIC          24 :     list_free(runlist);
     860                 : 
     861                 :     /*
     862                 :      * Make sure anything the event triggers did will be visible to the main
     863                 :      * command.
     864 ECB             :      */
     865 GIC          24 :     CommandCounterIncrement();
     866                 : }
     867                 : 
     868                 : /*
     869                 :  * Invoke each event trigger in a list of event triggers.
     870                 :  */
     871 ECB             : static void
     872 GIC         510 : EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
     873                 : {
     874                 :     MemoryContext context;
     875                 :     MemoryContext oldcontext;
     876 ECB             :     ListCell   *lc;
     877 GIC         510 :     bool        first = true;
     878                 : 
     879 ECB             :     /* Guard against stack overflow due to recursive event trigger */
     880 GIC         510 :     check_stack_depth();
     881                 : 
     882                 :     /*
     883                 :      * Let's evaluate event triggers in their own memory context, so that any
     884                 :      * leaks get cleaned up promptly.
     885 ECB             :      */
     886 GIC         510 :     context = AllocSetContextCreate(CurrentMemoryContext,
     887                 :                                     "event trigger context",
     888 ECB             :                                     ALLOCSET_DEFAULT_SIZES);
     889 GIC         510 :     oldcontext = MemoryContextSwitchTo(context);
     890                 : 
     891 ECB             :     /* Call each event trigger. */
     892 GIC        1041 :     foreach(lc, fn_oid_list)
     893 ECB             :     {
     894 CBC         543 :         LOCAL_FCINFO(fcinfo, 0);
     895 GIC         543 :         Oid         fnoid = lfirst_oid(lc);
     896                 :         FmgrInfo    flinfo;
     897                 :         PgStat_FunctionCallUsage fcusage;
     898 ECB             : 
     899 GIC         543 :         elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
     900                 : 
     901                 :         /*
     902                 :          * We want each event trigger to be able to see the results of the
     903                 :          * previous event trigger's action.  Caller is responsible for any
     904                 :          * command-counter increment that is needed between the event trigger
     905                 :          * and anything else in the transaction.
     906 ECB             :          */
     907 CBC         543 :         if (first)
     908 GIC         510 :             first = false;
     909 ECB             :         else
     910 GIC          33 :             CommandCounterIncrement();
     911                 : 
     912 ECB             :         /* Look up the function */
     913 GIC         543 :         fmgr_info(fnoid, &flinfo);
     914                 : 
     915 ECB             :         /* Call the function, passing no arguments but setting a context. */
     916 GIC         543 :         InitFunctionCallInfoData(*fcinfo, &flinfo, 0,
     917 ECB             :                                  InvalidOid, (Node *) trigdata, NULL);
     918 CBC         543 :         pgstat_init_function_usage(fcinfo, &fcusage);
     919             543 :         FunctionCallInvoke(fcinfo);
     920 GIC         531 :         pgstat_end_function_usage(&fcusage, true);
     921                 : 
     922 ECB             :         /* Reclaim memory. */
     923 GIC         531 :         MemoryContextReset(context);
     924                 :     }
     925                 : 
     926 ECB             :     /* Restore old memory context and delete the temporary one. */
     927 CBC         498 :     MemoryContextSwitchTo(oldcontext);
     928             498 :     MemoryContextDelete(context);
     929 GIC         498 : }
     930                 : 
     931                 : /*
     932                 :  * Do event triggers support this object type?
     933                 :  */
     934 ECB             : bool
     935 GIC      129757 : EventTriggerSupportsObjectType(ObjectType obtype)
     936 ECB             : {
     937 GIC      129757 :     switch (obtype)
     938 ECB             :     {
     939 GIC        2074 :         case OBJECT_DATABASE:
     940                 :         case OBJECT_TABLESPACE:
     941                 :         case OBJECT_ROLE:
     942                 :         case OBJECT_PARAMETER_ACL:
     943 ECB             :             /* no support for global objects */
     944 CBC        2074 :             return false;
     945 GIC          62 :         case OBJECT_EVENT_TRIGGER:
     946 ECB             :             /* no support for event triggers on event triggers */
     947 CBC          62 :             return false;
     948 GIC      127621 :         case OBJECT_ACCESS_METHOD:
     949                 :         case OBJECT_AGGREGATE:
     950                 :         case OBJECT_AMOP:
     951                 :         case OBJECT_AMPROC:
     952                 :         case OBJECT_ATTRIBUTE:
     953                 :         case OBJECT_CAST:
     954                 :         case OBJECT_COLUMN:
     955                 :         case OBJECT_COLLATION:
     956                 :         case OBJECT_CONVERSION:
     957                 :         case OBJECT_DEFACL:
     958                 :         case OBJECT_DEFAULT:
     959                 :         case OBJECT_DOMAIN:
     960                 :         case OBJECT_DOMCONSTRAINT:
     961                 :         case OBJECT_EXTENSION:
     962                 :         case OBJECT_FDW:
     963                 :         case OBJECT_FOREIGN_SERVER:
     964                 :         case OBJECT_FOREIGN_TABLE:
     965                 :         case OBJECT_FUNCTION:
     966                 :         case OBJECT_INDEX:
     967                 :         case OBJECT_LANGUAGE:
     968                 :         case OBJECT_LARGEOBJECT:
     969                 :         case OBJECT_MATVIEW:
     970                 :         case OBJECT_OPCLASS:
     971                 :         case OBJECT_OPERATOR:
     972                 :         case OBJECT_OPFAMILY:
     973                 :         case OBJECT_POLICY:
     974                 :         case OBJECT_PROCEDURE:
     975                 :         case OBJECT_PUBLICATION:
     976                 :         case OBJECT_PUBLICATION_NAMESPACE:
     977                 :         case OBJECT_PUBLICATION_REL:
     978                 :         case OBJECT_ROUTINE:
     979                 :         case OBJECT_RULE:
     980                 :         case OBJECT_SCHEMA:
     981                 :         case OBJECT_SEQUENCE:
     982                 :         case OBJECT_SUBSCRIPTION:
     983                 :         case OBJECT_STATISTIC_EXT:
     984                 :         case OBJECT_TABCONSTRAINT:
     985                 :         case OBJECT_TABLE:
     986                 :         case OBJECT_TRANSFORM:
     987                 :         case OBJECT_TRIGGER:
     988                 :         case OBJECT_TSCONFIGURATION:
     989                 :         case OBJECT_TSDICTIONARY:
     990                 :         case OBJECT_TSPARSER:
     991                 :         case OBJECT_TSTEMPLATE:
     992                 :         case OBJECT_TYPE:
     993                 :         case OBJECT_USER_MAPPING:
     994 ECB             :         case OBJECT_VIEW:
     995 GIC      127621 :             return true;
     996                 : 
     997                 :             /*
     998                 :              * There's intentionally no default: case here; we want the
     999                 :              * compiler to warn if a new ObjectType hasn't been handled above.
    1000                 :              */
    1001                 :     }
    1002                 : 
    1003 EUB             :     /* Shouldn't get here, but if we do, say "no support" */
    1004 UIC           0 :     return false;
    1005                 : }
    1006                 : 
    1007                 : /*
    1008                 :  * Do event triggers support this object class?
    1009                 :  */
    1010 ECB             : bool
    1011 GIC        2456 : EventTriggerSupportsObjectClass(ObjectClass objclass)
    1012 ECB             : {
    1013 GIC        2456 :     switch (objclass)
    1014 EUB             :     {
    1015 UIC           0 :         case OCLASS_DATABASE:
    1016                 :         case OCLASS_TBLSPACE:
    1017                 :         case OCLASS_ROLE:
    1018                 :         case OCLASS_ROLE_MEMBERSHIP:
    1019                 :         case OCLASS_PARAMETER_ACL:
    1020                 :             /* no support for global objects */
    1021 UBC           0 :             return false;
    1022 CBC          44 :         case OCLASS_EVENT_TRIGGER:
    1023                 :             /* no support for event triggers on event triggers */
    1024              44 :             return false;
    1025            2412 :         case OCLASS_CLASS:
    1026                 :         case OCLASS_PROC:
    1027                 :         case OCLASS_TYPE:
    1028                 :         case OCLASS_CAST:
    1029                 :         case OCLASS_COLLATION:
    1030                 :         case OCLASS_CONSTRAINT:
    1031                 :         case OCLASS_CONVERSION:
    1032                 :         case OCLASS_DEFAULT:
    1033                 :         case OCLASS_LANGUAGE:
    1034                 :         case OCLASS_LARGEOBJECT:
    1035                 :         case OCLASS_OPERATOR:
    1036                 :         case OCLASS_OPCLASS:
    1037                 :         case OCLASS_OPFAMILY:
    1038                 :         case OCLASS_AM:
    1039                 :         case OCLASS_AMOP:
    1040                 :         case OCLASS_AMPROC:
    1041                 :         case OCLASS_REWRITE:
    1042                 :         case OCLASS_TRIGGER:
    1043                 :         case OCLASS_SCHEMA:
    1044                 :         case OCLASS_STATISTIC_EXT:
    1045                 :         case OCLASS_TSPARSER:
    1046                 :         case OCLASS_TSDICT:
    1047                 :         case OCLASS_TSTEMPLATE:
    1048                 :         case OCLASS_TSCONFIG:
    1049                 :         case OCLASS_FDW:
    1050                 :         case OCLASS_FOREIGN_SERVER:
    1051                 :         case OCLASS_USER_MAPPING:
    1052                 :         case OCLASS_DEFACL:
    1053                 :         case OCLASS_EXTENSION:
    1054                 :         case OCLASS_POLICY:
    1055                 :         case OCLASS_PUBLICATION:
    1056                 :         case OCLASS_PUBLICATION_NAMESPACE:
    1057                 :         case OCLASS_PUBLICATION_REL:
    1058                 :         case OCLASS_SUBSCRIPTION:
    1059                 :         case OCLASS_TRANSFORM:
    1060            2412 :             return true;
    1061                 : 
    1062                 :             /*
    1063                 :              * There's intentionally no default: case here; we want the
    1064                 :              * compiler to warn if a new OCLASS hasn't been handled above.
    1065                 :              */
    1066                 :     }
    1067                 : 
    1068                 :     /* Shouldn't get here, but if we do, say "no support" */
    1069 UBC           0 :     return false;
    1070                 : }
    1071                 : 
    1072                 : /*
    1073                 :  * Prepare event trigger state for a new complete query to run, if necessary;
    1074                 :  * returns whether this was done.  If it was, EventTriggerEndCompleteQuery must
    1075                 :  * be called when the query is done, regardless of whether it succeeds or fails
    1076                 :  * -- so use of a PG_TRY block is mandatory.
    1077                 :  */
    1078                 : bool
    1079 CBC      276916 : EventTriggerBeginCompleteQuery(void)
    1080                 : {
    1081                 :     EventTriggerQueryState *state;
    1082                 :     MemoryContext cxt;
    1083                 : 
    1084                 :     /*
    1085                 :      * Currently, sql_drop, table_rewrite, ddl_command_end events are the only
    1086                 :      * reason to have event trigger state at all; so if there are none, don't
    1087                 :      * install one.
    1088                 :      */
    1089          276916 :     if (!trackDroppedObjectsNeeded())
    1090          276136 :         return false;
    1091                 : 
    1092             780 :     cxt = AllocSetContextCreate(TopMemoryContext,
    1093                 :                                 "event trigger state",
    1094                 :                                 ALLOCSET_DEFAULT_SIZES);
    1095             780 :     state = MemoryContextAlloc(cxt, sizeof(EventTriggerQueryState));
    1096             780 :     state->cxt = cxt;
    1097             780 :     slist_init(&(state->SQLDropList));
    1098             780 :     state->in_sql_drop = false;
    1099             780 :     state->table_rewrite_oid = InvalidOid;
    1100                 : 
    1101             780 :     state->commandCollectionInhibited = currentEventTriggerState ?
    1102             780 :         currentEventTriggerState->commandCollectionInhibited : false;
    1103             780 :     state->currentCommand = NULL;
    1104             780 :     state->commandList = NIL;
    1105             780 :     state->previous = currentEventTriggerState;
    1106             780 :     currentEventTriggerState = state;
    1107                 : 
    1108             780 :     return true;
    1109                 : }
    1110                 : 
    1111                 : /*
    1112                 :  * Query completed (or errored out) -- clean up local state, return to previous
    1113                 :  * one.
    1114                 :  *
    1115                 :  * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
    1116                 :  * returned false previously.
    1117                 :  *
    1118                 :  * Note: this might be called in the PG_CATCH block of a failing transaction,
    1119                 :  * so be wary of running anything unnecessary.  (In particular, it's probably
    1120                 :  * unwise to try to allocate memory.)
    1121                 :  */
    1122                 : void
    1123             780 : EventTriggerEndCompleteQuery(void)
    1124                 : {
    1125                 :     EventTriggerQueryState *prevstate;
    1126                 : 
    1127             780 :     prevstate = currentEventTriggerState->previous;
    1128                 : 
    1129                 :     /* this avoids the need for retail pfree of SQLDropList items: */
    1130             780 :     MemoryContextDelete(currentEventTriggerState->cxt);
    1131                 : 
    1132             780 :     currentEventTriggerState = prevstate;
    1133             780 : }
    1134                 : 
    1135                 : /*
    1136                 :  * Do we need to keep close track of objects being dropped?
    1137                 :  *
    1138                 :  * This is useful because there is a cost to running with them enabled.
    1139                 :  */
    1140                 : bool
    1141          290528 : trackDroppedObjectsNeeded(void)
    1142                 : {
    1143                 :     /*
    1144                 :      * true if any sql_drop, table_rewrite, ddl_command_end event trigger
    1145                 :      * exists
    1146                 :      */
    1147 GNC      580844 :     return (EventCacheLookup(EVT_SQLDrop) != NIL) ||
    1148          580844 :         (EventCacheLookup(EVT_TableRewrite) != NIL) ||
    1149          289649 :         (EventCacheLookup(EVT_DDLCommandEnd) != NIL);
    1150                 : }
    1151                 : 
    1152                 : /*
    1153                 :  * Support for dropped objects information on event trigger functions.
    1154                 :  *
    1155                 :  * We keep the list of objects dropped by the current command in current
    1156                 :  * state's SQLDropList (comprising SQLDropObject items).  Each time a new
    1157                 :  * command is to start, a clean EventTriggerQueryState is created; commands
    1158                 :  * that drop objects do the dependency.c dance to drop objects, which
    1159                 :  * populates the current state's SQLDropList; when the event triggers are
    1160                 :  * invoked they can consume the list via pg_event_trigger_dropped_objects().
    1161                 :  * When the command finishes, the EventTriggerQueryState is cleared, and
    1162                 :  * the one from the previous command is restored (when no command is in
    1163                 :  * execution, the current state is NULL).
    1164                 :  *
    1165                 :  * All this lets us support the case that an event trigger function drops
    1166                 :  * objects "reentrantly".
    1167                 :  */
    1168                 : 
    1169                 : /*
    1170                 :  * Register one object as being dropped by the current command.
    1171                 :  */
    1172                 : void
    1173 CBC        1275 : EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
    1174                 : {
    1175                 :     SQLDropObject *obj;
    1176                 :     MemoryContext oldcxt;
    1177                 : 
    1178            1275 :     if (!currentEventTriggerState)
    1179              69 :         return;
    1180                 : 
    1181            1206 :     Assert(EventTriggerSupportsObjectClass(getObjectClass(object)));
    1182                 : 
    1183                 :     /* don't report temp schemas except my own */
    1184            1230 :     if (object->classId == NamespaceRelationId &&
    1185              24 :         (isAnyTempNamespace(object->objectId) &&
    1186 UBC           0 :          !isTempNamespace(object->objectId)))
    1187               0 :         return;
    1188                 : 
    1189 CBC        1206 :     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1190                 : 
    1191            1206 :     obj = palloc0(sizeof(SQLDropObject));
    1192            1206 :     obj->address = *object;
    1193            1206 :     obj->original = original;
    1194            1206 :     obj->normal = normal;
    1195                 : 
    1196                 :     /*
    1197                 :      * Obtain schema names from the object's catalog tuple, if one exists;
    1198                 :      * this lets us skip objects in temp schemas.  We trust that
    1199                 :      * ObjectProperty contains all object classes that can be
    1200                 :      * schema-qualified.
    1201                 :      */
    1202            1206 :     if (is_objectclass_supported(object->classId))
    1203                 :     {
    1204                 :         Relation    catalog;
    1205                 :         HeapTuple   tuple;
    1206                 : 
    1207            1034 :         catalog = table_open(obj->address.classId, AccessShareLock);
    1208            1034 :         tuple = get_catalog_object_by_oid(catalog,
    1209            1034 :                                           get_object_attnum_oid(object->classId),
    1210                 :                                           obj->address.objectId);
    1211                 : 
    1212            1034 :         if (tuple)
    1213                 :         {
    1214                 :             AttrNumber  attnum;
    1215                 :             Datum       datum;
    1216                 :             bool        isnull;
    1217                 : 
    1218            1034 :             attnum = get_object_attnum_namespace(obj->address.classId);
    1219            1034 :             if (attnum != InvalidAttrNumber)
    1220                 :             {
    1221             940 :                 datum = heap_getattr(tuple, attnum,
    1222                 :                                      RelationGetDescr(catalog), &isnull);
    1223             940 :                 if (!isnull)
    1224                 :                 {
    1225                 :                     Oid         namespaceId;
    1226                 : 
    1227             940 :                     namespaceId = DatumGetObjectId(datum);
    1228                 :                     /* temp objects are only reported if they are my own */
    1229             940 :                     if (isTempNamespace(namespaceId))
    1230                 :                     {
    1231               9 :                         obj->schemaname = "pg_temp";
    1232               9 :                         obj->istemp = true;
    1233                 :                     }
    1234             931 :                     else if (isAnyTempNamespace(namespaceId))
    1235                 :                     {
    1236 UBC           0 :                         pfree(obj);
    1237               0 :                         table_close(catalog, AccessShareLock);
    1238               0 :                         MemoryContextSwitchTo(oldcxt);
    1239               0 :                         return;
    1240                 :                     }
    1241                 :                     else
    1242                 :                     {
    1243 CBC         931 :                         obj->schemaname = get_namespace_name(namespaceId);
    1244             931 :                         obj->istemp = false;
    1245                 :                     }
    1246                 :                 }
    1247                 :             }
    1248                 : 
    1249            1034 :             if (get_object_namensp_unique(obj->address.classId) &&
    1250             769 :                 obj->address.objectSubId == 0)
    1251                 :             {
    1252             757 :                 attnum = get_object_attnum_name(obj->address.classId);
    1253             757 :                 if (attnum != InvalidAttrNumber)
    1254                 :                 {
    1255             757 :                     datum = heap_getattr(tuple, attnum,
    1256                 :                                          RelationGetDescr(catalog), &isnull);
    1257             757 :                     if (!isnull)
    1258             757 :                         obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
    1259                 :                 }
    1260                 :             }
    1261                 :         }
    1262                 : 
    1263            1034 :         table_close(catalog, AccessShareLock);
    1264                 :     }
    1265                 :     else
    1266                 :     {
    1267             172 :         if (object->classId == NamespaceRelationId &&
    1268 UBC           0 :             isTempNamespace(object->objectId))
    1269               0 :             obj->istemp = true;
    1270                 :     }
    1271                 : 
    1272                 :     /* object identity, objname and objargs */
    1273 CBC        1206 :     obj->objidentity =
    1274            1206 :         getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs,
    1275                 :                                false);
    1276                 : 
    1277                 :     /* object type */
    1278            1206 :     obj->objecttype = getObjectTypeDescription(&obj->address, false);
    1279                 : 
    1280            1206 :     slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
    1281                 : 
    1282            1206 :     MemoryContextSwitchTo(oldcxt);
    1283                 : }
    1284                 : 
    1285                 : /*
    1286                 :  * pg_event_trigger_dropped_objects
    1287                 :  *
    1288                 :  * Make the list of dropped objects available to the user function run by the
    1289                 :  * Event Trigger.
    1290                 :  */
    1291                 : Datum
    1292              57 : pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
    1293                 : {
    1294              57 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
    1295                 :     slist_iter  iter;
    1296                 : 
    1297                 :     /*
    1298                 :      * Protect this function from being called out of context
    1299                 :      */
    1300              57 :     if (!currentEventTriggerState ||
    1301              57 :         !currentEventTriggerState->in_sql_drop)
    1302 UBC           0 :         ereport(ERROR,
    1303                 :                 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
    1304                 :                  errmsg("%s can only be called in a sql_drop event trigger function",
    1305                 :                         "pg_event_trigger_dropped_objects()")));
    1306                 : 
    1307                 :     /* Build tuplestore to hold the result rows */
    1308 CBC          57 :     InitMaterializedSRF(fcinfo, 0);
    1309                 : 
    1310             594 :     slist_foreach(iter, &(currentEventTriggerState->SQLDropList))
    1311                 :     {
    1312                 :         SQLDropObject *obj;
    1313             537 :         int         i = 0;
    1314 GNC         537 :         Datum       values[12] = {0};
    1315             537 :         bool        nulls[12] = {0};
    1316                 : 
    1317 CBC         537 :         obj = slist_container(SQLDropObject, next, iter.cur);
    1318                 : 
    1319                 :         /* classid */
    1320             537 :         values[i++] = ObjectIdGetDatum(obj->address.classId);
    1321                 : 
    1322                 :         /* objid */
    1323             537 :         values[i++] = ObjectIdGetDatum(obj->address.objectId);
    1324                 : 
    1325                 :         /* objsubid */
    1326             537 :         values[i++] = Int32GetDatum(obj->address.objectSubId);
    1327                 : 
    1328                 :         /* original */
    1329             537 :         values[i++] = BoolGetDatum(obj->original);
    1330                 : 
    1331                 :         /* normal */
    1332             537 :         values[i++] = BoolGetDatum(obj->normal);
    1333                 : 
    1334                 :         /* is_temporary */
    1335             537 :         values[i++] = BoolGetDatum(obj->istemp);
    1336                 : 
    1337                 :         /* object_type */
    1338             537 :         values[i++] = CStringGetTextDatum(obj->objecttype);
    1339 ECB             : 
    1340                 :         /* schema_name */
    1341 CBC         537 :         if (obj->schemaname)
    1342 GIC         477 :             values[i++] = CStringGetTextDatum(obj->schemaname);
    1343                 :         else
    1344 CBC          60 :             nulls[i++] = true;
    1345 ECB             : 
    1346                 :         /* object_name */
    1347 CBC         537 :         if (obj->objname)
    1348 GIC         438 :             values[i++] = CStringGetTextDatum(obj->objname);
    1349                 :         else
    1350 CBC          99 :             nulls[i++] = true;
    1351 ECB             : 
    1352                 :         /* object_identity */
    1353 GBC         537 :         if (obj->objidentity)
    1354 GIC         537 :             values[i++] = CStringGetTextDatum(obj->objidentity);
    1355                 :         else
    1356 LBC           0 :             nulls[i++] = true;
    1357                 : 
    1358 ECB             :         /* address_names and address_args */
    1359 GIC         537 :         if (obj->addrnames)
    1360 ECB             :         {
    1361 CBC         537 :             values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrnames));
    1362                 : 
    1363             537 :             if (obj->addrargs)
    1364 GIC          30 :                 values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrargs));
    1365                 :             else
    1366             507 :                 values[i++] = PointerGetDatum(construct_empty_array(TEXTOID));
    1367 EUB             :         }
    1368                 :         else
    1369                 :         {
    1370 UIC           0 :             nulls[i++] = true;
    1371 LBC           0 :             nulls[i++] = true;
    1372                 :         }
    1373                 : 
    1374 GIC         537 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
    1375 ECB             :                              values, nulls);
    1376                 :     }
    1377                 : 
    1378 GIC          57 :     return (Datum) 0;
    1379                 : }
    1380                 : 
    1381                 : /*
    1382                 :  * pg_event_trigger_table_rewrite_oid
    1383                 :  *
    1384                 :  * Make the Oid of the table going to be rewritten available to the user
    1385 ECB             :  * function run by the Event Trigger.
    1386                 :  */
    1387                 : Datum
    1388 GIC          33 : pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS)
    1389                 : {
    1390 ECB             :     /*
    1391                 :      * Protect this function from being called out of context
    1392                 :      */
    1393 GIC          33 :     if (!currentEventTriggerState ||
    1394              30 :         currentEventTriggerState->table_rewrite_oid == InvalidOid)
    1395               3 :         ereport(ERROR,
    1396                 :                 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
    1397 ECB             :                  errmsg("%s can only be called in a table_rewrite event trigger function",
    1398                 :                         "pg_event_trigger_table_rewrite_oid()")));
    1399                 : 
    1400 GIC          30 :     PG_RETURN_OID(currentEventTriggerState->table_rewrite_oid);
    1401                 : }
    1402                 : 
    1403                 : /*
    1404                 :  * pg_event_trigger_table_rewrite_reason
    1405                 :  *
    1406 ECB             :  * Make the rewrite reason available to the user.
    1407                 :  */
    1408                 : Datum
    1409 GIC          24 : pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS)
    1410                 : {
    1411 ECB             :     /*
    1412                 :      * Protect this function from being called out of context
    1413 EUB             :      */
    1414 GIC          24 :     if (!currentEventTriggerState ||
    1415              24 :         currentEventTriggerState->table_rewrite_reason == 0)
    1416 UIC           0 :         ereport(ERROR,
    1417                 :                 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
    1418 ECB             :                  errmsg("%s can only be called in a table_rewrite event trigger function",
    1419                 :                         "pg_event_trigger_table_rewrite_reason()")));
    1420                 : 
    1421 GIC          24 :     PG_RETURN_INT32(currentEventTriggerState->table_rewrite_reason);
    1422                 : }
    1423                 : 
    1424                 : /*-------------------------------------------------------------------------
    1425                 :  * Support for DDL command deparsing
    1426                 :  *
    1427                 :  * The routines below enable an event trigger function to obtain a list of
    1428                 :  * DDL commands as they are executed.  There are three main pieces to this
    1429                 :  * feature:
    1430                 :  *
    1431                 :  * 1) Within ProcessUtilitySlow, or some sub-routine thereof, each DDL command
    1432                 :  * adds a struct CollectedCommand representation of itself to the command list,
    1433                 :  * using the routines below.
    1434                 :  *
    1435                 :  * 2) Some time after that, ddl_command_end fires and the command list is made
    1436                 :  * available to the event trigger function via pg_event_trigger_ddl_commands();
    1437                 :  * the complete command details are exposed as a column of type pg_ddl_command.
    1438                 :  *
    1439                 :  * 3) An extension can install a function capable of taking a value of type
    1440                 :  * pg_ddl_command and transform it into some external, user-visible and/or
    1441                 :  * -modifiable representation.
    1442                 :  *-------------------------------------------------------------------------
    1443                 :  */
    1444                 : 
    1445                 : /*
    1446 ECB             :  * Inhibit DDL command collection.
    1447                 :  */
    1448                 : void
    1449 CBC         123 : EventTriggerInhibitCommandCollection(void)
    1450                 : {
    1451             123 :     if (!currentEventTriggerState)
    1452 GIC         122 :         return;
    1453                 : 
    1454               1 :     currentEventTriggerState->commandCollectionInhibited = true;
    1455                 : }
    1456                 : 
    1457                 : /*
    1458 ECB             :  * Re-establish DDL command collection.
    1459                 :  */
    1460                 : void
    1461 CBC         123 : EventTriggerUndoInhibitCommandCollection(void)
    1462                 : {
    1463             123 :     if (!currentEventTriggerState)
    1464 GIC         122 :         return;
    1465                 : 
    1466               1 :     currentEventTriggerState->commandCollectionInhibited = false;
    1467                 : }
    1468                 : 
    1469                 : /*
    1470                 :  * EventTriggerCollectSimpleCommand
    1471                 :  *      Save data about a simple DDL command that was just executed
    1472                 :  *
    1473                 :  * address identifies the object being operated on.  secondaryObject is an
    1474                 :  * object address that was related in some way to the executed command; its
    1475                 :  * meaning is command-specific.
    1476                 :  *
    1477                 :  * For instance, for an ALTER obj SET SCHEMA command, objtype is the type of
    1478                 :  * object being moved, objectId is its OID, and secondaryOid is the OID of the
    1479                 :  * old schema.  (The destination schema OID can be obtained by catalog lookup
    1480 ECB             :  * of the object.)
    1481                 :  */
    1482                 : void
    1483 GIC      151428 : EventTriggerCollectSimpleCommand(ObjectAddress address,
    1484                 :                                  ObjectAddress secondaryObject,
    1485                 :                                  Node *parsetree)
    1486                 : {
    1487                 :     MemoryContext oldcxt;
    1488 ECB             :     CollectedCommand *command;
    1489                 : 
    1490                 :     /* ignore if event trigger context not set, or collection disabled */
    1491 GIC      151428 :     if (!currentEventTriggerState ||
    1492 CBC         483 :         currentEventTriggerState->commandCollectionInhibited)
    1493 GIC      150945 :         return;
    1494 ECB             : 
    1495 GIC         483 :     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1496 ECB             : 
    1497 CBC         483 :     command = palloc(sizeof(CollectedCommand));
    1498                 : 
    1499             483 :     command->type = SCT_Simple;
    1500             483 :     command->in_extension = creating_extension;
    1501 ECB             : 
    1502 GIC         483 :     command->d.simple.address = address;
    1503 CBC         483 :     command->d.simple.secondaryObject = secondaryObject;
    1504 GIC         483 :     command->parsetree = copyObject(parsetree);
    1505                 : 
    1506 CBC         483 :     currentEventTriggerState->commandList = lappend(currentEventTriggerState->commandList,
    1507                 :                                                     command);
    1508                 : 
    1509 GIC         483 :     MemoryContextSwitchTo(oldcxt);
    1510                 : }
    1511                 : 
    1512                 : /*
    1513                 :  * EventTriggerAlterTableStart
    1514                 :  *      Prepare to receive data on an ALTER TABLE command about to be executed
    1515                 :  *
    1516                 :  * Note we don't collect the command immediately; instead we keep it in
    1517                 :  * currentCommand, and only when we're done processing the subcommands we will
    1518 ECB             :  * add it to the command list.
    1519                 :  */
    1520                 : void
    1521 GIC       94996 : EventTriggerAlterTableStart(Node *parsetree)
    1522                 : {
    1523                 :     MemoryContext oldcxt;
    1524 ECB             :     CollectedCommand *command;
    1525                 : 
    1526                 :     /* ignore if event trigger context not set, or collection disabled */
    1527 GIC       94996 :     if (!currentEventTriggerState ||
    1528 CBC         419 :         currentEventTriggerState->commandCollectionInhibited)
    1529 GIC       94577 :         return;
    1530 ECB             : 
    1531 GIC         419 :     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1532 ECB             : 
    1533 CBC         419 :     command = palloc(sizeof(CollectedCommand));
    1534                 : 
    1535             419 :     command->type = SCT_AlterTable;
    1536             419 :     command->in_extension = creating_extension;
    1537 ECB             : 
    1538 CBC         419 :     command->d.alterTable.classId = RelationRelationId;
    1539 GIC         419 :     command->d.alterTable.objectId = InvalidOid;
    1540 CBC         419 :     command->d.alterTable.subcmds = NIL;
    1541             419 :     command->parsetree = copyObject(parsetree);
    1542                 : 
    1543             419 :     command->parent = currentEventTriggerState->currentCommand;
    1544 GIC         419 :     currentEventTriggerState->currentCommand = command;
    1545                 : 
    1546             419 :     MemoryContextSwitchTo(oldcxt);
    1547                 : }
    1548                 : 
    1549                 : /*
    1550                 :  * Remember the OID of the object being affected by an ALTER TABLE.
    1551                 :  *
    1552 ECB             :  * This is needed because in some cases we don't know the OID until later.
    1553                 :  */
    1554                 : void
    1555 CBC       45170 : EventTriggerAlterTableRelid(Oid objectId)
    1556 ECB             : {
    1557 GIC       45170 :     if (!currentEventTriggerState ||
    1558 CBC         337 :         currentEventTriggerState->commandCollectionInhibited)
    1559 GIC       44833 :         return;
    1560                 : 
    1561             337 :     currentEventTriggerState->currentCommand->d.alterTable.objectId = objectId;
    1562                 : }
    1563                 : 
    1564                 : /*
    1565                 :  * EventTriggerCollectAlterTableSubcmd
    1566                 :  *      Save data about a single part of an ALTER TABLE.
    1567                 :  *
    1568                 :  * Several different commands go through this path, but apart from ALTER TABLE
    1569                 :  * itself, they are all concerned with AlterTableCmd nodes that are generated
    1570 ECB             :  * internally, so that's all that this code needs to handle at the moment.
    1571                 :  */
    1572                 : void
    1573 GIC       70431 : EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
    1574                 : {
    1575                 :     MemoryContext oldcxt;
    1576 ECB             :     CollectedATSubcmd *newsub;
    1577                 : 
    1578                 :     /* ignore if event trigger context not set, or collection disabled */
    1579 GIC       70431 :     if (!currentEventTriggerState ||
    1580 CBC         507 :         currentEventTriggerState->commandCollectionInhibited)
    1581           69924 :         return;
    1582 ECB             : 
    1583 GIC         507 :     Assert(IsA(subcmd, AlterTableCmd));
    1584 CBC         507 :     Assert(currentEventTriggerState->currentCommand != NULL);
    1585 GIC         507 :     Assert(OidIsValid(currentEventTriggerState->currentCommand->d.alterTable.objectId));
    1586 ECB             : 
    1587 CBC         507 :     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1588 ECB             : 
    1589 GIC         507 :     newsub = palloc(sizeof(CollectedATSubcmd));
    1590 CBC         507 :     newsub->address = address;
    1591             507 :     newsub->parsetree = copyObject(subcmd);
    1592                 : 
    1593            1014 :     currentEventTriggerState->currentCommand->d.alterTable.subcmds =
    1594 GIC         507 :         lappend(currentEventTriggerState->currentCommand->d.alterTable.subcmds, newsub);
    1595                 : 
    1596             507 :     MemoryContextSwitchTo(oldcxt);
    1597                 : }
    1598                 : 
    1599                 : /*
    1600                 :  * EventTriggerAlterTableEnd
    1601                 :  *      Finish up saving an ALTER TABLE command, and add it to command list.
    1602                 :  *
    1603                 :  * FIXME this API isn't considering the possibility that an xact/subxact is
    1604                 :  * aborted partway through.  Probably it's best to add an
    1605 ECB             :  * AtEOSubXact_EventTriggers() to fix this.
    1606                 :  */
    1607                 : void
    1608 GIC       93452 : EventTriggerAlterTableEnd(void)
    1609                 : {
    1610 ECB             :     CollectedCommand *parent;
    1611                 : 
    1612                 :     /* ignore if event trigger context not set, or collection disabled */
    1613 GIC       93452 :     if (!currentEventTriggerState ||
    1614 CBC         413 :         currentEventTriggerState->commandCollectionInhibited)
    1615 GIC       93039 :         return;
    1616                 : 
    1617 CBC         413 :     parent = currentEventTriggerState->currentCommand->parent;
    1618                 : 
    1619                 :     /* If no subcommands, don't collect */
    1620 GNC         413 :     if (currentEventTriggerState->currentCommand->d.alterTable.subcmds != NIL)
    1621 ECB             :     {
    1622                 :         MemoryContext oldcxt;
    1623                 : 
    1624 CBC         320 :         oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1625 ECB             : 
    1626 GIC         640 :         currentEventTriggerState->commandList =
    1627 CBC         320 :             lappend(currentEventTriggerState->commandList,
    1628 GIC         320 :                     currentEventTriggerState->currentCommand);
    1629                 : 
    1630 CBC         320 :         MemoryContextSwitchTo(oldcxt);
    1631                 :     }
    1632 ECB             :     else
    1633 GIC          93 :         pfree(currentEventTriggerState->currentCommand);
    1634                 : 
    1635             413 :     currentEventTriggerState->currentCommand = parent;
    1636                 : }
    1637                 : 
    1638                 : /*
    1639                 :  * EventTriggerCollectGrant
    1640                 :  *      Save data about a GRANT/REVOKE command being executed
    1641                 :  *
    1642                 :  * This function creates a copy of the InternalGrant, as the original might
    1643 ECB             :  * not have the right lifetime.
    1644                 :  */
    1645                 : void
    1646 GIC       48143 : EventTriggerCollectGrant(InternalGrant *istmt)
    1647                 : {
    1648                 :     MemoryContext oldcxt;
    1649                 :     CollectedCommand *command;
    1650                 :     InternalGrant *icopy;
    1651 ECB             :     ListCell   *cell;
    1652                 : 
    1653                 :     /* ignore if event trigger context not set, or collection disabled */
    1654 GIC       48143 :     if (!currentEventTriggerState ||
    1655 CBC          15 :         currentEventTriggerState->commandCollectionInhibited)
    1656 GIC       48128 :         return;
    1657                 : 
    1658              15 :     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1659                 : 
    1660 ECB             :     /*
    1661                 :      * This is tedious, but necessary.
    1662                 :      */
    1663 CBC          15 :     icopy = palloc(sizeof(InternalGrant));
    1664              15 :     memcpy(icopy, istmt, sizeof(InternalGrant));
    1665              15 :     icopy->objects = list_copy(istmt->objects);
    1666 GBC          15 :     icopy->grantees = list_copy(istmt->grantees);
    1667 GIC          15 :     icopy->col_privs = NIL;
    1668              15 :     foreach(cell, istmt->col_privs)
    1669 LBC           0 :         icopy->col_privs = lappend(icopy->col_privs, copyObject(lfirst(cell)));
    1670 ECB             : 
    1671                 :     /* Now collect it, using the copied InternalGrant */
    1672 CBC          15 :     command = palloc(sizeof(CollectedCommand));
    1673              15 :     command->type = SCT_Grant;
    1674 GIC          15 :     command->in_extension = creating_extension;
    1675 CBC          15 :     command->d.grant.istmt = icopy;
    1676              15 :     command->parsetree = NULL;
    1677                 : 
    1678              30 :     currentEventTriggerState->commandList =
    1679 GIC          15 :         lappend(currentEventTriggerState->commandList, command);
    1680                 : 
    1681              15 :     MemoryContextSwitchTo(oldcxt);
    1682                 : }
    1683                 : 
    1684                 : /*
    1685                 :  * EventTriggerCollectAlterOpFam
    1686                 :  *      Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
    1687 ECB             :  *      executed
    1688                 :  */
    1689                 : void
    1690 GIC         145 : EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid,
    1691                 :                               List *operators, List *procedures)
    1692                 : {
    1693                 :     MemoryContext oldcxt;
    1694 ECB             :     CollectedCommand *command;
    1695                 : 
    1696                 :     /* ignore if event trigger context not set, or collection disabled */
    1697 GIC         145 :     if (!currentEventTriggerState ||
    1698 CBC           1 :         currentEventTriggerState->commandCollectionInhibited)
    1699 GIC         144 :         return;
    1700 ECB             : 
    1701 CBC           1 :     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1702 ECB             : 
    1703 CBC           1 :     command = palloc(sizeof(CollectedCommand));
    1704 GIC           1 :     command->type = SCT_AlterOpFamily;
    1705 CBC           1 :     command->in_extension = creating_extension;
    1706               1 :     ObjectAddressSet(command->d.opfam.address,
    1707 ECB             :                      OperatorFamilyRelationId, opfamoid);
    1708 GIC           1 :     command->d.opfam.operators = operators;
    1709 CBC           1 :     command->d.opfam.procedures = procedures;
    1710               1 :     command->parsetree = (Node *) copyObject(stmt);
    1711                 : 
    1712               2 :     currentEventTriggerState->commandList =
    1713 GIC           1 :         lappend(currentEventTriggerState->commandList, command);
    1714                 : 
    1715               1 :     MemoryContextSwitchTo(oldcxt);
    1716                 : }
    1717                 : 
    1718                 : /*
    1719                 :  * EventTriggerCollectCreateOpClass
    1720 ECB             :  *      Save data about a CREATE OPERATOR CLASS command being executed
    1721                 :  */
    1722                 : void
    1723 GIC         183 : EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid,
    1724                 :                                  List *operators, List *procedures)
    1725                 : {
    1726                 :     MemoryContext oldcxt;
    1727 ECB             :     CollectedCommand *command;
    1728                 : 
    1729                 :     /* ignore if event trigger context not set, or collection disabled */
    1730 GIC         183 :     if (!currentEventTriggerState ||
    1731 CBC           4 :         currentEventTriggerState->commandCollectionInhibited)
    1732 GIC         179 :         return;
    1733 ECB             : 
    1734 CBC           4 :     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1735 ECB             : 
    1736 CBC           4 :     command = palloc0(sizeof(CollectedCommand));
    1737 GIC           4 :     command->type = SCT_CreateOpClass;
    1738 CBC           4 :     command->in_extension = creating_extension;
    1739               4 :     ObjectAddressSet(command->d.createopc.address,
    1740 ECB             :                      OperatorClassRelationId, opcoid);
    1741 GIC           4 :     command->d.createopc.operators = operators;
    1742 CBC           4 :     command->d.createopc.procedures = procedures;
    1743               4 :     command->parsetree = (Node *) copyObject(stmt);
    1744                 : 
    1745               8 :     currentEventTriggerState->commandList =
    1746 GIC           4 :         lappend(currentEventTriggerState->commandList, command);
    1747                 : 
    1748               4 :     MemoryContextSwitchTo(oldcxt);
    1749                 : }
    1750                 : 
    1751                 : /*
    1752                 :  * EventTriggerCollectAlterTSConfig
    1753                 :  *      Save data about an ALTER TEXT SEARCH CONFIGURATION command being
    1754 ECB             :  *      executed
    1755                 :  */
    1756                 : void
    1757 GIC       25548 : EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId,
    1758                 :                                  Oid *dictIds, int ndicts)
    1759                 : {
    1760                 :     MemoryContext oldcxt;
    1761 ECB             :     CollectedCommand *command;
    1762                 : 
    1763                 :     /* ignore if event trigger context not set, or collection disabled */
    1764 GIC       25548 :     if (!currentEventTriggerState ||
    1765 CBC           1 :         currentEventTriggerState->commandCollectionInhibited)
    1766 GIC       25547 :         return;
    1767 ECB             : 
    1768 CBC           1 :     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1769 ECB             : 
    1770 CBC           1 :     command = palloc0(sizeof(CollectedCommand));
    1771 GIC           1 :     command->type = SCT_AlterTSConfig;
    1772 CBC           1 :     command->in_extension = creating_extension;
    1773               1 :     ObjectAddressSet(command->d.atscfg.address,
    1774 ECB             :                      TSConfigRelationId, cfgId);
    1775 CBC           1 :     command->d.atscfg.dictIds = palloc(sizeof(Oid) * ndicts);
    1776 GIC           1 :     memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts);
    1777 CBC           1 :     command->d.atscfg.ndicts = ndicts;
    1778               1 :     command->parsetree = (Node *) copyObject(stmt);
    1779                 : 
    1780               2 :     currentEventTriggerState->commandList =
    1781 GIC           1 :         lappend(currentEventTriggerState->commandList, command);
    1782                 : 
    1783               1 :     MemoryContextSwitchTo(oldcxt);
    1784                 : }
    1785                 : 
    1786                 : /*
    1787                 :  * EventTriggerCollectAlterDefPrivs
    1788                 :  *      Save data about an ALTER DEFAULT PRIVILEGES command being
    1789 ECB             :  *      executed
    1790                 :  */
    1791                 : void
    1792 GIC          77 : EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt)
    1793                 : {
    1794                 :     MemoryContext oldcxt;
    1795 ECB             :     CollectedCommand *command;
    1796                 : 
    1797                 :     /* ignore if event trigger context not set, or collection disabled */
    1798 GIC          77 :     if (!currentEventTriggerState ||
    1799 CBC           4 :         currentEventTriggerState->commandCollectionInhibited)
    1800 GIC          73 :         return;
    1801 ECB             : 
    1802 CBC           4 :     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
    1803 ECB             : 
    1804 CBC           4 :     command = palloc0(sizeof(CollectedCommand));
    1805               4 :     command->type = SCT_AlterDefaultPrivileges;
    1806 GIC           4 :     command->d.defprivs.objtype = stmt->action->objtype;
    1807 CBC           4 :     command->in_extension = creating_extension;
    1808               4 :     command->parsetree = (Node *) copyObject(stmt);
    1809 ECB             : 
    1810 GIC           8 :     currentEventTriggerState->commandList =
    1811               4 :         lappend(currentEventTriggerState->commandList, command);
    1812               4 :     MemoryContextSwitchTo(oldcxt);
    1813                 : }
    1814                 : 
    1815                 : /*
    1816                 :  * In a ddl_command_end event trigger, this function reports the DDL commands
    1817 ECB             :  * being run.
    1818                 :  */
    1819                 : Datum
    1820 GIC         208 : pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
    1821                 : {
    1822             208 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
    1823                 :     ListCell   *lc;
    1824                 : 
    1825 ECB             :     /*
    1826 EUB             :      * Protect this function from being called out of context
    1827                 :      */
    1828 GIC         208 :     if (!currentEventTriggerState)
    1829 UIC           0 :         ereport(ERROR,
    1830                 :                 (errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
    1831                 :                  errmsg("%s can only be called in an event trigger function",
    1832 ECB             :                         "pg_event_trigger_ddl_commands()")));
    1833                 : 
    1834                 :     /* Build tuplestore to hold the result rows */
    1835 GIC         208 :     InitMaterializedSRF(fcinfo, 0);
    1836 ECB             : 
    1837 GIC         487 :     foreach(lc, currentEventTriggerState->commandList)
    1838 ECB             :     {
    1839 GIC         279 :         CollectedCommand *cmd = lfirst(lc);
    1840 ECB             :         Datum       values[9];
    1841 GNC         279 :         bool        nulls[9] = {0};
    1842                 :         ObjectAddress addr;
    1843 GIC         279 :         int         i = 0;
    1844                 : 
    1845                 :         /*
    1846                 :          * For IF NOT EXISTS commands that attempt to create an existing
    1847                 :          * object, the returned OID is Invalid.  Don't return anything.
    1848                 :          *
    1849                 :          * One might think that a viable alternative would be to look up the
    1850                 :          * Oid of the existing object and run the deparse with that.  But
    1851                 :          * since the parse tree might be different from the one that created
    1852 ECB             :          * the object in the first place, we might not end up in a consistent
    1853                 :          * state anyway.
    1854                 :          */
    1855 GIC         279 :         if (cmd->type == SCT_Simple &&
    1856 CBC         196 :             !OidIsValid(cmd->d.simple.address.objectId))
    1857 GIC           3 :             continue;
    1858 ECB             : 
    1859 GIC         279 :         switch (cmd->type)
    1860                 :         {
    1861             269 :             case SCT_Simple:
    1862                 :             case SCT_AlterTable:
    1863                 :             case SCT_AlterOpFamily:
    1864 ECB             :             case SCT_CreateOpClass:
    1865                 :             case SCT_AlterTSConfig:
    1866                 :                 {
    1867                 :                     char       *identity;
    1868                 :                     char       *type;
    1869 CBC         269 :                     char       *schema = NULL;
    1870                 : 
    1871 GIC         269 :                     if (cmd->type == SCT_Simple)
    1872 CBC         196 :                         addr = cmd->d.simple.address;
    1873              73 :                     else if (cmd->type == SCT_AlterTable)
    1874              67 :                         ObjectAddressSet(addr,
    1875 ECB             :                                          cmd->d.alterTable.classId,
    1876                 :                                          cmd->d.alterTable.objectId);
    1877 CBC           6 :                     else if (cmd->type == SCT_AlterOpFamily)
    1878 GIC           1 :                         addr = cmd->d.opfam.address;
    1879               5 :                     else if (cmd->type == SCT_CreateOpClass)
    1880               4 :                         addr = cmd->d.createopc.address;
    1881               1 :                     else if (cmd->type == SCT_AlterTSConfig)
    1882               1 :                         addr = cmd->d.atscfg.address;
    1883                 : 
    1884                 :                     /*
    1885                 :                      * If an object was dropped in the same command we may end
    1886 ECB             :                      * up in a situation where we generated a message but can
    1887                 :                      * no longer look for the object information, so skip it
    1888                 :                      * rather than failing.  This can happen for example with
    1889                 :                      * some subcommand combinations of ALTER TABLE.
    1890                 :                      */
    1891 CBC         269 :                     identity = getObjectIdentity(&addr, true);
    1892 GIC         269 :                     if (identity == NULL)
    1893               3 :                         continue;
    1894                 : 
    1895                 :                     /* The type can never be NULL. */
    1896             266 :                     type = getObjectTypeDescription(&addr, true);
    1897                 : 
    1898                 :                     /*
    1899 ECB             :                      * Obtain schema name, if any ("pg_temp" if a temp
    1900                 :                      * object). If the object class is not in the supported
    1901                 :                      * list here, we assume it's a schema-less object type,
    1902                 :                      * and thus "schema" remains set to NULL.
    1903                 :                      */
    1904 CBC         266 :                     if (is_objectclass_supported(addr.classId))
    1905                 :                     {
    1906                 :                         AttrNumber  nspAttnum;
    1907                 : 
    1908 GIC         266 :                         nspAttnum = get_object_attnum_namespace(addr.classId);
    1909             266 :                         if (nspAttnum != InvalidAttrNumber)
    1910                 :                         {
    1911 ECB             :                             Relation    catalog;
    1912                 :                             HeapTuple   objtup;
    1913                 :                             Oid         schema_oid;
    1914                 :                             bool        isnull;
    1915                 : 
    1916 GBC         238 :                             catalog = table_open(addr.classId, AccessShareLock);
    1917 GIC         238 :                             objtup = get_catalog_object_by_oid(catalog,
    1918 CBC         238 :                                                                get_object_attnum_oid(addr.classId),
    1919 ECB             :                                                                addr.objectId);
    1920 GIC         238 :                             if (!HeapTupleIsValid(objtup))
    1921 LBC           0 :                                 elog(ERROR, "cache lookup failed for object %u/%u",
    1922 EUB             :                                      addr.classId, addr.objectId);
    1923 GIC         238 :                             schema_oid =
    1924             238 :                                 heap_getattr(objtup, nspAttnum,
    1925 ECB             :                                              RelationGetDescr(catalog), &isnull);
    1926 GIC         238 :                             if (isnull)
    1927 LBC           0 :                                 elog(ERROR,
    1928                 :                                      "invalid null namespace in object %u/%u/%d",
    1929                 :                                      addr.classId, addr.objectId, addr.objectSubId);
    1930 GIC         238 :                             schema = get_namespace_name_or_temp(schema_oid);
    1931                 : 
    1932 CBC         238 :                             table_close(catalog, AccessShareLock);
    1933                 :                         }
    1934 ECB             :                     }
    1935                 : 
    1936                 :                     /* classid */
    1937 GIC         266 :                     values[i++] = ObjectIdGetDatum(addr.classId);
    1938 ECB             :                     /* objid */
    1939 GIC         266 :                     values[i++] = ObjectIdGetDatum(addr.objectId);
    1940 ECB             :                     /* objsubid */
    1941 GIC         266 :                     values[i++] = Int32GetDatum(addr.objectSubId);
    1942 ECB             :                     /* command tag */
    1943 CBC         266 :                     values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
    1944                 :                     /* object_type */
    1945             266 :                     values[i++] = CStringGetTextDatum(type);
    1946                 :                     /* schema */
    1947             266 :                     if (schema == NULL)
    1948 GIC          28 :                         nulls[i++] = true;
    1949 ECB             :                     else
    1950 GIC         238 :                         values[i++] = CStringGetTextDatum(schema);
    1951 ECB             :                     /* identity */
    1952 GIC         266 :                     values[i++] = CStringGetTextDatum(identity);
    1953 ECB             :                     /* in_extension */
    1954 GIC         266 :                     values[i++] = BoolGetDatum(cmd->in_extension);
    1955 ECB             :                     /* command */
    1956 GIC         266 :                     values[i++] = PointerGetDatum(cmd);
    1957 ECB             :                 }
    1958 GIC         266 :                 break;
    1959 ECB             : 
    1960 GIC           1 :             case SCT_AlterDefaultPrivileges:
    1961 ECB             :                 /* classid */
    1962 GIC           1 :                 nulls[i++] = true;
    1963 ECB             :                 /* objid */
    1964 GIC           1 :                 nulls[i++] = true;
    1965 ECB             :                 /* objsubid */
    1966 GIC           1 :                 nulls[i++] = true;
    1967 ECB             :                 /* command tag */
    1968 GIC           1 :                 values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
    1969 ECB             :                 /* object_type */
    1970 GIC           1 :                 values[i++] = CStringGetTextDatum(stringify_adefprivs_objtype(cmd->d.defprivs.objtype));
    1971 ECB             :                 /* schema */
    1972 GIC           1 :                 nulls[i++] = true;
    1973 ECB             :                 /* identity */
    1974 CBC           1 :                 nulls[i++] = true;
    1975                 :                 /* in_extension */
    1976               1 :                 values[i++] = BoolGetDatum(cmd->in_extension);
    1977                 :                 /* command */
    1978               1 :                 values[i++] = PointerGetDatum(cmd);
    1979 GIC           1 :                 break;
    1980 ECB             : 
    1981 GIC           9 :             case SCT_Grant:
    1982 ECB             :                 /* classid */
    1983 GIC           9 :                 nulls[i++] = true;
    1984 ECB             :                 /* objid */
    1985 GIC           9 :                 nulls[i++] = true;
    1986                 :                 /* objsubid */
    1987 CBC           9 :                 nulls[i++] = true;
    1988                 :                 /* command tag */
    1989               9 :                 values[i++] = CStringGetTextDatum(cmd->d.grant.istmt->is_grant ?
    1990                 :                                                   "GRANT" : "REVOKE");
    1991 ECB             :                 /* object_type */
    1992 GIC           9 :                 values[i++] = CStringGetTextDatum(stringify_grant_objtype(cmd->d.grant.istmt->objtype));
    1993 ECB             :                 /* schema */
    1994 GIC           9 :                 nulls[i++] = true;
    1995 ECB             :                 /* identity */
    1996 CBC           9 :                 nulls[i++] = true;
    1997                 :                 /* in_extension */
    1998 GIC           9 :                 values[i++] = BoolGetDatum(cmd->in_extension);
    1999 ECB             :                 /* command */
    2000 GIC           9 :                 values[i++] = PointerGetDatum(cmd);
    2001               9 :                 break;
    2002                 :         }
    2003 ECB             : 
    2004 GIC         276 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
    2005                 :                              values, nulls);
    2006                 :     }
    2007                 : 
    2008             208 :     PG_RETURN_VOID();
    2009                 : }
    2010                 : 
    2011 ECB             : /*
    2012                 :  * Return the ObjectType as a string, as it would appear in GRANT and
    2013                 :  * REVOKE commands.
    2014                 :  */
    2015 EUB             : static const char *
    2016 GBC           9 : stringify_grant_objtype(ObjectType objtype)
    2017 ECB             : {
    2018 CBC           9 :     switch (objtype)
    2019 EUB             :     {
    2020 UBC           0 :         case OBJECT_COLUMN:
    2021               0 :             return "COLUMN";
    2022 GBC           5 :         case OBJECT_TABLE:
    2023               5 :             return "TABLE";
    2024 UBC           0 :         case OBJECT_SEQUENCE:
    2025               0 :             return "SEQUENCE";
    2026               0 :         case OBJECT_DATABASE:
    2027               0 :             return "DATABASE";
    2028               0 :         case OBJECT_DOMAIN:
    2029 LBC           0 :             return "DOMAIN";
    2030               0 :         case OBJECT_FDW:
    2031 UBC           0 :             return "FOREIGN DATA WRAPPER";
    2032               0 :         case OBJECT_FOREIGN_SERVER:
    2033               0 :             return "FOREIGN SERVER";
    2034 GBC           4 :         case OBJECT_FUNCTION:
    2035               4 :             return "FUNCTION";
    2036 UBC           0 :         case OBJECT_LANGUAGE:
    2037               0 :             return "LANGUAGE";
    2038               0 :         case OBJECT_LARGEOBJECT:
    2039               0 :             return "LARGE OBJECT";
    2040               0 :         case OBJECT_SCHEMA:
    2041               0 :             return "SCHEMA";
    2042               0 :         case OBJECT_PARAMETER_ACL:
    2043               0 :             return "PARAMETER";
    2044               0 :         case OBJECT_PROCEDURE:
    2045               0 :             return "PROCEDURE";
    2046               0 :         case OBJECT_ROUTINE:
    2047 UIC           0 :             return "ROUTINE";
    2048 UBC           0 :         case OBJECT_TABLESPACE:
    2049 UIC           0 :             return "TABLESPACE";
    2050               0 :         case OBJECT_TYPE:
    2051               0 :             return "TYPE";
    2052                 :             /* these currently aren't used */
    2053               0 :         case OBJECT_ACCESS_METHOD:
    2054                 :         case OBJECT_AGGREGATE:
    2055                 :         case OBJECT_AMOP:
    2056                 :         case OBJECT_AMPROC:
    2057                 :         case OBJECT_ATTRIBUTE:
    2058                 :         case OBJECT_CAST:
    2059                 :         case OBJECT_COLLATION:
    2060                 :         case OBJECT_CONVERSION:
    2061                 :         case OBJECT_DEFAULT:
    2062                 :         case OBJECT_DEFACL:
    2063                 :         case OBJECT_DOMCONSTRAINT:
    2064                 :         case OBJECT_EVENT_TRIGGER:
    2065                 :         case OBJECT_EXTENSION:
    2066                 :         case OBJECT_FOREIGN_TABLE:
    2067                 :         case OBJECT_INDEX:
    2068                 :         case OBJECT_MATVIEW:
    2069                 :         case OBJECT_OPCLASS:
    2070                 :         case OBJECT_OPERATOR:
    2071                 :         case OBJECT_OPFAMILY:
    2072                 :         case OBJECT_POLICY:
    2073                 :         case OBJECT_PUBLICATION:
    2074                 :         case OBJECT_PUBLICATION_NAMESPACE:
    2075                 :         case OBJECT_PUBLICATION_REL:
    2076                 :         case OBJECT_ROLE:
    2077                 :         case OBJECT_RULE:
    2078                 :         case OBJECT_STATISTIC_EXT:
    2079                 :         case OBJECT_SUBSCRIPTION:
    2080                 :         case OBJECT_TABCONSTRAINT:
    2081                 :         case OBJECT_TRANSFORM:
    2082                 :         case OBJECT_TRIGGER:
    2083                 :         case OBJECT_TSCONFIGURATION:
    2084 EUB             :         case OBJECT_TSDICTIONARY:
    2085                 :         case OBJECT_TSPARSER:
    2086                 :         case OBJECT_TSTEMPLATE:
    2087                 :         case OBJECT_USER_MAPPING:
    2088                 :         case OBJECT_VIEW:
    2089 UIC           0 :             elog(ERROR, "unsupported object type: %d", (int) objtype);
    2090                 :     }
    2091                 : 
    2092               0 :     return "???";             /* keep compiler quiet */
    2093                 : }
    2094                 : 
    2095                 : /*
    2096 ECB             :  * Return the ObjectType as a string; as above, but use the spelling
    2097                 :  * in ALTER DEFAULT PRIVILEGES commands instead.  Generally this is just
    2098                 :  * the plural.
    2099                 :  */
    2100 EUB             : static const char *
    2101 GBC           1 : stringify_adefprivs_objtype(ObjectType objtype)
    2102 ECB             : {
    2103 CBC           1 :     switch (objtype)
    2104 EUB             :     {
    2105 UBC           0 :         case OBJECT_COLUMN:
    2106               0 :             return "COLUMNS";
    2107 GBC           1 :         case OBJECT_TABLE:
    2108               1 :             return "TABLES";
    2109 UBC           0 :         case OBJECT_SEQUENCE:
    2110               0 :             return "SEQUENCES";
    2111               0 :         case OBJECT_DATABASE:
    2112               0 :             return "DATABASES";
    2113               0 :         case OBJECT_DOMAIN:
    2114               0 :             return "DOMAINS";
    2115               0 :         case OBJECT_FDW:
    2116               0 :             return "FOREIGN DATA WRAPPERS";
    2117               0 :         case OBJECT_FOREIGN_SERVER:
    2118               0 :             return "FOREIGN SERVERS";
    2119               0 :         case OBJECT_FUNCTION:
    2120               0 :             return "FUNCTIONS";
    2121               0 :         case OBJECT_LANGUAGE:
    2122               0 :             return "LANGUAGES";
    2123               0 :         case OBJECT_LARGEOBJECT:
    2124               0 :             return "LARGE OBJECTS";
    2125               0 :         case OBJECT_SCHEMA:
    2126               0 :             return "SCHEMAS";
    2127               0 :         case OBJECT_PROCEDURE:
    2128               0 :             return "PROCEDURES";
    2129               0 :         case OBJECT_ROUTINE:
    2130 UIC           0 :             return "ROUTINES";
    2131 UBC           0 :         case OBJECT_TABLESPACE:
    2132 UIC           0 :             return "TABLESPACES";
    2133               0 :         case OBJECT_TYPE:
    2134               0 :             return "TYPES";
    2135                 :             /* these currently aren't used */
    2136               0 :         case OBJECT_ACCESS_METHOD:
    2137                 :         case OBJECT_AGGREGATE:
    2138                 :         case OBJECT_AMOP:
    2139                 :         case OBJECT_AMPROC:
    2140                 :         case OBJECT_ATTRIBUTE:
    2141                 :         case OBJECT_CAST:
    2142                 :         case OBJECT_COLLATION:
    2143                 :         case OBJECT_CONVERSION:
    2144                 :         case OBJECT_DEFAULT:
    2145                 :         case OBJECT_DEFACL:
    2146                 :         case OBJECT_DOMCONSTRAINT:
    2147                 :         case OBJECT_EVENT_TRIGGER:
    2148                 :         case OBJECT_EXTENSION:
    2149                 :         case OBJECT_FOREIGN_TABLE:
    2150                 :         case OBJECT_INDEX:
    2151                 :         case OBJECT_MATVIEW:
    2152                 :         case OBJECT_OPCLASS:
    2153                 :         case OBJECT_OPERATOR:
    2154                 :         case OBJECT_OPFAMILY:
    2155                 :         case OBJECT_PARAMETER_ACL:
    2156                 :         case OBJECT_POLICY:
    2157                 :         case OBJECT_PUBLICATION:
    2158                 :         case OBJECT_PUBLICATION_NAMESPACE:
    2159                 :         case OBJECT_PUBLICATION_REL:
    2160                 :         case OBJECT_ROLE:
    2161                 :         case OBJECT_RULE:
    2162                 :         case OBJECT_STATISTIC_EXT:
    2163                 :         case OBJECT_SUBSCRIPTION:
    2164                 :         case OBJECT_TABCONSTRAINT:
    2165                 :         case OBJECT_TRANSFORM:
    2166                 :         case OBJECT_TRIGGER:
    2167                 :         case OBJECT_TSCONFIGURATION:
    2168 EUB             :         case OBJECT_TSDICTIONARY:
    2169                 :         case OBJECT_TSPARSER:
    2170                 :         case OBJECT_TSTEMPLATE:
    2171                 :         case OBJECT_USER_MAPPING:
    2172                 :         case OBJECT_VIEW:
    2173 UIC           0 :             elog(ERROR, "unsupported object type: %d", (int) objtype);
    2174                 :     }
    2175                 : 
    2176               0 :     return "???";             /* keep compiler quiet */
    2177                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a