00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
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
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
00143
00144
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
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
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
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
00188
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
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
00207 return insert_event_trigger_tuple(stmt->trigname, stmt->eventname,
00208 evtowner, funcoid, tags);
00209 }
00210
00211
00212
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
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
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
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
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
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
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
00308 tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
00309
00310
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
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
00331 recordDependencyOnOwner(EventTriggerRelationId, trigoid, evtOwner);
00332
00333
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
00343 InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
00344
00345
00346 heap_close(tgrel, RowExclusiveLock);
00347
00348 return trigoid;
00349 }
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
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
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
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
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
00449 heap_freetuple(tup);
00450 heap_close(tgrel, RowExclusiveLock);
00451
00452 return trigoid;
00453 }
00454
00455
00456
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
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
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
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
00540 changeDependencyOnOwner(EventTriggerRelationId,
00541 HeapTupleGetOid(tup),
00542 newOwnerId);
00543
00544 InvokeObjectPostAlterHook(EventTriggerRelationId,
00545 HeapTupleGetOid(tup), 0);
00546 }
00547
00548
00549
00550
00551
00552
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
00569
00570
00571
00572 static bool
00573 filter_event_trigger(const char **tag, EventTriggerCacheItem *item)
00574 {
00575
00576
00577
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
00591 if (item->ntags != 0 && bsearch(tag, item->tag,
00592 item->ntags, sizeof(char *),
00593 pg_qsort_strcmp) == NULL)
00594 return false;
00595
00596
00597 return true;
00598 }
00599
00600
00601
00602
00603
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
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
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
00641 cachelist = EventCacheLookup(event);
00642 if (cachelist == NIL)
00643 return NIL;
00644
00645
00646 tag = CreateCommandTag(parsetree);
00647
00648
00649
00650
00651
00652
00653
00654
00655 foreach (lc, cachelist)
00656 {
00657 EventTriggerCacheItem *item = lfirst(lc);
00658
00659 if (filter_event_trigger(&tag, item))
00660 {
00661
00662 runlist = lappend_oid(runlist, item->fnoid);
00663 }
00664 }
00665
00666
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
00680
00681 void
00682 EventTriggerDDLCommandStart(Node *parsetree)
00683 {
00684 List *runlist;
00685 EventTriggerData trigdata;
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
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
00713 EventTriggerInvoke(runlist, &trigdata);
00714
00715
00716 list_free(runlist);
00717
00718
00719
00720
00721
00722 CommandCounterIncrement();
00723 }
00724
00725
00726
00727
00728 void
00729 EventTriggerDDLCommandEnd(Node *parsetree)
00730 {
00731 List *runlist;
00732 EventTriggerData trigdata;
00733
00734
00735
00736
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
00749
00750
00751 CommandCounterIncrement();
00752
00753
00754 EventTriggerInvoke(runlist, &trigdata);
00755
00756
00757 list_free(runlist);
00758 }
00759
00760
00761
00762
00763 void
00764 EventTriggerSQLDrop(Node *parsetree)
00765 {
00766 List *runlist;
00767 EventTriggerData trigdata;
00768
00769
00770
00771
00772
00773 if (!IsUnderPostmaster)
00774 return;
00775
00776
00777
00778
00779
00780
00781
00782 if (!currentEventTriggerState ||
00783 slist_is_empty(¤tEventTriggerState->SQLDropList))
00784 return;
00785
00786 runlist = EventTriggerCommonSetup(parsetree,
00787 EVT_SQLDrop, "sql_drop",
00788 &trigdata);
00789
00790
00791
00792
00793
00794 if (runlist == NIL)
00795 return;
00796
00797
00798
00799
00800
00801 CommandCounterIncrement();
00802
00803
00804
00805
00806
00807
00808
00809
00810 currentEventTriggerState->in_sql_drop = true;
00811
00812
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
00826 list_free(runlist);
00827 }
00828
00829
00830
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
00841 check_stack_depth();
00842
00843
00844
00845
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
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
00864
00865
00866
00867
00868 if (first)
00869 first = false;
00870 else
00871 CommandCounterIncrement();
00872
00873
00874 fmgr_info(fnoid, &flinfo);
00875
00876
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
00884 MemoryContextReset(context);
00885 }
00886
00887
00888 MemoryContextSwitchTo(oldcontext);
00889 MemoryContextDelete(context);
00890 }
00891
00892
00893
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
00904 return false;
00905 case OBJECT_EVENT_TRIGGER:
00906
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
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
00956 return false;
00957 case OCLASS_EVENT_TRIGGER:
00958
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
00992
00993
00994 Assert(false);
00995 break;
00996 }
00997
00998 return true;
00999 }
01000
01001
01002
01003
01004
01005
01006
01007 bool
01008 EventTriggerBeginCompleteQuery(void)
01009 {
01010 EventTriggerQueryState *state;
01011 MemoryContext cxt;
01012
01013
01014
01015
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
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047 void
01048 EventTriggerEndCompleteQuery(void)
01049 {
01050 EventTriggerQueryState *prevstate;
01051
01052 prevstate = currentEventTriggerState->previous;
01053
01054
01055 MemoryContextDelete(currentEventTriggerState->cxt);
01056
01057 currentEventTriggerState = prevstate;
01058 }
01059
01060
01061
01062
01063
01064
01065 bool
01066 trackDroppedObjectsNeeded(void)
01067 {
01068
01069 return list_length(EventCacheLookup(EVT_SQLDrop)) > 0;
01070 }
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
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
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
01115
01116
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
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
01173 obj->objidentity = getObjectIdentity(&obj->address);
01174
01175
01176 obj->objecttype = getObjectTypeDescription(&obj->address);
01177
01178 slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
01179
01180 MemoryContextSwitchTo(oldcxt);
01181 }
01182
01183
01184
01185
01186
01187
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
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
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
01220 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
01221 elog(ERROR, "return type must be a row type");
01222
01223
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
01247 values[i++] = ObjectIdGetDatum(obj->address.classId);
01248
01249
01250 values[i++] = ObjectIdGetDatum(obj->address.objectId);
01251
01252
01253 values[i++] = Int32GetDatum(obj->address.objectSubId);
01254
01255
01256 values[i++] = CStringGetTextDatum(obj->objecttype);
01257
01258
01259 if (obj->schemaname)
01260 values[i++] = CStringGetTextDatum(obj->schemaname);
01261 else
01262 nulls[i++] = true;
01263
01264
01265 if (obj->objname)
01266 values[i++] = CStringGetTextDatum(obj->objname);
01267 else
01268 nulls[i++] = true;
01269
01270
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
01280 tuplestore_donestoring(tupstore);
01281
01282 return (Datum) 0;
01283 }