LCOV - code coverage report
Current view: top level - src/backend/commands - event_trigger.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 598 713 83.9 %
Date: 2020-06-01 07:06:57 Functions: 41 43 95.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13