Header And Logo

PostgreSQL
| The world's most advanced open source database.

event_trigger.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * event_trigger.c
00004  *    PostgreSQL EVENT TRIGGER support code.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  * IDENTIFICATION
00010  *    src/backend/commands/event_trigger.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 #include "postgres.h"
00015 
00016 #include "access/htup_details.h"
00017 #include "access/xact.h"
00018 #include "catalog/dependency.h"
00019 #include "catalog/indexing.h"
00020 #include "catalog/objectaccess.h"
00021 #include "catalog/pg_event_trigger.h"
00022 #include "catalog/pg_namespace.h"
00023 #include "catalog/pg_proc.h"
00024 #include "catalog/pg_trigger.h"
00025 #include "catalog/pg_type.h"
00026 #include "commands/dbcommands.h"
00027 #include "commands/event_trigger.h"
00028 #include "commands/trigger.h"
00029 #include "funcapi.h"
00030 #include "parser/parse_func.h"
00031 #include "pgstat.h"
00032 #include "lib/ilist.h"
00033 #include "miscadmin.h"
00034 #include "utils/acl.h"
00035 #include "utils/builtins.h"
00036 #include "utils/evtcache.h"
00037 #include "utils/fmgroids.h"
00038 #include "utils/lsyscache.h"
00039 #include "utils/memutils.h"
00040 #include "utils/rel.h"
00041 #include "utils/tqual.h"
00042 #include "utils/syscache.h"
00043 #include "tcop/utility.h"
00044 
00045 
00046 typedef struct EventTriggerQueryState
00047 {
00048     slist_head  SQLDropList;
00049     bool        in_sql_drop;
00050     MemoryContext   cxt;
00051     struct EventTriggerQueryState *previous;
00052 } EventTriggerQueryState;
00053 
00054 EventTriggerQueryState  *currentEventTriggerState = NULL;
00055 
00056 typedef struct
00057 {
00058     const char     *obtypename;
00059     bool            supported;
00060 } event_trigger_support_data;
00061 
00062 typedef enum
00063 {
00064     EVENT_TRIGGER_COMMAND_TAG_OK,
00065     EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED,
00066     EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED
00067 } event_trigger_command_tag_check_result;
00068 
00069 static event_trigger_support_data event_trigger_support[] = {
00070     { "AGGREGATE", true },
00071     { "CAST", true },
00072     { "CONSTRAINT", true },
00073     { "COLLATION", true },
00074     { "CONVERSION", true },
00075     { "DATABASE", false },
00076     { "DOMAIN", true },
00077     { "EXTENSION", true },
00078     { "EVENT TRIGGER", false },
00079     { "FOREIGN DATA WRAPPER", true },
00080     { "FOREIGN TABLE", true },
00081     { "FUNCTION", true },
00082     { "INDEX", true },
00083     { "LANGUAGE", true },
00084     { "MATERIALIZED VIEW", true },
00085     { "OPERATOR", true },
00086     { "OPERATOR CLASS", true },
00087     { "OPERATOR FAMILY", true },
00088     { "ROLE", false },
00089     { "RULE", true },
00090     { "SCHEMA", true },
00091     { "SEQUENCE", true },
00092     { "SERVER", true },
00093     { "TABLE", true },
00094     { "TABLESPACE", false},
00095     { "TRIGGER", true },
00096     { "TEXT SEARCH CONFIGURATION", true },
00097     { "TEXT SEARCH DICTIONARY", true },
00098     { "TEXT SEARCH PARSER", true },
00099     { "TEXT SEARCH TEMPLATE", true },
00100     { "TYPE", true },
00101     { "USER MAPPING", true },
00102     { "VIEW", true },
00103     { NULL, false }
00104 };
00105 
00106 /* Support for dropped objects */
00107 typedef struct SQLDropObject
00108 {
00109     ObjectAddress   address;
00110     const char     *schemaname;
00111     const char     *objname;
00112     const char     *objidentity;
00113     const char     *objecttype;
00114     slist_node      next;
00115 } SQLDropObject;
00116 
00117 static void AlterEventTriggerOwner_internal(Relation rel,
00118                                             HeapTuple tup,
00119                                             Oid newOwnerId);
00120 static event_trigger_command_tag_check_result check_ddl_tag(const char *tag);
00121 static void error_duplicate_filter_variable(const char *defname);
00122 static Datum filter_list_to_array(List *filterlist);
00123 static Oid insert_event_trigger_tuple(char *trigname, char *eventname,
00124                                       Oid evtOwner, Oid funcoid, List *tags);
00125 static void validate_ddl_tags(const char *filtervar, List *taglist);
00126 static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
00127 
00128 /*
00129  * Create an event trigger.
00130  */
00131 Oid
00132 CreateEventTrigger(CreateEventTrigStmt *stmt)
00133 {
00134     HeapTuple   tuple;
00135     Oid         funcoid;
00136     Oid         funcrettype;
00137     Oid         evtowner = GetUserId();
00138     ListCell   *lc;
00139     List       *tags = NULL;
00140 
00141     /*
00142      * It would be nice to allow database owners or even regular users to do
00143      * this, but there are obvious privilege escalation risks which would have
00144      * to somehow be plugged first.
00145      */
00146     if (!superuser())
00147         ereport(ERROR,
00148             (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00149              errmsg("permission denied to create event trigger \"%s\"",
00150                     stmt->trigname),
00151              errhint("Must be superuser to create an event trigger.")));
00152 
00153     /* Validate event name. */
00154     if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
00155         strcmp(stmt->eventname, "ddl_command_end") != 0 &&
00156         strcmp(stmt->eventname, "sql_drop") != 0)
00157         ereport(ERROR,
00158             (errcode(ERRCODE_SYNTAX_ERROR),
00159              errmsg("unrecognized event name \"%s\"",
00160                     stmt->eventname)));
00161 
00162     /* Validate filter conditions. */
00163     foreach (lc, stmt->whenclause)
00164     {
00165         DefElem    *def = (DefElem *) lfirst(lc);
00166 
00167         if (strcmp(def->defname, "tag") == 0)
00168         {
00169             if (tags != NULL)
00170                 error_duplicate_filter_variable(def->defname);
00171             tags = (List *) def->arg;
00172         }
00173         else
00174             ereport(ERROR,
00175                 (errcode(ERRCODE_SYNTAX_ERROR),
00176                  errmsg("unrecognized filter variable \"%s\"", def->defname)));
00177     }
00178 
00179     /* Validate tag list, if any. */
00180     if ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||
00181          strcmp(stmt->eventname, "ddl_command_end") == 0 ||
00182          strcmp(stmt->eventname, "sql_drop") == 0)
00183         && tags != NULL)
00184         validate_ddl_tags("tag", tags);
00185 
00186     /*
00187      * Give user a nice error message if an event trigger of the same name
00188      * already exists.
00189      */
00190     tuple = SearchSysCache1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
00191     if (HeapTupleIsValid(tuple))
00192         ereport(ERROR,
00193                 (errcode(ERRCODE_DUPLICATE_OBJECT),
00194                  errmsg("event trigger \"%s\" already exists",
00195                     stmt->trigname)));
00196 
00197     /* Find and validate the trigger function. */
00198     funcoid = LookupFuncName(stmt->funcname, 0, NULL, false);
00199     funcrettype = get_func_rettype(funcoid);
00200     if (funcrettype != EVTTRIGGEROID)
00201         ereport(ERROR,
00202                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00203                  errmsg("function \"%s\" must return type \"event_trigger\"",
00204                         NameListToString(stmt->funcname))));
00205 
00206     /* Insert catalog entries. */
00207     return insert_event_trigger_tuple(stmt->trigname, stmt->eventname,
00208                                       evtowner, funcoid, tags);
00209 }
00210 
00211 /*
00212  * Validate DDL command tags.
00213  */
00214 static void
00215 validate_ddl_tags(const char *filtervar, List *taglist)
00216 {
00217     ListCell   *lc;
00218 
00219     foreach (lc, taglist)
00220     {
00221         const char *tag = strVal(lfirst(lc));
00222         event_trigger_command_tag_check_result result;
00223 
00224         result = check_ddl_tag(tag);
00225         if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED)
00226             ereport(ERROR,
00227                     (errcode(ERRCODE_SYNTAX_ERROR),
00228                      errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
00229                         tag, filtervar)));
00230         if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED)
00231             ereport(ERROR,
00232                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00233                  /* translator: %s represents an SQL statement name */
00234                  errmsg("event triggers are not supported for %s",
00235                     tag)));
00236     }
00237 }
00238 
00239 static event_trigger_command_tag_check_result
00240 check_ddl_tag(const char *tag)
00241 {
00242     const char *obtypename;
00243     event_trigger_support_data     *etsd;
00244 
00245     /*
00246      * Handle some idiosyncratic special cases.
00247      */
00248     if (pg_strcasecmp(tag, "CREATE TABLE AS") == 0 ||
00249         pg_strcasecmp(tag, "SELECT INTO") == 0 ||
00250         pg_strcasecmp(tag, "REFRESH MATERIALIZED VIEW") == 0 ||
00251         pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 ||
00252         pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0 ||
00253         pg_strcasecmp(tag, "DROP OWNED") == 0)
00254         return EVENT_TRIGGER_COMMAND_TAG_OK;
00255 
00256     /*
00257      * Otherwise, command should be CREATE, ALTER, or DROP.
00258      */
00259     if (pg_strncasecmp(tag, "CREATE ", 7) == 0)
00260         obtypename = tag + 7;
00261     else if (pg_strncasecmp(tag, "ALTER ", 6) == 0)
00262         obtypename = tag + 6;
00263     else if (pg_strncasecmp(tag, "DROP ", 5) == 0)
00264         obtypename = tag + 5;
00265     else
00266         return EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED;
00267 
00268     /*
00269      * ...and the object type should be something recognizable.
00270      */
00271     for (etsd = event_trigger_support; etsd->obtypename != NULL; etsd++)
00272         if (pg_strcasecmp(etsd->obtypename, obtypename) == 0)
00273             break;
00274     if (etsd->obtypename == NULL)
00275         return EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED;
00276     if (!etsd->supported)
00277         return EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED;
00278     return EVENT_TRIGGER_COMMAND_TAG_OK;
00279 }
00280 
00281 /*
00282  * Complain about a duplicate filter variable.
00283  */
00284 static void
00285 error_duplicate_filter_variable(const char *defname)
00286 {
00287     ereport(ERROR,
00288             (errcode(ERRCODE_SYNTAX_ERROR),
00289              errmsg("filter variable \"%s\" specified more than once",
00290                 defname)));
00291 }
00292 
00293 /*
00294  * Insert the new pg_event_trigger row and record dependencies.
00295  */
00296 static Oid
00297 insert_event_trigger_tuple(char *trigname, char *eventname, Oid evtOwner,
00298                            Oid funcoid, List *taglist)
00299 {
00300     Relation tgrel;
00301     Oid         trigoid;
00302     HeapTuple   tuple;
00303     Datum       values[Natts_pg_trigger];
00304     bool        nulls[Natts_pg_trigger];
00305     ObjectAddress myself, referenced;
00306 
00307     /* Open pg_event_trigger. */
00308     tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
00309 
00310     /* Build the new pg_trigger tuple. */
00311     memset(nulls, false, sizeof(nulls));
00312     values[Anum_pg_event_trigger_evtname - 1] = NameGetDatum(trigname);
00313     values[Anum_pg_event_trigger_evtevent - 1] = NameGetDatum(eventname);
00314     values[Anum_pg_event_trigger_evtowner - 1] = ObjectIdGetDatum(evtOwner);
00315     values[Anum_pg_event_trigger_evtfoid - 1] = ObjectIdGetDatum(funcoid);
00316     values[Anum_pg_event_trigger_evtenabled - 1] =
00317         CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
00318     if (taglist == NIL)
00319         nulls[Anum_pg_event_trigger_evttags - 1] = true;
00320     else
00321         values[Anum_pg_event_trigger_evttags - 1] =
00322             filter_list_to_array(taglist);
00323 
00324     /* Insert heap tuple. */
00325     tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
00326     trigoid = simple_heap_insert(tgrel, tuple);
00327     CatalogUpdateIndexes(tgrel, tuple);
00328     heap_freetuple(tuple);
00329 
00330     /* Depend on owner. */
00331     recordDependencyOnOwner(EventTriggerRelationId, trigoid, evtOwner);
00332 
00333     /* Depend on event trigger function. */
00334     myself.classId = EventTriggerRelationId;
00335     myself.objectId = trigoid;
00336     myself.objectSubId = 0;
00337     referenced.classId = ProcedureRelationId;
00338     referenced.objectId = funcoid;
00339     referenced.objectSubId = 0;
00340     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00341 
00342     /* Post creation hook for new operator family */
00343     InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
00344 
00345     /* Close pg_event_trigger. */
00346     heap_close(tgrel, RowExclusiveLock);
00347 
00348     return trigoid;
00349 }
00350 
00351 /*
00352  * In the parser, a clause like WHEN tag IN ('cmd1', 'cmd2') is represented
00353  * by a DefElem whose value is a List of String nodes; in the catalog, we
00354  * store the list of strings as a text array.  This function transforms the
00355  * former representation into the latter one.
00356  *
00357  * For cleanliness, we store command tags in the catalog as text.  It's
00358  * possible (although not currently anticipated) that we might have
00359  * a case-sensitive filter variable in the future, in which case this would
00360  * need some further adjustment.
00361  */
00362 static Datum
00363 filter_list_to_array(List *filterlist)
00364 {
00365     ListCell   *lc;
00366     Datum      *data;
00367     int         i = 0,
00368                 l = list_length(filterlist);
00369 
00370     data = (Datum *) palloc(l * sizeof(Datum));
00371 
00372     foreach(lc, filterlist)
00373     {
00374         const char *value = strVal(lfirst(lc));
00375         char       *result,
00376                    *p;
00377 
00378         result = pstrdup(value);
00379         for (p = result; *p; p++)
00380             *p = pg_ascii_toupper((unsigned char) *p);
00381         data[i++] = PointerGetDatum(cstring_to_text(result));
00382         pfree(result);
00383     }
00384 
00385     return PointerGetDatum(construct_array(data, l, TEXTOID, -1, false, 'i'));
00386 }
00387 
00388 /*
00389  * Guts of event trigger deletion.
00390  */
00391 void
00392 RemoveEventTriggerById(Oid trigOid)
00393 {
00394     Relation    tgrel;
00395     HeapTuple   tup;
00396 
00397     tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
00398 
00399     tup = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(trigOid));
00400     if (!HeapTupleIsValid(tup))
00401         elog(ERROR, "cache lookup failed for event trigger %u", trigOid);
00402 
00403     simple_heap_delete(tgrel, &tup->t_self);
00404 
00405     ReleaseSysCache(tup);
00406 
00407     heap_close(tgrel, RowExclusiveLock);
00408 }
00409 
00410 /*
00411  * ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
00412  */
00413 Oid
00414 AlterEventTrigger(AlterEventTrigStmt *stmt)
00415 {
00416     Relation    tgrel;
00417     HeapTuple   tup;
00418     Oid         trigoid;
00419     Form_pg_event_trigger evtForm;
00420     char        tgenabled = stmt->tgenabled;
00421 
00422     tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
00423 
00424     tup = SearchSysCacheCopy1(EVENTTRIGGERNAME,
00425                               CStringGetDatum(stmt->trigname));
00426     if (!HeapTupleIsValid(tup))
00427         ereport(ERROR,
00428                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00429                  errmsg("event trigger \"%s\" does not exist",
00430                     stmt->trigname)));
00431 
00432     trigoid = HeapTupleGetOid(tup);
00433 
00434     if (!pg_event_trigger_ownercheck(trigoid, GetUserId()))
00435         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
00436                        stmt->trigname);
00437 
00438     /* tuple is a copy, so we can modify it below */
00439     evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
00440     evtForm->evtenabled = tgenabled;
00441 
00442     simple_heap_update(tgrel, &tup->t_self, tup);
00443     CatalogUpdateIndexes(tgrel, tup);
00444 
00445     InvokeObjectPostAlterHook(EventTriggerRelationId,
00446                               trigoid, 0);
00447 
00448     /* clean up */
00449     heap_freetuple(tup);
00450     heap_close(tgrel, RowExclusiveLock);
00451 
00452     return trigoid;
00453 }
00454 
00455 /*
00456  * Change event trigger's owner -- by name
00457  */
00458 Oid
00459 AlterEventTriggerOwner(const char *name, Oid newOwnerId)
00460 {
00461     Oid         evtOid;
00462     HeapTuple   tup;
00463     Relation    rel;
00464 
00465     rel = heap_open(EventTriggerRelationId, RowExclusiveLock);
00466 
00467     tup = SearchSysCacheCopy1(EVENTTRIGGERNAME, CStringGetDatum(name));
00468 
00469     if (!HeapTupleIsValid(tup))
00470         ereport(ERROR,
00471                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00472                  errmsg("event trigger \"%s\" does not exist", name)));
00473 
00474     evtOid = HeapTupleGetOid(tup);
00475 
00476     AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
00477 
00478     heap_freetuple(tup);
00479 
00480     heap_close(rel, RowExclusiveLock);
00481 
00482     return evtOid;
00483 }
00484 
00485 /*
00486  * Change extension owner, by OID
00487  */
00488 void
00489 AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
00490 {
00491     HeapTuple   tup;
00492     Relation    rel;
00493 
00494     rel = heap_open(EventTriggerRelationId, RowExclusiveLock);
00495 
00496     tup = SearchSysCacheCopy1(EVENTTRIGGEROID, ObjectIdGetDatum(trigOid));
00497 
00498     if (!HeapTupleIsValid(tup))
00499         ereport(ERROR,
00500                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00501           errmsg("event trigger with OID %u does not exist", trigOid)));
00502 
00503     AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
00504 
00505     heap_freetuple(tup);
00506 
00507     heap_close(rel, RowExclusiveLock);
00508 }
00509 
00510 /*
00511  * Internal workhorse for changing an event trigger's owner
00512  */
00513 static void
00514 AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
00515 {
00516     Form_pg_event_trigger form;
00517 
00518     form = (Form_pg_event_trigger) GETSTRUCT(tup);
00519 
00520     if (form->evtowner == newOwnerId)
00521         return;
00522 
00523     if (!pg_event_trigger_ownercheck(HeapTupleGetOid(tup), GetUserId()))
00524         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
00525                        NameStr(form->evtname));
00526 
00527     /* New owner must be a superuser */
00528     if (!superuser_arg(newOwnerId))
00529         ereport(ERROR,
00530                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00531                  errmsg("permission denied to change owner of event trigger \"%s\"",
00532                     NameStr(form->evtname)),
00533                  errhint("The owner of an event trigger must be a superuser.")));
00534 
00535     form->evtowner = newOwnerId;
00536     simple_heap_update(rel, &tup->t_self, tup);
00537     CatalogUpdateIndexes(rel, tup);
00538 
00539     /* Update owner dependency reference */
00540     changeDependencyOnOwner(EventTriggerRelationId,
00541                             HeapTupleGetOid(tup),
00542                             newOwnerId);
00543 
00544     InvokeObjectPostAlterHook(EventTriggerRelationId,
00545                               HeapTupleGetOid(tup), 0);
00546 }
00547 
00548 /*
00549  * get_event_trigger_oid - Look up an event trigger by name to find its OID.
00550  *
00551  * If missing_ok is false, throw an error if trigger not found.  If
00552  * true, just return InvalidOid.
00553  */
00554 Oid
00555 get_event_trigger_oid(const char *trigname, bool missing_ok)
00556 {
00557     Oid         oid;
00558 
00559     oid = GetSysCacheOid1(EVENTTRIGGERNAME, CStringGetDatum(trigname));
00560     if (!OidIsValid(oid) && !missing_ok)
00561         ereport(ERROR,
00562                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00563                  errmsg("event trigger \"%s\" does not exist", trigname)));
00564     return oid;
00565 }
00566 
00567 /*
00568  * Return true when we want to fire given Event Trigger and false otherwise,
00569  * filtering on the session replication role and the event trigger registered
00570  * tags matching.
00571  */
00572 static bool
00573 filter_event_trigger(const char **tag, EventTriggerCacheItem  *item)
00574 {
00575     /*
00576      * Filter by session replication role, knowing that we never see disabled
00577      * items down here.
00578      */
00579     if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
00580     {
00581         if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
00582             return false;
00583     }
00584     else
00585     {
00586         if (item->enabled == TRIGGER_FIRES_ON_REPLICA)
00587             return false;
00588     }
00589 
00590     /* Filter by tags, if any were specified. */
00591     if (item->ntags != 0 && bsearch(tag, item->tag,
00592                                     item->ntags, sizeof(char *),
00593                                     pg_qsort_strcmp) == NULL)
00594         return false;
00595 
00596     /* if we reach that point, we're not filtering out this item */
00597     return true;
00598 }
00599 
00600 /*
00601  * Setup for running triggers for the given event.  Return value is an OID list
00602  * of functions to run; if there are any, trigdata is filled with an
00603  * appropriate EventTriggerData for them to receive.
00604  */
00605 static List *
00606 EventTriggerCommonSetup(Node *parsetree,
00607                         EventTriggerEvent event, const char *eventstr,
00608                         EventTriggerData *trigdata)
00609 {
00610     const char *tag;
00611     List       *cachelist;
00612     ListCell   *lc;
00613     List       *runlist = NIL;
00614 
00615     /*
00616      * We want the list of command tags for which this procedure is actually
00617      * invoked to match up exactly with the list that CREATE EVENT TRIGGER
00618      * accepts.  This debugging cross-check will throw an error if this
00619      * function is invoked for a command tag that CREATE EVENT TRIGGER won't
00620      * accept.  (Unfortunately, there doesn't seem to be any simple, automated
00621      * way to verify that CREATE EVENT TRIGGER doesn't accept extra stuff that
00622      * never reaches this control point.)
00623      *
00624      * If this cross-check fails for you, you probably need to either adjust
00625      * standard_ProcessUtility() not to invoke event triggers for the command
00626      * type in question, or you need to adjust check_ddl_tag to accept the
00627      * relevant command tag.
00628      */
00629 #ifdef USE_ASSERT_CHECKING
00630     if (assert_enabled)
00631     {
00632         const char *dbgtag;
00633 
00634         dbgtag = CreateCommandTag(parsetree);
00635         if (check_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
00636             elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
00637     }
00638 #endif
00639 
00640     /* Use cache to find triggers for this event; fast exit if none. */
00641     cachelist = EventCacheLookup(event);
00642     if (cachelist == NIL)
00643         return NIL;
00644 
00645     /* Get the command tag. */
00646     tag = CreateCommandTag(parsetree);
00647 
00648     /*
00649      * Filter list of event triggers by command tag, and copy them into
00650      * our memory context.  Once we start running the command trigers, or
00651      * indeed once we do anything at all that touches the catalogs, an
00652      * invalidation might leave cachelist pointing at garbage, so we must
00653      * do this before we can do much else.
00654      */
00655     foreach (lc, cachelist)
00656     {
00657         EventTriggerCacheItem  *item = lfirst(lc);
00658 
00659         if (filter_event_trigger(&tag, item))
00660         {
00661             /* We must plan to fire this trigger. */
00662             runlist = lappend_oid(runlist, item->fnoid);
00663         }
00664     }
00665 
00666     /* don't spend any more time on this if no functions to run */
00667     if (runlist == NIL)
00668         return NIL;
00669 
00670     trigdata->type = T_EventTriggerData;
00671     trigdata->event = eventstr;
00672     trigdata->parsetree = parsetree;
00673     trigdata->tag = tag;
00674 
00675     return runlist;
00676 }
00677 
00678 /*
00679  * Fire ddl_command_start triggers.
00680  */
00681 void
00682 EventTriggerDDLCommandStart(Node *parsetree)
00683 {
00684     List       *runlist;
00685     EventTriggerData    trigdata;
00686 
00687     /*
00688      * Event Triggers are completely disabled in standalone mode.  There are
00689      * (at least) two reasons for this:
00690      *
00691      * 1. A sufficiently broken event trigger might not only render the
00692      * database unusable, but prevent disabling itself to fix the situation.
00693      * In this scenario, restarting in standalone mode provides an escape
00694      * hatch.
00695      *
00696      * 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
00697      * therefore will malfunction if pg_event_trigger's indexes are damaged.
00698      * To allow recovery from a damaged index, we need some operating mode
00699      * wherein event triggers are disabled.  (Or we could implement
00700      * heapscan-and-sort logic for that case, but having disaster recovery
00701      * scenarios depend on code that's otherwise untested isn't appetizing.)
00702      */
00703     if (!IsUnderPostmaster)
00704         return;
00705 
00706     runlist = EventTriggerCommonSetup(parsetree,
00707                                       EVT_DDLCommandStart, "ddl_command_start",
00708                                       &trigdata);
00709     if (runlist == NIL)
00710         return;
00711 
00712     /* Run the triggers. */
00713     EventTriggerInvoke(runlist, &trigdata);
00714 
00715     /* Cleanup. */
00716     list_free(runlist);
00717 
00718     /*
00719      * Make sure anything the event triggers did will be visible to
00720      * the main command.
00721      */
00722     CommandCounterIncrement();
00723 }
00724 
00725 /*
00726  * Fire ddl_command_end triggers.
00727  */
00728 void
00729 EventTriggerDDLCommandEnd(Node *parsetree)
00730 {
00731     List       *runlist;
00732     EventTriggerData    trigdata;
00733 
00734     /*
00735      * See EventTriggerDDLCommandStart for a discussion about why event
00736      * triggers are disabled in single user mode.
00737      */
00738     if (!IsUnderPostmaster)
00739         return;
00740 
00741     runlist = EventTriggerCommonSetup(parsetree,
00742                                       EVT_DDLCommandEnd, "ddl_command_end",
00743                                       &trigdata);
00744     if (runlist == NIL)
00745         return;
00746 
00747     /*
00748      * Make sure anything the main command did will be visible to the
00749      * event triggers.
00750      */
00751     CommandCounterIncrement();
00752 
00753     /* Run the triggers. */
00754     EventTriggerInvoke(runlist, &trigdata);
00755 
00756     /* Cleanup. */
00757     list_free(runlist);
00758 }
00759 
00760 /*
00761  * Fire sql_drop triggers.
00762  */
00763 void
00764 EventTriggerSQLDrop(Node *parsetree)
00765 {
00766     List       *runlist;
00767     EventTriggerData    trigdata;
00768 
00769     /*
00770      * See EventTriggerDDLCommandStart for a discussion about why event
00771      * triggers are disabled in single user mode.
00772      */
00773     if (!IsUnderPostmaster)
00774         return;
00775 
00776     /*
00777      * Use current state to determine whether this event fires at all.  If there
00778      * are no triggers for the sql_drop event, then we don't have anything to do
00779      * here.  Note that dropped object collection is disabled if this is the case,
00780      * so even if we were to try to run, the list would be empty.
00781      */
00782     if (!currentEventTriggerState ||
00783         slist_is_empty(&currentEventTriggerState->SQLDropList))
00784         return;
00785 
00786     runlist = EventTriggerCommonSetup(parsetree,
00787                                       EVT_SQLDrop, "sql_drop",
00788                                       &trigdata);
00789     /*
00790      * Nothing to do if run list is empty.  Note this shouldn't happen, because
00791      * if there are no sql_drop events, then objects-to-drop wouldn't have been
00792      * collected in the first place and we would have quitted above.
00793      */
00794     if (runlist == NIL)
00795         return;
00796 
00797     /*
00798      * Make sure anything the main command did will be visible to the
00799      * event triggers.
00800      */
00801     CommandCounterIncrement();
00802 
00803     /*
00804      * Make sure pg_event_trigger_dropped_objects only works when running these
00805      * triggers.  Use PG_TRY to ensure in_sql_drop is reset even when one
00806      * trigger fails.  (This is perhaps not necessary, as the currentState
00807      * variable will be removed shortly by our caller, but it seems better to
00808      * play safe.)
00809      */
00810     currentEventTriggerState->in_sql_drop = true;
00811 
00812     /* Run the triggers. */
00813     PG_TRY();
00814     {
00815         EventTriggerInvoke(runlist, &trigdata);
00816     }
00817     PG_CATCH();
00818     {
00819         currentEventTriggerState->in_sql_drop = false;
00820         PG_RE_THROW();
00821     }
00822     PG_END_TRY();
00823     currentEventTriggerState->in_sql_drop = false;
00824 
00825     /* Cleanup. */
00826     list_free(runlist);
00827 }
00828 
00829 /*
00830  * Invoke each event trigger in a list of event triggers.
00831  */
00832 static void
00833 EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
00834 {
00835     MemoryContext   context;
00836     MemoryContext   oldcontext;
00837     ListCell       *lc;
00838     bool            first = true;
00839 
00840     /* Guard against stack overflow due to recursive event trigger */
00841     check_stack_depth();
00842 
00843     /*
00844      * Let's evaluate event triggers in their own memory context, so
00845      * that any leaks get cleaned up promptly.
00846      */
00847     context = AllocSetContextCreate(CurrentMemoryContext,
00848                                     "event trigger context",
00849                                     ALLOCSET_DEFAULT_MINSIZE,
00850                                     ALLOCSET_DEFAULT_INITSIZE,
00851                                     ALLOCSET_DEFAULT_MAXSIZE);
00852     oldcontext = MemoryContextSwitchTo(context);
00853 
00854     /* Call each event trigger. */
00855     foreach (lc, fn_oid_list)
00856     {
00857         Oid     fnoid = lfirst_oid(lc);
00858         FmgrInfo        flinfo;
00859         FunctionCallInfoData fcinfo;
00860         PgStat_FunctionCallUsage fcusage;
00861 
00862         /*
00863          * We want each event trigger to be able to see the results of
00864          * the previous event trigger's action.  Caller is responsible
00865          * for any command-counter increment that is needed between the
00866          * event trigger and anything else in the transaction.
00867          */
00868         if (first)
00869             first = false;
00870         else
00871             CommandCounterIncrement();
00872 
00873         /* Look up the function */
00874         fmgr_info(fnoid, &flinfo);
00875 
00876         /* Call the function, passing no arguments but setting a context. */
00877         InitFunctionCallInfoData(fcinfo, &flinfo, 0,
00878                                  InvalidOid, (Node *) trigdata, NULL);
00879         pgstat_init_function_usage(&fcinfo, &fcusage);
00880         FunctionCallInvoke(&fcinfo);
00881         pgstat_end_function_usage(&fcusage, true);
00882 
00883         /* Reclaim memory. */
00884         MemoryContextReset(context);
00885     }
00886 
00887     /* Restore old memory context and delete the temporary one. */
00888     MemoryContextSwitchTo(oldcontext);
00889     MemoryContextDelete(context);
00890 }
00891 
00892 /*
00893  * Do event triggers support this object type?
00894  */
00895 bool
00896 EventTriggerSupportsObjectType(ObjectType obtype)
00897 {
00898     switch (obtype)
00899     {
00900         case OBJECT_DATABASE:
00901         case OBJECT_TABLESPACE:
00902         case OBJECT_ROLE:
00903             /* no support for global objects */
00904             return false;
00905         case OBJECT_EVENT_TRIGGER:
00906             /* no support for event triggers on event triggers */
00907             return false;
00908         case OBJECT_AGGREGATE:
00909         case OBJECT_ATTRIBUTE:
00910         case OBJECT_CAST:
00911         case OBJECT_COLUMN:
00912         case OBJECT_CONSTRAINT:
00913         case OBJECT_COLLATION:
00914         case OBJECT_CONVERSION:
00915         case OBJECT_DOMAIN:
00916         case OBJECT_EXTENSION:
00917         case OBJECT_FDW:
00918         case OBJECT_FOREIGN_SERVER:
00919         case OBJECT_FOREIGN_TABLE:
00920         case OBJECT_FUNCTION:
00921         case OBJECT_INDEX:
00922         case OBJECT_LANGUAGE:
00923         case OBJECT_LARGEOBJECT:
00924         case OBJECT_MATVIEW:
00925         case OBJECT_OPCLASS:
00926         case OBJECT_OPERATOR:
00927         case OBJECT_OPFAMILY:
00928         case OBJECT_RULE:
00929         case OBJECT_SCHEMA:
00930         case OBJECT_SEQUENCE:
00931         case OBJECT_TABLE:
00932         case OBJECT_TRIGGER:
00933         case OBJECT_TSCONFIGURATION:
00934         case OBJECT_TSDICTIONARY:
00935         case OBJECT_TSPARSER:
00936         case OBJECT_TSTEMPLATE:
00937         case OBJECT_TYPE:
00938         case OBJECT_VIEW:
00939             return true;
00940     }
00941     return true;
00942 }
00943 
00944 /*
00945  * Do event triggers support this object class?
00946  */
00947 bool
00948 EventTriggerSupportsObjectClass(ObjectClass objclass)
00949 {
00950     switch (objclass)
00951     {
00952         case OCLASS_DATABASE:
00953         case OCLASS_TBLSPACE:
00954         case OCLASS_ROLE:
00955             /* no support for global objects */
00956             return false;
00957         case OCLASS_EVENT_TRIGGER:
00958             /* no support for event triggers on event triggers */
00959             return false;
00960         case OCLASS_CLASS:
00961         case OCLASS_PROC:
00962         case OCLASS_TYPE:
00963         case OCLASS_CAST:
00964         case OCLASS_COLLATION:
00965         case OCLASS_CONSTRAINT:
00966         case OCLASS_CONVERSION:
00967         case OCLASS_DEFAULT:
00968         case OCLASS_LANGUAGE:
00969         case OCLASS_LARGEOBJECT:
00970         case OCLASS_OPERATOR:
00971         case OCLASS_OPCLASS:
00972         case OCLASS_OPFAMILY:
00973         case OCLASS_AMOP:
00974         case OCLASS_AMPROC:
00975         case OCLASS_REWRITE:
00976         case OCLASS_TRIGGER:
00977         case OCLASS_SCHEMA:
00978         case OCLASS_TSPARSER:
00979         case OCLASS_TSDICT:
00980         case OCLASS_TSTEMPLATE:
00981         case OCLASS_TSCONFIG:
00982         case OCLASS_FDW:
00983         case OCLASS_FOREIGN_SERVER:
00984         case OCLASS_USER_MAPPING:
00985         case OCLASS_DEFACL:
00986         case OCLASS_EXTENSION:
00987             return true;
00988 
00989         case MAX_OCLASS:
00990             /*
00991              * This shouldn't ever happen, but we keep the case to avoid a
00992              * compiler warning without a "default" clause in the switch.
00993              */
00994             Assert(false);
00995             break;
00996     }
00997 
00998     return true;
00999 }
01000 
01001 /*
01002  * Prepare event trigger state for a new complete query to run, if necessary;
01003  * returns whether this was done.  If it was, EventTriggerEndCompleteQuery must
01004  * be called when the query is done, regardless of whether it succeeds or fails
01005  * -- so use of a PG_TRY block is mandatory.
01006  */
01007 bool
01008 EventTriggerBeginCompleteQuery(void)
01009 {
01010     EventTriggerQueryState *state;
01011     MemoryContext   cxt;
01012 
01013     /*
01014      * Currently, sql_drop events are the only reason to have event trigger
01015      * state at all; so if there are none, don't install one.
01016      */
01017     if (!trackDroppedObjectsNeeded())
01018         return false;
01019 
01020     cxt = AllocSetContextCreate(TopMemoryContext,
01021                                 "event trigger state",
01022                                 ALLOCSET_DEFAULT_MINSIZE,
01023                                 ALLOCSET_DEFAULT_INITSIZE,
01024                                 ALLOCSET_DEFAULT_MAXSIZE);
01025     state = MemoryContextAlloc(cxt, sizeof(EventTriggerQueryState));
01026     state->cxt = cxt;
01027     slist_init(&(state->SQLDropList));
01028     state->in_sql_drop = false;
01029 
01030     state->previous = currentEventTriggerState;
01031     currentEventTriggerState = state;
01032 
01033     return true;
01034 }
01035 
01036 /*
01037  * Query completed (or errored out) -- clean up local state, return to previous
01038  * one.
01039  *
01040  * Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
01041  * returned false previously.
01042  *
01043  * Note: this might be called in the PG_CATCH block of a failing transaction,
01044  * so be wary of running anything unnecessary.  (In particular, it's probably
01045  * unwise to try to allocate memory.)
01046  */
01047 void
01048 EventTriggerEndCompleteQuery(void)
01049 {
01050     EventTriggerQueryState *prevstate;
01051 
01052     prevstate = currentEventTriggerState->previous;
01053 
01054     /* this avoids the need for retail pfree of SQLDropList items: */
01055     MemoryContextDelete(currentEventTriggerState->cxt);
01056 
01057     currentEventTriggerState = prevstate;
01058 }
01059 
01060 /*
01061  * Do we need to keep close track of objects being dropped?
01062  *
01063  * This is useful because there is a cost to running with them enabled.
01064  */
01065 bool
01066 trackDroppedObjectsNeeded(void)
01067 {
01068     /* true if any sql_drop event trigger exists */
01069     return list_length(EventCacheLookup(EVT_SQLDrop)) > 0;
01070 }
01071 
01072 /*
01073  * Support for dropped objects information on event trigger functions.
01074  *
01075  * We keep the list of objects dropped by the current command in current
01076  * state's SQLDropList (comprising SQLDropObject items).  Each time a new
01077  * command is to start, a clean EventTriggerQueryState is created; commands
01078  * that drop objects do the dependency.c dance to drop objects, which
01079  * populates the current state's SQLDropList; when the event triggers are
01080  * invoked they can consume the list via pg_event_trigger_dropped_objects().
01081  * When the command finishes, the EventTriggerQueryState is cleared, and
01082  * the one from the previous command is restored (when no command is in
01083  * execution, the current state is NULL).
01084  *
01085  * All this lets us support the case that an event trigger function drops
01086  * objects "reentrantly".
01087  */
01088 
01089 /*
01090  * Register one object as being dropped by the current command.
01091  */
01092 void
01093 EventTriggerSQLDropAddObject(ObjectAddress *object)
01094 {
01095     SQLDropObject  *obj;
01096     MemoryContext   oldcxt;
01097 
01098     if (!currentEventTriggerState)
01099         return;
01100 
01101     Assert(EventTriggerSupportsObjectClass(getObjectClass(object)));
01102 
01103     /* don't report temp schemas */
01104     if (object->classId == NamespaceRelationId &&
01105         isAnyTempNamespace(object->objectId))
01106         return;
01107 
01108     oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
01109 
01110     obj = palloc0(sizeof(SQLDropObject));
01111     obj->address = *object;
01112 
01113     /*
01114      * Obtain schema names from the object's catalog tuple, if one exists;
01115      * this lets us skip objects in temp schemas.  We trust that ObjectProperty
01116      * contains all object classes that can be schema-qualified.
01117      */
01118     if (is_objectclass_supported(object->classId))
01119     {
01120         Relation    catalog;
01121         HeapTuple   tuple;
01122 
01123         catalog = heap_open(obj->address.classId, AccessShareLock);
01124         tuple = get_catalog_object_by_oid(catalog, obj->address.objectId);
01125 
01126         if (tuple)
01127         {
01128             AttrNumber  attnum;
01129             Datum       datum;
01130             bool        isnull;
01131 
01132             attnum = get_object_attnum_namespace(obj->address.classId);
01133             if (attnum != InvalidAttrNumber)
01134             {
01135                 datum = heap_getattr(tuple, attnum,
01136                                      RelationGetDescr(catalog), &isnull);
01137                 if (!isnull)
01138                 {
01139                     Oid     namespaceId;
01140 
01141                     namespaceId = DatumGetObjectId(datum);
01142                     /* Don't report objects in temp namespaces */
01143                     if (isAnyTempNamespace(namespaceId))
01144                     {
01145                         pfree(obj);
01146                         heap_close(catalog, AccessShareLock);
01147                         MemoryContextSwitchTo(oldcxt);
01148                         return;
01149                     }
01150 
01151                     obj->schemaname = get_namespace_name(namespaceId);
01152                 }
01153             }
01154 
01155             if (get_object_namensp_unique(obj->address.classId) &&
01156                 obj->address.objectSubId == 0)
01157             {
01158                 attnum = get_object_attnum_name(obj->address.classId);
01159                 if (attnum != InvalidAttrNumber)
01160                 {
01161                     datum = heap_getattr(tuple, attnum,
01162                                          RelationGetDescr(catalog), &isnull);
01163                     if (!isnull)
01164                         obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
01165                 }
01166             }
01167         }
01168 
01169         heap_close(catalog, AccessShareLock);
01170     }
01171 
01172     /* object identity */
01173     obj->objidentity = getObjectIdentity(&obj->address);
01174 
01175     /* and object type, too */
01176     obj->objecttype = getObjectTypeDescription(&obj->address);
01177 
01178     slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
01179 
01180     MemoryContextSwitchTo(oldcxt);
01181 }
01182 
01183 /*
01184  * pg_event_trigger_dropped_objects
01185  *
01186  * Make the list of dropped objects available to the user function run by the
01187  * Event Trigger.
01188  */
01189 Datum
01190 pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
01191 {
01192     ReturnSetInfo      *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
01193     TupleDesc           tupdesc;
01194     Tuplestorestate    *tupstore;
01195     MemoryContext       per_query_ctx;
01196     MemoryContext       oldcontext;
01197     slist_iter          iter;
01198 
01199     /*
01200      * Protect this function from being called out of context
01201      */
01202     if (!currentEventTriggerState ||
01203         !currentEventTriggerState->in_sql_drop)
01204         ereport(ERROR,
01205                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01206                  errmsg("%s can only be called in a sql_drop event trigger function",
01207                         "pg_event_trigger_dropped_objects()")));
01208 
01209     /* check to see if caller supports us returning a tuplestore */
01210     if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
01211         ereport(ERROR,
01212                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01213                  errmsg("set-valued function called in context that cannot accept a set")));
01214     if (!(rsinfo->allowedModes & SFRM_Materialize))
01215         ereport(ERROR,
01216                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01217                  errmsg("materialize mode required, but it is not allowed in this context")));
01218 
01219     /* Build a tuple descriptor for our result type */
01220     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
01221         elog(ERROR, "return type must be a row type");
01222 
01223     /* Build tuplestore to hold the result rows */
01224     per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
01225     oldcontext = MemoryContextSwitchTo(per_query_ctx);
01226 
01227     tupstore = tuplestore_begin_heap(true, false, work_mem);
01228     rsinfo->returnMode = SFRM_Materialize;
01229     rsinfo->setResult = tupstore;
01230     rsinfo->setDesc = tupdesc;
01231 
01232     MemoryContextSwitchTo(oldcontext);
01233 
01234     slist_foreach(iter, &(currentEventTriggerState->SQLDropList))
01235     {
01236         SQLDropObject *obj;
01237         int         i = 0;
01238         Datum       values[7];
01239         bool        nulls[7];
01240 
01241         obj = slist_container(SQLDropObject, next, iter.cur);
01242 
01243         MemSet(values, 0, sizeof(values));
01244         MemSet(nulls, 0, sizeof(nulls));
01245 
01246         /* classid */
01247         values[i++] = ObjectIdGetDatum(obj->address.classId);
01248 
01249         /* objid */
01250         values[i++] = ObjectIdGetDatum(obj->address.objectId);
01251 
01252         /* objsubid */
01253         values[i++] = Int32GetDatum(obj->address.objectSubId);
01254 
01255         /* object_type */
01256         values[i++] = CStringGetTextDatum(obj->objecttype);
01257 
01258         /* schema_name */
01259         if (obj->schemaname)
01260             values[i++] = CStringGetTextDatum(obj->schemaname);
01261         else
01262             nulls[i++] = true;
01263 
01264         /* object_name */
01265         if (obj->objname)
01266             values[i++] = CStringGetTextDatum(obj->objname);
01267         else
01268             nulls[i++] = true;
01269 
01270         /* object_identity */
01271         if (obj->objidentity)
01272             values[i++] = CStringGetTextDatum(obj->objidentity);
01273         else
01274             nulls[i++] = true;
01275 
01276         tuplestore_putvalues(tupstore, tupdesc, values, nulls);
01277     }
01278 
01279     /* clean up and return the tuplestore */
01280     tuplestore_donestoring(tupstore);
01281 
01282     return (Datum) 0;
01283 }