00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres.h"
00015
00016 #include "access/genam.h"
00017 #include "access/heapam.h"
00018 #include "access/sysattr.h"
00019 #include "access/htup_details.h"
00020 #include "access/xact.h"
00021 #include "catalog/catalog.h"
00022 #include "catalog/dependency.h"
00023 #include "catalog/indexing.h"
00024 #include "catalog/objectaccess.h"
00025 #include "catalog/pg_constraint.h"
00026 #include "catalog/pg_proc.h"
00027 #include "catalog/pg_trigger.h"
00028 #include "catalog/pg_type.h"
00029 #include "commands/dbcommands.h"
00030 #include "commands/defrem.h"
00031 #include "commands/trigger.h"
00032 #include "executor/executor.h"
00033 #include "miscadmin.h"
00034 #include "nodes/bitmapset.h"
00035 #include "nodes/makefuncs.h"
00036 #include "optimizer/clauses.h"
00037 #include "optimizer/var.h"
00038 #include "parser/parse_clause.h"
00039 #include "parser/parse_collate.h"
00040 #include "parser/parse_func.h"
00041 #include "parser/parse_relation.h"
00042 #include "parser/parsetree.h"
00043 #include "pgstat.h"
00044 #include "rewrite/rewriteManip.h"
00045 #include "storage/bufmgr.h"
00046 #include "tcop/utility.h"
00047 #include "utils/acl.h"
00048 #include "utils/builtins.h"
00049 #include "utils/bytea.h"
00050 #include "utils/fmgroids.h"
00051 #include "utils/inval.h"
00052 #include "utils/lsyscache.h"
00053 #include "utils/memutils.h"
00054 #include "utils/rel.h"
00055 #include "utils/snapmgr.h"
00056 #include "utils/syscache.h"
00057 #include "utils/tqual.h"
00058
00059
00060
00061 int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
00062
00063
00064 static int MyTriggerDepth = 0;
00065
00066 #define GetModifiedColumns(relinfo, estate) \
00067 (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->modifiedCols)
00068
00069
00070 static void ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid);
00071 static void SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger);
00072 static HeapTuple GetTupleForTrigger(EState *estate,
00073 EPQState *epqstate,
00074 ResultRelInfo *relinfo,
00075 ItemPointer tid,
00076 LockTupleMode lockmode,
00077 TupleTableSlot **newSlot);
00078 static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
00079 Trigger *trigger, TriggerEvent event,
00080 Bitmapset *modifiedCols,
00081 HeapTuple oldtup, HeapTuple newtup);
00082 static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
00083 int tgindx,
00084 FmgrInfo *finfo,
00085 Instrumentation *instr,
00086 MemoryContext per_tuple_context);
00087 static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
00088 int event, bool row_trigger,
00089 HeapTuple oldtup, HeapTuple newtup,
00090 List *recheckIndexes, Bitmapset *modifiedCols);
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 Oid
00120 CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
00121 Oid constraintOid, Oid indexOid,
00122 bool isInternal)
00123 {
00124 int16 tgtype;
00125 int ncolumns;
00126 int16 *columns;
00127 int2vector *tgattr;
00128 Node *whenClause;
00129 List *whenRtable;
00130 char *qual;
00131 Datum values[Natts_pg_trigger];
00132 bool nulls[Natts_pg_trigger];
00133 Relation rel;
00134 AclResult aclresult;
00135 Relation tgrel;
00136 SysScanDesc tgscan;
00137 ScanKeyData key;
00138 Relation pgrel;
00139 HeapTuple tuple;
00140 Oid fargtypes[1];
00141 Oid funcoid;
00142 Oid funcrettype;
00143 Oid trigoid;
00144 char internaltrigname[NAMEDATALEN];
00145 char *trigname;
00146 Oid constrrelid = InvalidOid;
00147 ObjectAddress myself,
00148 referenced;
00149
00150 rel = heap_openrv(stmt->relation, AccessExclusiveLock);
00151
00152
00153
00154
00155
00156 if (rel->rd_rel->relkind == RELKIND_RELATION)
00157 {
00158
00159 if (stmt->timing != TRIGGER_TYPE_BEFORE &&
00160 stmt->timing != TRIGGER_TYPE_AFTER)
00161 ereport(ERROR,
00162 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00163 errmsg("\"%s\" is a table",
00164 RelationGetRelationName(rel)),
00165 errdetail("Tables cannot have INSTEAD OF triggers.")));
00166 }
00167 else if (rel->rd_rel->relkind == RELKIND_VIEW)
00168 {
00169
00170
00171
00172
00173 if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
00174 ereport(ERROR,
00175 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00176 errmsg("\"%s\" is a view",
00177 RelationGetRelationName(rel)),
00178 errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
00179
00180 if (TRIGGER_FOR_TRUNCATE(stmt->events))
00181 ereport(ERROR,
00182 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00183 errmsg("\"%s\" is a view",
00184 RelationGetRelationName(rel)),
00185 errdetail("Views cannot have TRUNCATE triggers.")));
00186 }
00187 else
00188 ereport(ERROR,
00189 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00190 errmsg("\"%s\" is not a table or view",
00191 RelationGetRelationName(rel))));
00192
00193 if (!allowSystemTableMods && IsSystemRelation(rel))
00194 ereport(ERROR,
00195 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00196 errmsg("permission denied: \"%s\" is a system catalog",
00197 RelationGetRelationName(rel))));
00198
00199 if (stmt->isconstraint && stmt->constrrel != NULL)
00200 {
00201
00202
00203
00204
00205
00206
00207
00208 constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock, false);
00209 }
00210
00211
00212 if (!isInternal)
00213 {
00214 aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
00215 ACL_TRIGGER);
00216 if (aclresult != ACLCHECK_OK)
00217 aclcheck_error(aclresult, ACL_KIND_CLASS,
00218 RelationGetRelationName(rel));
00219
00220 if (OidIsValid(constrrelid))
00221 {
00222 aclresult = pg_class_aclcheck(constrrelid, GetUserId(),
00223 ACL_TRIGGER);
00224 if (aclresult != ACLCHECK_OK)
00225 aclcheck_error(aclresult, ACL_KIND_CLASS,
00226 get_rel_name(constrrelid));
00227 }
00228 }
00229
00230
00231 TRIGGER_CLEAR_TYPE(tgtype);
00232 if (stmt->row)
00233 TRIGGER_SETT_ROW(tgtype);
00234 tgtype |= stmt->timing;
00235 tgtype |= stmt->events;
00236
00237
00238 if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
00239 ereport(ERROR,
00240 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00241 errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
00242
00243
00244 if (TRIGGER_FOR_INSTEAD(tgtype))
00245 {
00246 if (!TRIGGER_FOR_ROW(tgtype))
00247 ereport(ERROR,
00248 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00249 errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
00250 if (stmt->whenClause)
00251 ereport(ERROR,
00252 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00253 errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
00254 if (stmt->columns != NIL)
00255 ereport(ERROR,
00256 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00257 errmsg("INSTEAD OF triggers cannot have column lists")));
00258 }
00259
00260
00261
00262
00263 if (stmt->whenClause)
00264 {
00265 ParseState *pstate;
00266 RangeTblEntry *rte;
00267 List *varList;
00268 ListCell *lc;
00269
00270
00271 pstate = make_parsestate(NULL);
00272 pstate->p_sourcetext = queryString;
00273
00274
00275
00276
00277
00278
00279 rte = addRangeTableEntryForRelation(pstate, rel,
00280 makeAlias("old", NIL),
00281 false, false);
00282 addRTEtoQuery(pstate, rte, false, true, true);
00283 rte = addRangeTableEntryForRelation(pstate, rel,
00284 makeAlias("new", NIL),
00285 false, false);
00286 addRTEtoQuery(pstate, rte, false, true, true);
00287
00288
00289 whenClause = transformWhereClause(pstate,
00290 copyObject(stmt->whenClause),
00291 EXPR_KIND_TRIGGER_WHEN,
00292 "WHEN");
00293
00294 assign_expr_collations(pstate, whenClause);
00295
00296
00297
00298
00299
00300
00301
00302
00303 varList = pull_var_clause(whenClause,
00304 PVC_REJECT_AGGREGATES,
00305 PVC_REJECT_PLACEHOLDERS);
00306 foreach(lc, varList)
00307 {
00308 Var *var = (Var *) lfirst(lc);
00309
00310 switch (var->varno)
00311 {
00312 case PRS2_OLD_VARNO:
00313 if (!TRIGGER_FOR_ROW(tgtype))
00314 ereport(ERROR,
00315 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00316 errmsg("statement trigger's WHEN condition cannot reference column values"),
00317 parser_errposition(pstate, var->location)));
00318 if (TRIGGER_FOR_INSERT(tgtype))
00319 ereport(ERROR,
00320 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00321 errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
00322 parser_errposition(pstate, var->location)));
00323
00324 break;
00325 case PRS2_NEW_VARNO:
00326 if (!TRIGGER_FOR_ROW(tgtype))
00327 ereport(ERROR,
00328 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00329 errmsg("statement trigger's WHEN condition cannot reference column values"),
00330 parser_errposition(pstate, var->location)));
00331 if (TRIGGER_FOR_DELETE(tgtype))
00332 ereport(ERROR,
00333 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00334 errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
00335 parser_errposition(pstate, var->location)));
00336 if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
00337 ereport(ERROR,
00338 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00339 errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
00340 parser_errposition(pstate, var->location)));
00341 break;
00342 default:
00343
00344 elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
00345 break;
00346 }
00347 }
00348
00349
00350 whenRtable = pstate->p_rtable;
00351
00352 qual = nodeToString(whenClause);
00353
00354 free_parsestate(pstate);
00355 }
00356 else
00357 {
00358 whenClause = NULL;
00359 whenRtable = NIL;
00360 qual = NULL;
00361 }
00362
00363
00364
00365
00366 funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
00367 if (!isInternal)
00368 {
00369 aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
00370 if (aclresult != ACLCHECK_OK)
00371 aclcheck_error(aclresult, ACL_KIND_PROC,
00372 NameListToString(stmt->funcname));
00373 }
00374 funcrettype = get_func_rettype(funcoid);
00375 if (funcrettype != TRIGGEROID)
00376 {
00377
00378
00379
00380
00381 if (funcrettype == OPAQUEOID)
00382 {
00383 ereport(WARNING,
00384 (errmsg("changing return type of function %s from \"opaque\" to \"trigger\"",
00385 NameListToString(stmt->funcname))));
00386 SetFunctionReturnType(funcoid, TRIGGEROID);
00387 }
00388 else
00389 ereport(ERROR,
00390 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00391 errmsg("function %s must return type \"trigger\"",
00392 NameListToString(stmt->funcname))));
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402 if (stmt->isconstraint && !isInternal &&
00403 list_length(stmt->args) >= 6 &&
00404 (list_length(stmt->args) % 2) == 0 &&
00405 RI_FKey_trigger_type(funcoid) != RI_TRIGGER_NONE)
00406 {
00407
00408 heap_close(rel, NoLock);
00409
00410 ConvertTriggerToFK(stmt, funcoid);
00411
00412 return InvalidOid;
00413 }
00414
00415
00416
00417
00418
00419 if (stmt->isconstraint && !OidIsValid(constraintOid))
00420 {
00421
00422 Assert(!isInternal);
00423 constraintOid = CreateConstraintEntry(stmt->trigname,
00424 RelationGetNamespace(rel),
00425 CONSTRAINT_TRIGGER,
00426 stmt->deferrable,
00427 stmt->initdeferred,
00428 true,
00429 RelationGetRelid(rel),
00430 NULL,
00431 0,
00432 InvalidOid,
00433 InvalidOid,
00434 InvalidOid,
00435 NULL,
00436 NULL,
00437 NULL,
00438 NULL,
00439 0,
00440 ' ',
00441 ' ',
00442 ' ',
00443 NULL,
00444 NULL,
00445 NULL,
00446 NULL,
00447 true,
00448 0,
00449 true,
00450 isInternal);
00451 }
00452
00453
00454
00455
00456
00457 tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
00458
00459 trigoid = GetNewOid(tgrel);
00460
00461
00462
00463
00464
00465
00466 if (isInternal)
00467 {
00468 snprintf(internaltrigname, sizeof(internaltrigname),
00469 "%s_%u", stmt->trigname, trigoid);
00470 trigname = internaltrigname;
00471 }
00472 else
00473 {
00474
00475 trigname = stmt->trigname;
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488 if (!isInternal)
00489 {
00490 ScanKeyInit(&key,
00491 Anum_pg_trigger_tgrelid,
00492 BTEqualStrategyNumber, F_OIDEQ,
00493 ObjectIdGetDatum(RelationGetRelid(rel)));
00494 tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
00495 SnapshotNow, 1, &key);
00496 while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
00497 {
00498 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
00499
00500 if (namestrcmp(&(pg_trigger->tgname), trigname) == 0)
00501 ereport(ERROR,
00502 (errcode(ERRCODE_DUPLICATE_OBJECT),
00503 errmsg("trigger \"%s\" for relation \"%s\" already exists",
00504 trigname, stmt->relation->relname)));
00505 }
00506 systable_endscan(tgscan);
00507 }
00508
00509
00510
00511
00512 memset(nulls, false, sizeof(nulls));
00513
00514 values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
00515 values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
00516 CStringGetDatum(trigname));
00517 values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
00518 values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
00519 values[Anum_pg_trigger_tgenabled - 1] = CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
00520 values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
00521 values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
00522 values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
00523 values[Anum_pg_trigger_tgconstraint - 1] = ObjectIdGetDatum(constraintOid);
00524 values[Anum_pg_trigger_tgdeferrable - 1] = BoolGetDatum(stmt->deferrable);
00525 values[Anum_pg_trigger_tginitdeferred - 1] = BoolGetDatum(stmt->initdeferred);
00526
00527 if (stmt->args)
00528 {
00529 ListCell *le;
00530 char *args;
00531 int16 nargs = list_length(stmt->args);
00532 int len = 0;
00533
00534 foreach(le, stmt->args)
00535 {
00536 char *ar = strVal(lfirst(le));
00537
00538 len += strlen(ar) + 4;
00539 for (; *ar; ar++)
00540 {
00541 if (*ar == '\\')
00542 len++;
00543 }
00544 }
00545 args = (char *) palloc(len + 1);
00546 args[0] = '\0';
00547 foreach(le, stmt->args)
00548 {
00549 char *s = strVal(lfirst(le));
00550 char *d = args + strlen(args);
00551
00552 while (*s)
00553 {
00554 if (*s == '\\')
00555 *d++ = '\\';
00556 *d++ = *s++;
00557 }
00558 strcpy(d, "\\000");
00559 }
00560 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
00561 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
00562 CStringGetDatum(args));
00563 }
00564 else
00565 {
00566 values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
00567 values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
00568 CStringGetDatum(""));
00569 }
00570
00571
00572 ncolumns = list_length(stmt->columns);
00573 if (ncolumns == 0)
00574 columns = NULL;
00575 else
00576 {
00577 ListCell *cell;
00578 int i = 0;
00579
00580 columns = (int16 *) palloc(ncolumns * sizeof(int16));
00581 foreach(cell, stmt->columns)
00582 {
00583 char *name = strVal(lfirst(cell));
00584 int16 attnum;
00585 int j;
00586
00587
00588 attnum = attnameAttNum(rel, name, false);
00589 if (attnum == InvalidAttrNumber)
00590 ereport(ERROR,
00591 (errcode(ERRCODE_UNDEFINED_COLUMN),
00592 errmsg("column \"%s\" of relation \"%s\" does not exist",
00593 name, RelationGetRelationName(rel))));
00594
00595
00596 for (j = i - 1; j >= 0; j--)
00597 {
00598 if (columns[j] == attnum)
00599 ereport(ERROR,
00600 (errcode(ERRCODE_DUPLICATE_COLUMN),
00601 errmsg("column \"%s\" specified more than once",
00602 name)));
00603 }
00604
00605 columns[i++] = attnum;
00606 }
00607 }
00608 tgattr = buildint2vector(columns, ncolumns);
00609 values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
00610
00611
00612 if (qual)
00613 values[Anum_pg_trigger_tgqual - 1] = CStringGetTextDatum(qual);
00614 else
00615 nulls[Anum_pg_trigger_tgqual - 1] = true;
00616
00617 tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
00618
00619
00620 HeapTupleSetOid(tuple, trigoid);
00621
00622
00623
00624
00625 simple_heap_insert(tgrel, tuple);
00626
00627 CatalogUpdateIndexes(tgrel, tuple);
00628
00629 heap_freetuple(tuple);
00630 heap_close(tgrel, RowExclusiveLock);
00631
00632 pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
00633 pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
00634 pfree(DatumGetPointer(values[Anum_pg_trigger_tgattr - 1]));
00635
00636
00637
00638
00639
00640
00641 pgrel = heap_open(RelationRelationId, RowExclusiveLock);
00642 tuple = SearchSysCacheCopy1(RELOID,
00643 ObjectIdGetDatum(RelationGetRelid(rel)));
00644 if (!HeapTupleIsValid(tuple))
00645 elog(ERROR, "cache lookup failed for relation %u",
00646 RelationGetRelid(rel));
00647
00648 ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
00649
00650 simple_heap_update(pgrel, &tuple->t_self, tuple);
00651
00652 CatalogUpdateIndexes(pgrel, tuple);
00653
00654 heap_freetuple(tuple);
00655 heap_close(pgrel, RowExclusiveLock);
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 myself.classId = TriggerRelationId;
00668 myself.objectId = trigoid;
00669 myself.objectSubId = 0;
00670
00671 referenced.classId = ProcedureRelationId;
00672 referenced.objectId = funcoid;
00673 referenced.objectSubId = 0;
00674 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00675
00676 if (isInternal && OidIsValid(constraintOid))
00677 {
00678
00679
00680
00681
00682
00683
00684 referenced.classId = ConstraintRelationId;
00685 referenced.objectId = constraintOid;
00686 referenced.objectSubId = 0;
00687 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
00688 }
00689 else
00690 {
00691
00692
00693
00694
00695
00696 referenced.classId = RelationRelationId;
00697 referenced.objectId = RelationGetRelid(rel);
00698 referenced.objectSubId = 0;
00699 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
00700 if (OidIsValid(constrrelid))
00701 {
00702 referenced.classId = RelationRelationId;
00703 referenced.objectId = constrrelid;
00704 referenced.objectSubId = 0;
00705 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
00706 }
00707
00708 Assert(!OidIsValid(indexOid));
00709
00710
00711
00712
00713
00714 if (OidIsValid(constraintOid))
00715 {
00716 referenced.classId = ConstraintRelationId;
00717 referenced.objectId = constraintOid;
00718 referenced.objectSubId = 0;
00719 recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
00720 }
00721 }
00722
00723
00724 if (columns != NULL)
00725 {
00726 int i;
00727
00728 referenced.classId = RelationRelationId;
00729 referenced.objectId = RelationGetRelid(rel);
00730 for (i = 0; i < ncolumns; i++)
00731 {
00732 referenced.objectSubId = columns[i];
00733 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00734 }
00735 }
00736
00737
00738
00739
00740
00741 if (whenClause != NULL)
00742 recordDependencyOnExpr(&myself, whenClause, whenRtable,
00743 DEPENDENCY_NORMAL);
00744
00745
00746 InvokeObjectPostCreateHookArg(TriggerRelationId, trigoid, 0,
00747 isInternal);
00748
00749
00750 heap_close(rel, NoLock);
00751
00752 return trigoid;
00753 }
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775 typedef struct
00776 {
00777 List *args;
00778 Oid funcoids[3];
00779
00780 } OldTriggerInfo;
00781
00782 static void
00783 ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
00784 {
00785 static List *info_list = NIL;
00786
00787 static const char *const funcdescr[3] = {
00788 gettext_noop("Found referenced table's UPDATE trigger."),
00789 gettext_noop("Found referenced table's DELETE trigger."),
00790 gettext_noop("Found referencing table's trigger.")
00791 };
00792
00793 char *constr_name;
00794 char *fk_table_name;
00795 char *pk_table_name;
00796 char fk_matchtype = FKCONSTR_MATCH_SIMPLE;
00797 List *fk_attrs = NIL;
00798 List *pk_attrs = NIL;
00799 StringInfoData buf;
00800 int funcnum;
00801 OldTriggerInfo *info = NULL;
00802 ListCell *l;
00803 int i;
00804
00805
00806 constr_name = strVal(linitial(stmt->args));
00807 fk_table_name = strVal(lsecond(stmt->args));
00808 pk_table_name = strVal(lthird(stmt->args));
00809 i = 0;
00810 foreach(l, stmt->args)
00811 {
00812 Value *arg = (Value *) lfirst(l);
00813
00814 i++;
00815 if (i < 4)
00816 continue;
00817 if (i == 4)
00818 {
00819 if (strcmp(strVal(arg), "FULL") == 0)
00820 fk_matchtype = FKCONSTR_MATCH_FULL;
00821 else
00822 fk_matchtype = FKCONSTR_MATCH_SIMPLE;
00823 continue;
00824 }
00825 if (i % 2)
00826 fk_attrs = lappend(fk_attrs, arg);
00827 else
00828 pk_attrs = lappend(pk_attrs, arg);
00829 }
00830
00831
00832 initStringInfo(&buf);
00833 appendStringInfo(&buf, "FOREIGN KEY %s(",
00834 quote_identifier(fk_table_name));
00835 i = 0;
00836 foreach(l, fk_attrs)
00837 {
00838 Value *arg = (Value *) lfirst(l);
00839
00840 if (i++ > 0)
00841 appendStringInfoChar(&buf, ',');
00842 appendStringInfoString(&buf, quote_identifier(strVal(arg)));
00843 }
00844 appendStringInfo(&buf, ") REFERENCES %s(",
00845 quote_identifier(pk_table_name));
00846 i = 0;
00847 foreach(l, pk_attrs)
00848 {
00849 Value *arg = (Value *) lfirst(l);
00850
00851 if (i++ > 0)
00852 appendStringInfoChar(&buf, ',');
00853 appendStringInfoString(&buf, quote_identifier(strVal(arg)));
00854 }
00855 appendStringInfoChar(&buf, ')');
00856
00857
00858 switch (funcoid)
00859 {
00860 case F_RI_FKEY_CASCADE_UPD:
00861 case F_RI_FKEY_RESTRICT_UPD:
00862 case F_RI_FKEY_SETNULL_UPD:
00863 case F_RI_FKEY_SETDEFAULT_UPD:
00864 case F_RI_FKEY_NOACTION_UPD:
00865 funcnum = 0;
00866 break;
00867
00868 case F_RI_FKEY_CASCADE_DEL:
00869 case F_RI_FKEY_RESTRICT_DEL:
00870 case F_RI_FKEY_SETNULL_DEL:
00871 case F_RI_FKEY_SETDEFAULT_DEL:
00872 case F_RI_FKEY_NOACTION_DEL:
00873 funcnum = 1;
00874 break;
00875
00876 default:
00877 funcnum = 2;
00878 break;
00879 }
00880
00881
00882 foreach(l, info_list)
00883 {
00884 info = (OldTriggerInfo *) lfirst(l);
00885 if (info->funcoids[funcnum] == InvalidOid &&
00886 equal(info->args, stmt->args))
00887 {
00888 info->funcoids[funcnum] = funcoid;
00889 break;
00890 }
00891 }
00892
00893 if (l == NULL)
00894 {
00895
00896 MemoryContext oldContext;
00897
00898 ereport(NOTICE,
00899 (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
00900 constr_name, buf.data),
00901 errdetail_internal("%s", _(funcdescr[funcnum]))));
00902 oldContext = MemoryContextSwitchTo(TopMemoryContext);
00903 info = (OldTriggerInfo *) palloc0(sizeof(OldTriggerInfo));
00904 info->args = copyObject(stmt->args);
00905 info->funcoids[funcnum] = funcoid;
00906 info_list = lappend(info_list, info);
00907 MemoryContextSwitchTo(oldContext);
00908 }
00909 else if (info->funcoids[0] == InvalidOid ||
00910 info->funcoids[1] == InvalidOid ||
00911 info->funcoids[2] == InvalidOid)
00912 {
00913
00914 ereport(NOTICE,
00915 (errmsg("ignoring incomplete trigger group for constraint \"%s\" %s",
00916 constr_name, buf.data),
00917 errdetail_internal("%s", _(funcdescr[funcnum]))));
00918 }
00919 else
00920 {
00921
00922 AlterTableStmt *atstmt = makeNode(AlterTableStmt);
00923 AlterTableCmd *atcmd = makeNode(AlterTableCmd);
00924 Constraint *fkcon = makeNode(Constraint);
00925
00926 ereport(NOTICE,
00927 (errmsg("converting trigger group into constraint \"%s\" %s",
00928 constr_name, buf.data),
00929 errdetail_internal("%s", _(funcdescr[funcnum]))));
00930 fkcon->contype = CONSTR_FOREIGN;
00931 fkcon->location = -1;
00932 if (funcnum == 2)
00933 {
00934
00935 atstmt->relation = stmt->relation;
00936 if (stmt->constrrel)
00937 fkcon->pktable = stmt->constrrel;
00938 else
00939 {
00940
00941 fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
00942 }
00943 }
00944 else
00945 {
00946
00947 fkcon->pktable = stmt->relation;
00948 if (stmt->constrrel)
00949 atstmt->relation = stmt->constrrel;
00950 else
00951 {
00952
00953 atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
00954 }
00955 }
00956 atstmt->cmds = list_make1(atcmd);
00957 atstmt->relkind = OBJECT_TABLE;
00958 atcmd->subtype = AT_AddConstraint;
00959 atcmd->def = (Node *) fkcon;
00960 if (strcmp(constr_name, "<unnamed>") == 0)
00961 fkcon->conname = NULL;
00962 else
00963 fkcon->conname = constr_name;
00964 fkcon->fk_attrs = fk_attrs;
00965 fkcon->pk_attrs = pk_attrs;
00966 fkcon->fk_matchtype = fk_matchtype;
00967 switch (info->funcoids[0])
00968 {
00969 case F_RI_FKEY_NOACTION_UPD:
00970 fkcon->fk_upd_action = FKCONSTR_ACTION_NOACTION;
00971 break;
00972 case F_RI_FKEY_CASCADE_UPD:
00973 fkcon->fk_upd_action = FKCONSTR_ACTION_CASCADE;
00974 break;
00975 case F_RI_FKEY_RESTRICT_UPD:
00976 fkcon->fk_upd_action = FKCONSTR_ACTION_RESTRICT;
00977 break;
00978 case F_RI_FKEY_SETNULL_UPD:
00979 fkcon->fk_upd_action = FKCONSTR_ACTION_SETNULL;
00980 break;
00981 case F_RI_FKEY_SETDEFAULT_UPD:
00982 fkcon->fk_upd_action = FKCONSTR_ACTION_SETDEFAULT;
00983 break;
00984 default:
00985
00986 elog(ERROR, "confused about RI update function");
00987 }
00988 switch (info->funcoids[1])
00989 {
00990 case F_RI_FKEY_NOACTION_DEL:
00991 fkcon->fk_del_action = FKCONSTR_ACTION_NOACTION;
00992 break;
00993 case F_RI_FKEY_CASCADE_DEL:
00994 fkcon->fk_del_action = FKCONSTR_ACTION_CASCADE;
00995 break;
00996 case F_RI_FKEY_RESTRICT_DEL:
00997 fkcon->fk_del_action = FKCONSTR_ACTION_RESTRICT;
00998 break;
00999 case F_RI_FKEY_SETNULL_DEL:
01000 fkcon->fk_del_action = FKCONSTR_ACTION_SETNULL;
01001 break;
01002 case F_RI_FKEY_SETDEFAULT_DEL:
01003 fkcon->fk_del_action = FKCONSTR_ACTION_SETDEFAULT;
01004 break;
01005 default:
01006
01007 elog(ERROR, "confused about RI delete function");
01008 }
01009 fkcon->deferrable = stmt->deferrable;
01010 fkcon->initdeferred = stmt->initdeferred;
01011 fkcon->skip_validation = false;
01012 fkcon->initially_valid = true;
01013
01014
01015 ProcessUtility((Node *) atstmt,
01016 "(generated ALTER TABLE ADD FOREIGN KEY command)",
01017 PROCESS_UTILITY_SUBCOMMAND, NULL,
01018 None_Receiver, NULL);
01019
01020
01021 info_list = list_delete_ptr(info_list, info);
01022 pfree(info);
01023
01024 }
01025 }
01026
01027
01028
01029
01030 void
01031 RemoveTriggerById(Oid trigOid)
01032 {
01033 Relation tgrel;
01034 SysScanDesc tgscan;
01035 ScanKeyData skey[1];
01036 HeapTuple tup;
01037 Oid relid;
01038 Relation rel;
01039
01040 tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
01041
01042
01043
01044
01045 ScanKeyInit(&skey[0],
01046 ObjectIdAttributeNumber,
01047 BTEqualStrategyNumber, F_OIDEQ,
01048 ObjectIdGetDatum(trigOid));
01049
01050 tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
01051 SnapshotNow, 1, skey);
01052
01053 tup = systable_getnext(tgscan);
01054 if (!HeapTupleIsValid(tup))
01055 elog(ERROR, "could not find tuple for trigger %u", trigOid);
01056
01057
01058
01059
01060 relid = ((Form_pg_trigger) GETSTRUCT(tup))->tgrelid;
01061
01062 rel = heap_open(relid, AccessExclusiveLock);
01063
01064 if (rel->rd_rel->relkind != RELKIND_RELATION &&
01065 rel->rd_rel->relkind != RELKIND_VIEW)
01066 ereport(ERROR,
01067 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01068 errmsg("\"%s\" is not a table or view",
01069 RelationGetRelationName(rel))));
01070
01071 if (!allowSystemTableMods && IsSystemRelation(rel))
01072 ereport(ERROR,
01073 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01074 errmsg("permission denied: \"%s\" is a system catalog",
01075 RelationGetRelationName(rel))));
01076
01077
01078
01079
01080 simple_heap_delete(tgrel, &tup->t_self);
01081
01082 systable_endscan(tgscan);
01083 heap_close(tgrel, RowExclusiveLock);
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094 CacheInvalidateRelcache(rel);
01095
01096
01097 heap_close(rel, NoLock);
01098 }
01099
01100
01101
01102
01103
01104
01105
01106 Oid
01107 get_trigger_oid(Oid relid, const char *trigname, bool missing_ok)
01108 {
01109 Relation tgrel;
01110 ScanKeyData skey[2];
01111 SysScanDesc tgscan;
01112 HeapTuple tup;
01113 Oid oid;
01114
01115
01116
01117
01118 tgrel = heap_open(TriggerRelationId, AccessShareLock);
01119
01120 ScanKeyInit(&skey[0],
01121 Anum_pg_trigger_tgrelid,
01122 BTEqualStrategyNumber, F_OIDEQ,
01123 ObjectIdGetDatum(relid));
01124 ScanKeyInit(&skey[1],
01125 Anum_pg_trigger_tgname,
01126 BTEqualStrategyNumber, F_NAMEEQ,
01127 CStringGetDatum(trigname));
01128
01129 tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
01130 SnapshotNow, 2, skey);
01131
01132 tup = systable_getnext(tgscan);
01133
01134 if (!HeapTupleIsValid(tup))
01135 {
01136 if (!missing_ok)
01137 ereport(ERROR,
01138 (errcode(ERRCODE_UNDEFINED_OBJECT),
01139 errmsg("trigger \"%s\" for table \"%s\" does not exist",
01140 trigname, get_rel_name(relid))));
01141 oid = InvalidOid;
01142 }
01143 else
01144 {
01145 oid = HeapTupleGetOid(tup);
01146 }
01147
01148 systable_endscan(tgscan);
01149 heap_close(tgrel, AccessShareLock);
01150 return oid;
01151 }
01152
01153
01154
01155
01156 static void
01157 RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid,
01158 void *arg)
01159 {
01160 HeapTuple tuple;
01161 Form_pg_class form;
01162
01163 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
01164 if (!HeapTupleIsValid(tuple))
01165 return;
01166 form = (Form_pg_class) GETSTRUCT(tuple);
01167
01168
01169 if (form->relkind != RELKIND_RELATION && form->relkind != RELKIND_VIEW)
01170 ereport(ERROR,
01171 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01172 errmsg("\"%s\" is not a table or view", rv->relname)));
01173
01174
01175 if (!pg_class_ownercheck(relid, GetUserId()))
01176 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, rv->relname);
01177 if (!allowSystemTableMods && IsSystemClass(form))
01178 ereport(ERROR,
01179 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01180 errmsg("permission denied: \"%s\" is a system catalog",
01181 rv->relname)));
01182
01183 ReleaseSysCache(tuple);
01184 }
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199 Oid
01200 renametrig(RenameStmt *stmt)
01201 {
01202 Oid tgoid;
01203 Relation targetrel;
01204 Relation tgrel;
01205 HeapTuple tuple;
01206 SysScanDesc tgscan;
01207 ScanKeyData key[2];
01208 Oid relid;
01209
01210
01211
01212
01213
01214 relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
01215 false, false,
01216 RangeVarCallbackForRenameTrigger,
01217 NULL);
01218
01219
01220 targetrel = relation_open(relid, NoLock);
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231 tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
01232
01233
01234
01235
01236 ScanKeyInit(&key[0],
01237 Anum_pg_trigger_tgrelid,
01238 BTEqualStrategyNumber, F_OIDEQ,
01239 ObjectIdGetDatum(relid));
01240 ScanKeyInit(&key[1],
01241 Anum_pg_trigger_tgname,
01242 BTEqualStrategyNumber, F_NAMEEQ,
01243 PointerGetDatum(stmt->newname));
01244 tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
01245 SnapshotNow, 2, key);
01246 if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
01247 ereport(ERROR,
01248 (errcode(ERRCODE_DUPLICATE_OBJECT),
01249 errmsg("trigger \"%s\" for relation \"%s\" already exists",
01250 stmt->newname, RelationGetRelationName(targetrel))));
01251 systable_endscan(tgscan);
01252
01253
01254
01255
01256 ScanKeyInit(&key[0],
01257 Anum_pg_trigger_tgrelid,
01258 BTEqualStrategyNumber, F_OIDEQ,
01259 ObjectIdGetDatum(relid));
01260 ScanKeyInit(&key[1],
01261 Anum_pg_trigger_tgname,
01262 BTEqualStrategyNumber, F_NAMEEQ,
01263 PointerGetDatum(stmt->subname));
01264 tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
01265 SnapshotNow, 2, key);
01266 if (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
01267 {
01268 tgoid = HeapTupleGetOid(tuple);
01269
01270
01271
01272 tuple = heap_copytuple(tuple);
01273
01274 namestrcpy(&((Form_pg_trigger) GETSTRUCT(tuple))->tgname,
01275 stmt->newname);
01276
01277 simple_heap_update(tgrel, &tuple->t_self, tuple);
01278
01279
01280 CatalogUpdateIndexes(tgrel, tuple);
01281
01282 InvokeObjectPostAlterHook(TriggerRelationId,
01283 HeapTupleGetOid(tuple), 0);
01284
01285
01286
01287
01288
01289
01290 CacheInvalidateRelcache(targetrel);
01291 }
01292 else
01293 {
01294 ereport(ERROR,
01295 (errcode(ERRCODE_UNDEFINED_OBJECT),
01296 errmsg("trigger \"%s\" for table \"%s\" does not exist",
01297 stmt->subname, RelationGetRelationName(targetrel))));
01298 }
01299
01300 systable_endscan(tgscan);
01301
01302 heap_close(tgrel, RowExclusiveLock);
01303
01304
01305
01306
01307 relation_close(targetrel, NoLock);
01308
01309 return tgoid;
01310 }
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330 void
01331 EnableDisableTrigger(Relation rel, const char *tgname,
01332 char fires_when, bool skip_system)
01333 {
01334 Relation tgrel;
01335 int nkeys;
01336 ScanKeyData keys[2];
01337 SysScanDesc tgscan;
01338 HeapTuple tuple;
01339 bool found;
01340 bool changed;
01341
01342
01343 tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
01344
01345 ScanKeyInit(&keys[0],
01346 Anum_pg_trigger_tgrelid,
01347 BTEqualStrategyNumber, F_OIDEQ,
01348 ObjectIdGetDatum(RelationGetRelid(rel)));
01349 if (tgname)
01350 {
01351 ScanKeyInit(&keys[1],
01352 Anum_pg_trigger_tgname,
01353 BTEqualStrategyNumber, F_NAMEEQ,
01354 CStringGetDatum(tgname));
01355 nkeys = 2;
01356 }
01357 else
01358 nkeys = 1;
01359
01360 tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
01361 SnapshotNow, nkeys, keys);
01362
01363 found = changed = false;
01364
01365 while (HeapTupleIsValid(tuple = systable_getnext(tgscan)))
01366 {
01367 Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple);
01368
01369 if (oldtrig->tgisinternal)
01370 {
01371
01372 if (skip_system)
01373 continue;
01374 if (!superuser())
01375 ereport(ERROR,
01376 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
01377 errmsg("permission denied: \"%s\" is a system trigger",
01378 NameStr(oldtrig->tgname))));
01379 }
01380
01381 found = true;
01382
01383 if (oldtrig->tgenabled != fires_when)
01384 {
01385
01386 HeapTuple newtup = heap_copytuple(tuple);
01387 Form_pg_trigger newtrig = (Form_pg_trigger) GETSTRUCT(newtup);
01388
01389 newtrig->tgenabled = fires_when;
01390
01391 simple_heap_update(tgrel, &newtup->t_self, newtup);
01392
01393
01394 CatalogUpdateIndexes(tgrel, newtup);
01395
01396 heap_freetuple(newtup);
01397
01398 changed = true;
01399 }
01400
01401 InvokeObjectPostAlterHook(TriggerRelationId,
01402 HeapTupleGetOid(tuple), 0);
01403 }
01404
01405 systable_endscan(tgscan);
01406
01407 heap_close(tgrel, RowExclusiveLock);
01408
01409 if (tgname && !found)
01410 ereport(ERROR,
01411 (errcode(ERRCODE_UNDEFINED_OBJECT),
01412 errmsg("trigger \"%s\" for table \"%s\" does not exist",
01413 tgname, RelationGetRelationName(rel))));
01414
01415
01416
01417
01418
01419
01420 if (changed)
01421 CacheInvalidateRelcache(rel);
01422 }
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435 void
01436 RelationBuildTriggers(Relation relation)
01437 {
01438 TriggerDesc *trigdesc;
01439 int numtrigs;
01440 int maxtrigs;
01441 Trigger *triggers;
01442 Relation tgrel;
01443 ScanKeyData skey;
01444 SysScanDesc tgscan;
01445 HeapTuple htup;
01446 MemoryContext oldContext;
01447 int i;
01448
01449
01450
01451
01452
01453 maxtrigs = 16;
01454 triggers = (Trigger *) palloc(maxtrigs * sizeof(Trigger));
01455 numtrigs = 0;
01456
01457
01458
01459
01460
01461
01462
01463 ScanKeyInit(&skey,
01464 Anum_pg_trigger_tgrelid,
01465 BTEqualStrategyNumber, F_OIDEQ,
01466 ObjectIdGetDatum(RelationGetRelid(relation)));
01467
01468 tgrel = heap_open(TriggerRelationId, AccessShareLock);
01469 tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true,
01470 SnapshotNow, 1, &skey);
01471
01472 while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
01473 {
01474 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
01475 Trigger *build;
01476 Datum datum;
01477 bool isnull;
01478
01479 if (numtrigs >= maxtrigs)
01480 {
01481 maxtrigs *= 2;
01482 triggers = (Trigger *) repalloc(triggers, maxtrigs * sizeof(Trigger));
01483 }
01484 build = &(triggers[numtrigs]);
01485
01486 build->tgoid = HeapTupleGetOid(htup);
01487 build->tgname = DatumGetCString(DirectFunctionCall1(nameout,
01488 NameGetDatum(&pg_trigger->tgname)));
01489 build->tgfoid = pg_trigger->tgfoid;
01490 build->tgtype = pg_trigger->tgtype;
01491 build->tgenabled = pg_trigger->tgenabled;
01492 build->tgisinternal = pg_trigger->tgisinternal;
01493 build->tgconstrrelid = pg_trigger->tgconstrrelid;
01494 build->tgconstrindid = pg_trigger->tgconstrindid;
01495 build->tgconstraint = pg_trigger->tgconstraint;
01496 build->tgdeferrable = pg_trigger->tgdeferrable;
01497 build->tginitdeferred = pg_trigger->tginitdeferred;
01498 build->tgnargs = pg_trigger->tgnargs;
01499
01500 build->tgnattr = pg_trigger->tgattr.dim1;
01501 if (build->tgnattr > 0)
01502 {
01503 build->tgattr = (int16 *) palloc(build->tgnattr * sizeof(int16));
01504 memcpy(build->tgattr, &(pg_trigger->tgattr.values),
01505 build->tgnattr * sizeof(int16));
01506 }
01507 else
01508 build->tgattr = NULL;
01509 if (build->tgnargs > 0)
01510 {
01511 bytea *val;
01512 char *p;
01513
01514 val = DatumGetByteaP(fastgetattr(htup,
01515 Anum_pg_trigger_tgargs,
01516 tgrel->rd_att, &isnull));
01517 if (isnull)
01518 elog(ERROR, "tgargs is null in trigger for relation \"%s\"",
01519 RelationGetRelationName(relation));
01520 p = (char *) VARDATA(val);
01521 build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *));
01522 for (i = 0; i < build->tgnargs; i++)
01523 {
01524 build->tgargs[i] = pstrdup(p);
01525 p += strlen(p) + 1;
01526 }
01527 }
01528 else
01529 build->tgargs = NULL;
01530 datum = fastgetattr(htup, Anum_pg_trigger_tgqual,
01531 tgrel->rd_att, &isnull);
01532 if (!isnull)
01533 build->tgqual = TextDatumGetCString(datum);
01534 else
01535 build->tgqual = NULL;
01536
01537 numtrigs++;
01538 }
01539
01540 systable_endscan(tgscan);
01541 heap_close(tgrel, AccessShareLock);
01542
01543
01544 if (numtrigs == 0)
01545 {
01546 pfree(triggers);
01547 return;
01548 }
01549
01550
01551 trigdesc = (TriggerDesc *) palloc0(sizeof(TriggerDesc));
01552 trigdesc->triggers = triggers;
01553 trigdesc->numtriggers = numtrigs;
01554 for (i = 0; i < numtrigs; i++)
01555 SetTriggerFlags(trigdesc, &(triggers[i]));
01556
01557
01558 oldContext = MemoryContextSwitchTo(CacheMemoryContext);
01559 relation->trigdesc = CopyTriggerDesc(trigdesc);
01560 MemoryContextSwitchTo(oldContext);
01561
01562
01563 FreeTriggerDesc(trigdesc);
01564 }
01565
01566
01567
01568
01569 static void
01570 SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger)
01571 {
01572 int16 tgtype = trigger->tgtype;
01573
01574 trigdesc->trig_insert_before_row |=
01575 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
01576 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSERT);
01577 trigdesc->trig_insert_after_row |=
01578 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
01579 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_INSERT);
01580 trigdesc->trig_insert_instead_row |=
01581 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
01582 TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_INSERT);
01583 trigdesc->trig_insert_before_statement |=
01584 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
01585 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSERT);
01586 trigdesc->trig_insert_after_statement |=
01587 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
01588 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_INSERT);
01589 trigdesc->trig_update_before_row |=
01590 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
01591 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_UPDATE);
01592 trigdesc->trig_update_after_row |=
01593 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
01594 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_UPDATE);
01595 trigdesc->trig_update_instead_row |=
01596 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
01597 TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_UPDATE);
01598 trigdesc->trig_update_before_statement |=
01599 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
01600 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_UPDATE);
01601 trigdesc->trig_update_after_statement |=
01602 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
01603 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_UPDATE);
01604 trigdesc->trig_delete_before_row |=
01605 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
01606 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_DELETE);
01607 trigdesc->trig_delete_after_row |=
01608 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
01609 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_DELETE);
01610 trigdesc->trig_delete_instead_row |=
01611 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
01612 TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_DELETE);
01613 trigdesc->trig_delete_before_statement |=
01614 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
01615 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_DELETE);
01616 trigdesc->trig_delete_after_statement |=
01617 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
01618 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_DELETE);
01619
01620 trigdesc->trig_truncate_before_statement |=
01621 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
01622 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_TRUNCATE);
01623 trigdesc->trig_truncate_after_statement |=
01624 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
01625 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_TRUNCATE);
01626 }
01627
01628
01629
01630
01631
01632
01633 TriggerDesc *
01634 CopyTriggerDesc(TriggerDesc *trigdesc)
01635 {
01636 TriggerDesc *newdesc;
01637 Trigger *trigger;
01638 int i;
01639
01640 if (trigdesc == NULL || trigdesc->numtriggers <= 0)
01641 return NULL;
01642
01643 newdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
01644 memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
01645
01646 trigger = (Trigger *) palloc(trigdesc->numtriggers * sizeof(Trigger));
01647 memcpy(trigger, trigdesc->triggers,
01648 trigdesc->numtriggers * sizeof(Trigger));
01649 newdesc->triggers = trigger;
01650
01651 for (i = 0; i < trigdesc->numtriggers; i++)
01652 {
01653 trigger->tgname = pstrdup(trigger->tgname);
01654 if (trigger->tgnattr > 0)
01655 {
01656 int16 *newattr;
01657
01658 newattr = (int16 *) palloc(trigger->tgnattr * sizeof(int16));
01659 memcpy(newattr, trigger->tgattr,
01660 trigger->tgnattr * sizeof(int16));
01661 trigger->tgattr = newattr;
01662 }
01663 if (trigger->tgnargs > 0)
01664 {
01665 char **newargs;
01666 int16 j;
01667
01668 newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
01669 for (j = 0; j < trigger->tgnargs; j++)
01670 newargs[j] = pstrdup(trigger->tgargs[j]);
01671 trigger->tgargs = newargs;
01672 }
01673 if (trigger->tgqual)
01674 trigger->tgqual = pstrdup(trigger->tgqual);
01675 trigger++;
01676 }
01677
01678 return newdesc;
01679 }
01680
01681
01682
01683
01684 void
01685 FreeTriggerDesc(TriggerDesc *trigdesc)
01686 {
01687 Trigger *trigger;
01688 int i;
01689
01690 if (trigdesc == NULL)
01691 return;
01692
01693 trigger = trigdesc->triggers;
01694 for (i = 0; i < trigdesc->numtriggers; i++)
01695 {
01696 pfree(trigger->tgname);
01697 if (trigger->tgnattr > 0)
01698 pfree(trigger->tgattr);
01699 if (trigger->tgnargs > 0)
01700 {
01701 while (--(trigger->tgnargs) >= 0)
01702 pfree(trigger->tgargs[trigger->tgnargs]);
01703 pfree(trigger->tgargs);
01704 }
01705 if (trigger->tgqual)
01706 pfree(trigger->tgqual);
01707 trigger++;
01708 }
01709 pfree(trigdesc->triggers);
01710 pfree(trigdesc);
01711 }
01712
01713
01714
01715
01716 #ifdef NOT_USED
01717 bool
01718 equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
01719 {
01720 int i,
01721 j;
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735 if (trigdesc1 != NULL)
01736 {
01737 if (trigdesc2 == NULL)
01738 return false;
01739 if (trigdesc1->numtriggers != trigdesc2->numtriggers)
01740 return false;
01741 for (i = 0; i < trigdesc1->numtriggers; i++)
01742 {
01743 Trigger *trig1 = trigdesc1->triggers + i;
01744 Trigger *trig2 = trigdesc2->triggers + i;
01745
01746 if (trig1->tgoid != trig2->tgoid)
01747 return false;
01748 if (strcmp(trig1->tgname, trig2->tgname) != 0)
01749 return false;
01750 if (trig1->tgfoid != trig2->tgfoid)
01751 return false;
01752 if (trig1->tgtype != trig2->tgtype)
01753 return false;
01754 if (trig1->tgenabled != trig2->tgenabled)
01755 return false;
01756 if (trig1->tgisinternal != trig2->tgisinternal)
01757 return false;
01758 if (trig1->tgconstrrelid != trig2->tgconstrrelid)
01759 return false;
01760 if (trig1->tgconstrindid != trig2->tgconstrindid)
01761 return false;
01762 if (trig1->tgconstraint != trig2->tgconstraint)
01763 return false;
01764 if (trig1->tgdeferrable != trig2->tgdeferrable)
01765 return false;
01766 if (trig1->tginitdeferred != trig2->tginitdeferred)
01767 return false;
01768 if (trig1->tgnargs != trig2->tgnargs)
01769 return false;
01770 if (trig1->tgnattr != trig2->tgnattr)
01771 return false;
01772 if (trig1->tgnattr > 0 &&
01773 memcmp(trig1->tgattr, trig2->tgattr,
01774 trig1->tgnattr * sizeof(int16)) != 0)
01775 return false;
01776 for (j = 0; j < trig1->tgnargs; j++)
01777 if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0)
01778 return false;
01779 if (trig1->tgqual == NULL && trig2->tgqual == NULL)
01780 ;
01781 else if (trig1->tgqual == NULL || trig2->tgqual == NULL)
01782 return false;
01783 else if (strcmp(trig1->tgqual, trig2->tgqual) != 0)
01784 return false;
01785 }
01786 }
01787 else if (trigdesc2 != NULL)
01788 return false;
01789 return true;
01790 }
01791 #endif
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804 static HeapTuple
01805 ExecCallTriggerFunc(TriggerData *trigdata,
01806 int tgindx,
01807 FmgrInfo *finfo,
01808 Instrumentation *instr,
01809 MemoryContext per_tuple_context)
01810 {
01811 FunctionCallInfoData fcinfo;
01812 PgStat_FunctionCallUsage fcusage;
01813 Datum result;
01814 MemoryContext oldContext;
01815
01816 finfo += tgindx;
01817
01818
01819
01820
01821
01822 if (finfo->fn_oid == InvalidOid)
01823 fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
01824
01825 Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
01826
01827
01828
01829
01830 if (instr)
01831 InstrStartNode(instr + tgindx);
01832
01833
01834
01835
01836
01837
01838
01839 oldContext = MemoryContextSwitchTo(per_tuple_context);
01840
01841
01842
01843
01844 InitFunctionCallInfoData(fcinfo, finfo, 0,
01845 InvalidOid, (Node *) trigdata, NULL);
01846
01847 pgstat_init_function_usage(&fcinfo, &fcusage);
01848
01849 MyTriggerDepth++;
01850 PG_TRY();
01851 {
01852 result = FunctionCallInvoke(&fcinfo);
01853 }
01854 PG_CATCH();
01855 {
01856 MyTriggerDepth--;
01857 PG_RE_THROW();
01858 }
01859 PG_END_TRY();
01860 MyTriggerDepth--;
01861
01862 pgstat_end_function_usage(&fcusage, true);
01863
01864 MemoryContextSwitchTo(oldContext);
01865
01866
01867
01868
01869
01870 if (fcinfo.isnull)
01871 ereport(ERROR,
01872 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
01873 errmsg("trigger function %u returned null value",
01874 fcinfo.flinfo->fn_oid)));
01875
01876
01877
01878
01879
01880 if (instr)
01881 InstrStopNode(instr + tgindx, 1);
01882
01883 return (HeapTuple) DatumGetPointer(result);
01884 }
01885
01886 void
01887 ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
01888 {
01889 TriggerDesc *trigdesc;
01890 int i;
01891 TriggerData LocTriggerData;
01892
01893 trigdesc = relinfo->ri_TrigDesc;
01894
01895 if (trigdesc == NULL)
01896 return;
01897 if (!trigdesc->trig_insert_before_statement)
01898 return;
01899
01900 LocTriggerData.type = T_TriggerData;
01901 LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
01902 TRIGGER_EVENT_BEFORE;
01903 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
01904 LocTriggerData.tg_trigtuple = NULL;
01905 LocTriggerData.tg_newtuple = NULL;
01906 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
01907 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
01908 for (i = 0; i < trigdesc->numtriggers; i++)
01909 {
01910 Trigger *trigger = &trigdesc->triggers[i];
01911 HeapTuple newtuple;
01912
01913 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
01914 TRIGGER_TYPE_STATEMENT,
01915 TRIGGER_TYPE_BEFORE,
01916 TRIGGER_TYPE_INSERT))
01917 continue;
01918 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
01919 NULL, NULL, NULL))
01920 continue;
01921
01922 LocTriggerData.tg_trigger = trigger;
01923 newtuple = ExecCallTriggerFunc(&LocTriggerData,
01924 i,
01925 relinfo->ri_TrigFunctions,
01926 relinfo->ri_TrigInstrument,
01927 GetPerTupleMemoryContext(estate));
01928
01929 if (newtuple)
01930 ereport(ERROR,
01931 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
01932 errmsg("BEFORE STATEMENT trigger cannot return a value")));
01933 }
01934 }
01935
01936 void
01937 ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo)
01938 {
01939 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
01940
01941 if (trigdesc && trigdesc->trig_insert_after_statement)
01942 AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
01943 false, NULL, NULL, NIL, NULL);
01944 }
01945
01946 TupleTableSlot *
01947 ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
01948 TupleTableSlot *slot)
01949 {
01950 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
01951 HeapTuple slottuple = ExecMaterializeSlot(slot);
01952 HeapTuple newtuple = slottuple;
01953 HeapTuple oldtuple;
01954 TriggerData LocTriggerData;
01955 int i;
01956
01957 LocTriggerData.type = T_TriggerData;
01958 LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
01959 TRIGGER_EVENT_ROW |
01960 TRIGGER_EVENT_BEFORE;
01961 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
01962 LocTriggerData.tg_newtuple = NULL;
01963 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
01964 for (i = 0; i < trigdesc->numtriggers; i++)
01965 {
01966 Trigger *trigger = &trigdesc->triggers[i];
01967
01968 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
01969 TRIGGER_TYPE_ROW,
01970 TRIGGER_TYPE_BEFORE,
01971 TRIGGER_TYPE_INSERT))
01972 continue;
01973 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
01974 NULL, NULL, newtuple))
01975 continue;
01976
01977 LocTriggerData.tg_trigtuple = oldtuple = newtuple;
01978 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
01979 LocTriggerData.tg_trigger = trigger;
01980 newtuple = ExecCallTriggerFunc(&LocTriggerData,
01981 i,
01982 relinfo->ri_TrigFunctions,
01983 relinfo->ri_TrigInstrument,
01984 GetPerTupleMemoryContext(estate));
01985 if (oldtuple != newtuple && oldtuple != slottuple)
01986 heap_freetuple(oldtuple);
01987 if (newtuple == NULL)
01988 return NULL;
01989 }
01990
01991 if (newtuple != slottuple)
01992 {
01993
01994
01995
01996
01997
01998
01999 TupleTableSlot *newslot = estate->es_trig_tuple_slot;
02000 TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
02001
02002 if (newslot->tts_tupleDescriptor != tupdesc)
02003 ExecSetSlotDescriptor(newslot, tupdesc);
02004 ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
02005 slot = newslot;
02006 }
02007 return slot;
02008 }
02009
02010 void
02011 ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
02012 HeapTuple trigtuple, List *recheckIndexes)
02013 {
02014 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02015
02016 if (trigdesc && trigdesc->trig_insert_after_row)
02017 AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
02018 true, NULL, trigtuple, recheckIndexes, NULL);
02019 }
02020
02021 TupleTableSlot *
02022 ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
02023 TupleTableSlot *slot)
02024 {
02025 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02026 HeapTuple slottuple = ExecMaterializeSlot(slot);
02027 HeapTuple newtuple = slottuple;
02028 HeapTuple oldtuple;
02029 TriggerData LocTriggerData;
02030 int i;
02031
02032 LocTriggerData.type = T_TriggerData;
02033 LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
02034 TRIGGER_EVENT_ROW |
02035 TRIGGER_EVENT_INSTEAD;
02036 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
02037 LocTriggerData.tg_newtuple = NULL;
02038 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
02039 for (i = 0; i < trigdesc->numtriggers; i++)
02040 {
02041 Trigger *trigger = &trigdesc->triggers[i];
02042
02043 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
02044 TRIGGER_TYPE_ROW,
02045 TRIGGER_TYPE_INSTEAD,
02046 TRIGGER_TYPE_INSERT))
02047 continue;
02048 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
02049 NULL, NULL, newtuple))
02050 continue;
02051
02052 LocTriggerData.tg_trigtuple = oldtuple = newtuple;
02053 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
02054 LocTriggerData.tg_trigger = trigger;
02055 newtuple = ExecCallTriggerFunc(&LocTriggerData,
02056 i,
02057 relinfo->ri_TrigFunctions,
02058 relinfo->ri_TrigInstrument,
02059 GetPerTupleMemoryContext(estate));
02060 if (oldtuple != newtuple && oldtuple != slottuple)
02061 heap_freetuple(oldtuple);
02062 if (newtuple == NULL)
02063 return NULL;
02064 }
02065
02066 if (newtuple != slottuple)
02067 {
02068
02069
02070
02071
02072
02073
02074 TupleTableSlot *newslot = estate->es_trig_tuple_slot;
02075 TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
02076
02077 if (newslot->tts_tupleDescriptor != tupdesc)
02078 ExecSetSlotDescriptor(newslot, tupdesc);
02079 ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
02080 slot = newslot;
02081 }
02082 return slot;
02083 }
02084
02085 void
02086 ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
02087 {
02088 TriggerDesc *trigdesc;
02089 int i;
02090 TriggerData LocTriggerData;
02091
02092 trigdesc = relinfo->ri_TrigDesc;
02093
02094 if (trigdesc == NULL)
02095 return;
02096 if (!trigdesc->trig_delete_before_statement)
02097 return;
02098
02099 LocTriggerData.type = T_TriggerData;
02100 LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
02101 TRIGGER_EVENT_BEFORE;
02102 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
02103 LocTriggerData.tg_trigtuple = NULL;
02104 LocTriggerData.tg_newtuple = NULL;
02105 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
02106 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
02107 for (i = 0; i < trigdesc->numtriggers; i++)
02108 {
02109 Trigger *trigger = &trigdesc->triggers[i];
02110 HeapTuple newtuple;
02111
02112 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
02113 TRIGGER_TYPE_STATEMENT,
02114 TRIGGER_TYPE_BEFORE,
02115 TRIGGER_TYPE_DELETE))
02116 continue;
02117 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
02118 NULL, NULL, NULL))
02119 continue;
02120
02121 LocTriggerData.tg_trigger = trigger;
02122 newtuple = ExecCallTriggerFunc(&LocTriggerData,
02123 i,
02124 relinfo->ri_TrigFunctions,
02125 relinfo->ri_TrigInstrument,
02126 GetPerTupleMemoryContext(estate));
02127
02128 if (newtuple)
02129 ereport(ERROR,
02130 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
02131 errmsg("BEFORE STATEMENT trigger cannot return a value")));
02132 }
02133 }
02134
02135 void
02136 ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
02137 {
02138 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02139
02140 if (trigdesc && trigdesc->trig_delete_after_statement)
02141 AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_DELETE,
02142 false, NULL, NULL, NIL, NULL);
02143 }
02144
02145 bool
02146 ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
02147 ResultRelInfo *relinfo,
02148 ItemPointer tupleid)
02149 {
02150 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02151 bool result = true;
02152 TriggerData LocTriggerData;
02153 HeapTuple trigtuple;
02154 HeapTuple newtuple;
02155 TupleTableSlot *newSlot;
02156 int i;
02157
02158 trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
02159 LockTupleExclusive, &newSlot);
02160 if (trigtuple == NULL)
02161 return false;
02162
02163 LocTriggerData.type = T_TriggerData;
02164 LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
02165 TRIGGER_EVENT_ROW |
02166 TRIGGER_EVENT_BEFORE;
02167 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
02168 LocTriggerData.tg_newtuple = NULL;
02169 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
02170 for (i = 0; i < trigdesc->numtriggers; i++)
02171 {
02172 Trigger *trigger = &trigdesc->triggers[i];
02173
02174 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
02175 TRIGGER_TYPE_ROW,
02176 TRIGGER_TYPE_BEFORE,
02177 TRIGGER_TYPE_DELETE))
02178 continue;
02179 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
02180 NULL, trigtuple, NULL))
02181 continue;
02182
02183 LocTriggerData.tg_trigtuple = trigtuple;
02184 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
02185 LocTriggerData.tg_trigger = trigger;
02186 newtuple = ExecCallTriggerFunc(&LocTriggerData,
02187 i,
02188 relinfo->ri_TrigFunctions,
02189 relinfo->ri_TrigInstrument,
02190 GetPerTupleMemoryContext(estate));
02191 if (newtuple == NULL)
02192 {
02193 result = false;
02194 break;
02195 }
02196 if (newtuple != trigtuple)
02197 heap_freetuple(newtuple);
02198 }
02199 heap_freetuple(trigtuple);
02200
02201 return result;
02202 }
02203
02204 void
02205 ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
02206 ItemPointer tupleid)
02207 {
02208 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02209
02210 if (trigdesc && trigdesc->trig_delete_after_row)
02211 {
02212 HeapTuple trigtuple = GetTupleForTrigger(estate, NULL, relinfo,
02213 tupleid, LockTupleExclusive,
02214 NULL);
02215
02216 AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_DELETE,
02217 true, trigtuple, NULL, NIL, NULL);
02218 heap_freetuple(trigtuple);
02219 }
02220 }
02221
02222 bool
02223 ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
02224 HeapTuple trigtuple)
02225 {
02226 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02227 TriggerData LocTriggerData;
02228 HeapTuple rettuple;
02229 int i;
02230
02231 LocTriggerData.type = T_TriggerData;
02232 LocTriggerData.tg_event = TRIGGER_EVENT_DELETE |
02233 TRIGGER_EVENT_ROW |
02234 TRIGGER_EVENT_INSTEAD;
02235 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
02236 LocTriggerData.tg_newtuple = NULL;
02237 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
02238 for (i = 0; i < trigdesc->numtriggers; i++)
02239 {
02240 Trigger *trigger = &trigdesc->triggers[i];
02241
02242 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
02243 TRIGGER_TYPE_ROW,
02244 TRIGGER_TYPE_INSTEAD,
02245 TRIGGER_TYPE_DELETE))
02246 continue;
02247 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
02248 NULL, trigtuple, NULL))
02249 continue;
02250
02251 LocTriggerData.tg_trigtuple = trigtuple;
02252 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
02253 LocTriggerData.tg_trigger = trigger;
02254 rettuple = ExecCallTriggerFunc(&LocTriggerData,
02255 i,
02256 relinfo->ri_TrigFunctions,
02257 relinfo->ri_TrigInstrument,
02258 GetPerTupleMemoryContext(estate));
02259 if (rettuple == NULL)
02260 return false;
02261 if (rettuple != trigtuple)
02262 heap_freetuple(rettuple);
02263 }
02264 return true;
02265 }
02266
02267 void
02268 ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
02269 {
02270 TriggerDesc *trigdesc;
02271 int i;
02272 TriggerData LocTriggerData;
02273 Bitmapset *modifiedCols;
02274
02275 trigdesc = relinfo->ri_TrigDesc;
02276
02277 if (trigdesc == NULL)
02278 return;
02279 if (!trigdesc->trig_update_before_statement)
02280 return;
02281
02282 modifiedCols = GetModifiedColumns(relinfo, estate);
02283
02284 LocTriggerData.type = T_TriggerData;
02285 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
02286 TRIGGER_EVENT_BEFORE;
02287 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
02288 LocTriggerData.tg_trigtuple = NULL;
02289 LocTriggerData.tg_newtuple = NULL;
02290 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
02291 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
02292 for (i = 0; i < trigdesc->numtriggers; i++)
02293 {
02294 Trigger *trigger = &trigdesc->triggers[i];
02295 HeapTuple newtuple;
02296
02297 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
02298 TRIGGER_TYPE_STATEMENT,
02299 TRIGGER_TYPE_BEFORE,
02300 TRIGGER_TYPE_UPDATE))
02301 continue;
02302 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
02303 modifiedCols, NULL, NULL))
02304 continue;
02305
02306 LocTriggerData.tg_trigger = trigger;
02307 newtuple = ExecCallTriggerFunc(&LocTriggerData,
02308 i,
02309 relinfo->ri_TrigFunctions,
02310 relinfo->ri_TrigInstrument,
02311 GetPerTupleMemoryContext(estate));
02312
02313 if (newtuple)
02314 ereport(ERROR,
02315 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
02316 errmsg("BEFORE STATEMENT trigger cannot return a value")));
02317 }
02318 }
02319
02320 void
02321 ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
02322 {
02323 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02324
02325 if (trigdesc && trigdesc->trig_update_after_statement)
02326 AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
02327 false, NULL, NULL, NIL,
02328 GetModifiedColumns(relinfo, estate));
02329 }
02330
02331 TupleTableSlot *
02332 ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
02333 ResultRelInfo *relinfo,
02334 ItemPointer tupleid, TupleTableSlot *slot)
02335 {
02336 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02337 HeapTuple slottuple = ExecMaterializeSlot(slot);
02338 HeapTuple newtuple = slottuple;
02339 TriggerData LocTriggerData;
02340 HeapTuple trigtuple;
02341 HeapTuple oldtuple;
02342 TupleTableSlot *newSlot;
02343 int i;
02344 Bitmapset *modifiedCols;
02345 Bitmapset *keyCols;
02346 LockTupleMode lockmode;
02347
02348
02349
02350
02351
02352
02353 modifiedCols = GetModifiedColumns(relinfo, estate);
02354 keyCols = RelationGetIndexAttrBitmap(relinfo->ri_RelationDesc, true);
02355 if (bms_overlap(keyCols, modifiedCols))
02356 lockmode = LockTupleExclusive;
02357 else
02358 lockmode = LockTupleNoKeyExclusive;
02359
02360
02361 trigtuple = GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
02362 lockmode, &newSlot);
02363 if (trigtuple == NULL)
02364 return NULL;
02365
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377 if (newSlot != NULL)
02378 {
02379 slot = ExecFilterJunk(relinfo->ri_junkFilter, newSlot);
02380 slottuple = ExecMaterializeSlot(slot);
02381 newtuple = slottuple;
02382 }
02383
02384
02385 LocTriggerData.type = T_TriggerData;
02386 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
02387 TRIGGER_EVENT_ROW |
02388 TRIGGER_EVENT_BEFORE;
02389 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
02390 for (i = 0; i < trigdesc->numtriggers; i++)
02391 {
02392 Trigger *trigger = &trigdesc->triggers[i];
02393
02394 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
02395 TRIGGER_TYPE_ROW,
02396 TRIGGER_TYPE_BEFORE,
02397 TRIGGER_TYPE_UPDATE))
02398 continue;
02399 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
02400 modifiedCols, trigtuple, newtuple))
02401 continue;
02402
02403 LocTriggerData.tg_trigtuple = trigtuple;
02404 LocTriggerData.tg_newtuple = oldtuple = newtuple;
02405 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
02406 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
02407 LocTriggerData.tg_trigger = trigger;
02408 newtuple = ExecCallTriggerFunc(&LocTriggerData,
02409 i,
02410 relinfo->ri_TrigFunctions,
02411 relinfo->ri_TrigInstrument,
02412 GetPerTupleMemoryContext(estate));
02413 if (oldtuple != newtuple && oldtuple != slottuple)
02414 heap_freetuple(oldtuple);
02415 if (newtuple == NULL)
02416 {
02417 heap_freetuple(trigtuple);
02418 return NULL;
02419 }
02420 }
02421 heap_freetuple(trigtuple);
02422
02423 if (newtuple != slottuple)
02424 {
02425
02426
02427
02428
02429
02430
02431 TupleTableSlot *newslot = estate->es_trig_tuple_slot;
02432 TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
02433
02434 if (newslot->tts_tupleDescriptor != tupdesc)
02435 ExecSetSlotDescriptor(newslot, tupdesc);
02436 ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
02437 slot = newslot;
02438 }
02439 return slot;
02440 }
02441
02442 void
02443 ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
02444 ItemPointer tupleid, HeapTuple newtuple,
02445 List *recheckIndexes)
02446 {
02447 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02448
02449 if (trigdesc && trigdesc->trig_update_after_row)
02450 {
02451 HeapTuple trigtuple = GetTupleForTrigger(estate, NULL, relinfo,
02452 tupleid, LockTupleExclusive,
02453 NULL);
02454
02455 AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
02456 true, trigtuple, newtuple, recheckIndexes,
02457 GetModifiedColumns(relinfo, estate));
02458 heap_freetuple(trigtuple);
02459 }
02460 }
02461
02462 TupleTableSlot *
02463 ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
02464 HeapTuple trigtuple, TupleTableSlot *slot)
02465 {
02466 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02467 HeapTuple slottuple = ExecMaterializeSlot(slot);
02468 HeapTuple newtuple = slottuple;
02469 TriggerData LocTriggerData;
02470 HeapTuple oldtuple;
02471 int i;
02472
02473 LocTriggerData.type = T_TriggerData;
02474 LocTriggerData.tg_event = TRIGGER_EVENT_UPDATE |
02475 TRIGGER_EVENT_ROW |
02476 TRIGGER_EVENT_INSTEAD;
02477 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
02478 for (i = 0; i < trigdesc->numtriggers; i++)
02479 {
02480 Trigger *trigger = &trigdesc->triggers[i];
02481
02482 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
02483 TRIGGER_TYPE_ROW,
02484 TRIGGER_TYPE_INSTEAD,
02485 TRIGGER_TYPE_UPDATE))
02486 continue;
02487 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
02488 NULL, trigtuple, newtuple))
02489 continue;
02490
02491 LocTriggerData.tg_trigtuple = trigtuple;
02492 LocTriggerData.tg_newtuple = oldtuple = newtuple;
02493 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
02494 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
02495 LocTriggerData.tg_trigger = trigger;
02496 newtuple = ExecCallTriggerFunc(&LocTriggerData,
02497 i,
02498 relinfo->ri_TrigFunctions,
02499 relinfo->ri_TrigInstrument,
02500 GetPerTupleMemoryContext(estate));
02501 if (oldtuple != newtuple && oldtuple != slottuple)
02502 heap_freetuple(oldtuple);
02503 if (newtuple == NULL)
02504 return NULL;
02505 }
02506
02507 if (newtuple != slottuple)
02508 {
02509
02510
02511
02512
02513
02514
02515 TupleTableSlot *newslot = estate->es_trig_tuple_slot;
02516 TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
02517
02518 if (newslot->tts_tupleDescriptor != tupdesc)
02519 ExecSetSlotDescriptor(newslot, tupdesc);
02520 ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
02521 slot = newslot;
02522 }
02523 return slot;
02524 }
02525
02526 void
02527 ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
02528 {
02529 TriggerDesc *trigdesc;
02530 int i;
02531 TriggerData LocTriggerData;
02532
02533 trigdesc = relinfo->ri_TrigDesc;
02534
02535 if (trigdesc == NULL)
02536 return;
02537 if (!trigdesc->trig_truncate_before_statement)
02538 return;
02539
02540 LocTriggerData.type = T_TriggerData;
02541 LocTriggerData.tg_event = TRIGGER_EVENT_TRUNCATE |
02542 TRIGGER_EVENT_BEFORE;
02543 LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
02544 LocTriggerData.tg_trigtuple = NULL;
02545 LocTriggerData.tg_newtuple = NULL;
02546 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
02547 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
02548 for (i = 0; i < trigdesc->numtriggers; i++)
02549 {
02550 Trigger *trigger = &trigdesc->triggers[i];
02551 HeapTuple newtuple;
02552
02553 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
02554 TRIGGER_TYPE_STATEMENT,
02555 TRIGGER_TYPE_BEFORE,
02556 TRIGGER_TYPE_TRUNCATE))
02557 continue;
02558 if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
02559 NULL, NULL, NULL))
02560 continue;
02561
02562 LocTriggerData.tg_trigger = trigger;
02563 newtuple = ExecCallTriggerFunc(&LocTriggerData,
02564 i,
02565 relinfo->ri_TrigFunctions,
02566 relinfo->ri_TrigInstrument,
02567 GetPerTupleMemoryContext(estate));
02568
02569 if (newtuple)
02570 ereport(ERROR,
02571 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
02572 errmsg("BEFORE STATEMENT trigger cannot return a value")));
02573 }
02574 }
02575
02576 void
02577 ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
02578 {
02579 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
02580
02581 if (trigdesc && trigdesc->trig_truncate_after_statement)
02582 AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_TRUNCATE,
02583 false, NULL, NULL, NIL, NULL);
02584 }
02585
02586
02587 static HeapTuple
02588 GetTupleForTrigger(EState *estate,
02589 EPQState *epqstate,
02590 ResultRelInfo *relinfo,
02591 ItemPointer tid,
02592 LockTupleMode lockmode,
02593 TupleTableSlot **newSlot)
02594 {
02595 Relation relation = relinfo->ri_RelationDesc;
02596 HeapTupleData tuple;
02597 HeapTuple result;
02598 Buffer buffer;
02599
02600 if (newSlot != NULL)
02601 {
02602 HTSU_Result test;
02603 HeapUpdateFailureData hufd;
02604
02605 *newSlot = NULL;
02606
02607
02608 Assert(epqstate != NULL);
02609
02610
02611
02612
02613 ltrmark:;
02614 tuple.t_self = *tid;
02615 test = heap_lock_tuple(relation, &tuple,
02616 estate->es_output_cid,
02617 lockmode, false ,
02618 false, &buffer, &hufd);
02619 switch (test)
02620 {
02621 case HeapTupleSelfUpdated:
02622
02623
02624
02625
02626
02627
02628
02629
02630 if (hufd.cmax != estate->es_output_cid)
02631 ereport(ERROR,
02632 (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
02633 errmsg("tuple to be updated was already modified by an operation triggered by the current command"),
02634 errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
02635
02636
02637 ReleaseBuffer(buffer);
02638 return NULL;
02639
02640 case HeapTupleMayBeUpdated:
02641 break;
02642
02643 case HeapTupleUpdated:
02644 ReleaseBuffer(buffer);
02645 if (IsolationUsesXactSnapshot())
02646 ereport(ERROR,
02647 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
02648 errmsg("could not serialize access due to concurrent update")));
02649 if (!ItemPointerEquals(&hufd.ctid, &tuple.t_self))
02650 {
02651
02652 TupleTableSlot *epqslot;
02653
02654 epqslot = EvalPlanQual(estate,
02655 epqstate,
02656 relation,
02657 relinfo->ri_RangeTableIndex,
02658 lockmode,
02659 &hufd.ctid,
02660 hufd.xmax);
02661 if (!TupIsNull(epqslot))
02662 {
02663 *tid = hufd.ctid;
02664 *newSlot = epqslot;
02665
02666
02667
02668
02669
02670
02671
02672 goto ltrmark;
02673 }
02674 }
02675
02676
02677
02678
02679
02680 return NULL;
02681
02682 default:
02683 ReleaseBuffer(buffer);
02684 elog(ERROR, "unrecognized heap_lock_tuple status: %u", test);
02685 return NULL;
02686 }
02687 }
02688 else
02689 {
02690 Page page;
02691 ItemId lp;
02692
02693 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703 LockBuffer(buffer, BUFFER_LOCK_SHARE);
02704
02705 page = BufferGetPage(buffer);
02706 lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
02707
02708 Assert(ItemIdIsNormal(lp));
02709
02710 tuple.t_data = (HeapTupleHeader) PageGetItem(page, lp);
02711 tuple.t_len = ItemIdGetLength(lp);
02712 tuple.t_self = *tid;
02713 tuple.t_tableOid = RelationGetRelid(relation);
02714
02715 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
02716 }
02717
02718 result = heap_copytuple(&tuple);
02719 ReleaseBuffer(buffer);
02720
02721 return result;
02722 }
02723
02724
02725
02726
02727 static bool
02728 TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
02729 Trigger *trigger, TriggerEvent event,
02730 Bitmapset *modifiedCols,
02731 HeapTuple oldtup, HeapTuple newtup)
02732 {
02733
02734 if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
02735 {
02736 if (trigger->tgenabled == TRIGGER_FIRES_ON_ORIGIN ||
02737 trigger->tgenabled == TRIGGER_DISABLED)
02738 return false;
02739 }
02740 else
02741 {
02742 if (trigger->tgenabled == TRIGGER_FIRES_ON_REPLICA ||
02743 trigger->tgenabled == TRIGGER_DISABLED)
02744 return false;
02745 }
02746
02747
02748
02749
02750
02751 if (trigger->tgnattr > 0 && TRIGGER_FIRED_BY_UPDATE(event))
02752 {
02753 int i;
02754 bool modified;
02755
02756 modified = false;
02757 for (i = 0; i < trigger->tgnattr; i++)
02758 {
02759 if (bms_is_member(trigger->tgattr[i] - FirstLowInvalidHeapAttributeNumber,
02760 modifiedCols))
02761 {
02762 modified = true;
02763 break;
02764 }
02765 }
02766 if (!modified)
02767 return false;
02768 }
02769
02770
02771 if (trigger->tgqual)
02772 {
02773 TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
02774 List **predicate;
02775 ExprContext *econtext;
02776 TupleTableSlot *oldslot = NULL;
02777 TupleTableSlot *newslot = NULL;
02778 MemoryContext oldContext;
02779 int i;
02780
02781 Assert(estate != NULL);
02782
02783
02784
02785
02786
02787 i = trigger - relinfo->ri_TrigDesc->triggers;
02788 predicate = &relinfo->ri_TrigWhenExprs[i];
02789
02790
02791
02792
02793
02794
02795 if (*predicate == NIL)
02796 {
02797 Node *tgqual;
02798
02799 oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
02800 tgqual = stringToNode(trigger->tgqual);
02801
02802 ChangeVarNodes(tgqual, PRS2_OLD_VARNO, INNER_VAR, 0);
02803 ChangeVarNodes(tgqual, PRS2_NEW_VARNO, OUTER_VAR, 0);
02804
02805 tgqual = (Node *) make_ands_implicit((Expr *) tgqual);
02806 *predicate = (List *) ExecPrepareExpr((Expr *) tgqual, estate);
02807 MemoryContextSwitchTo(oldContext);
02808 }
02809
02810
02811
02812
02813
02814 econtext = GetPerTupleExprContext(estate);
02815
02816
02817
02818
02819
02820
02821 if (HeapTupleIsValid(oldtup))
02822 {
02823 if (estate->es_trig_oldtup_slot == NULL)
02824 {
02825 oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
02826 estate->es_trig_oldtup_slot = ExecInitExtraTupleSlot(estate);
02827 MemoryContextSwitchTo(oldContext);
02828 }
02829 oldslot = estate->es_trig_oldtup_slot;
02830 if (oldslot->tts_tupleDescriptor != tupdesc)
02831 ExecSetSlotDescriptor(oldslot, tupdesc);
02832 ExecStoreTuple(oldtup, oldslot, InvalidBuffer, false);
02833 }
02834 if (HeapTupleIsValid(newtup))
02835 {
02836 if (estate->es_trig_newtup_slot == NULL)
02837 {
02838 oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
02839 estate->es_trig_newtup_slot = ExecInitExtraTupleSlot(estate);
02840 MemoryContextSwitchTo(oldContext);
02841 }
02842 newslot = estate->es_trig_newtup_slot;
02843 if (newslot->tts_tupleDescriptor != tupdesc)
02844 ExecSetSlotDescriptor(newslot, tupdesc);
02845 ExecStoreTuple(newtup, newslot, InvalidBuffer, false);
02846 }
02847
02848
02849
02850
02851
02852 econtext->ecxt_innertuple = oldslot;
02853 econtext->ecxt_outertuple = newslot;
02854 if (!ExecQual(*predicate, econtext, false))
02855 return false;
02856 }
02857
02858 return true;
02859 }
02860
02861
02862
02863
02864
02865
02866
02867
02868
02869
02870
02871
02872
02873
02874
02875
02876
02877
02878
02879
02880
02881
02882
02883
02884 typedef struct SetConstraintTriggerData
02885 {
02886 Oid sct_tgoid;
02887 bool sct_tgisdeferred;
02888 } SetConstraintTriggerData;
02889
02890 typedef struct SetConstraintTriggerData *SetConstraintTrigger;
02891
02892
02893
02894
02895
02896
02897
02898
02899
02900
02901
02902 typedef struct SetConstraintStateData
02903 {
02904 bool all_isset;
02905 bool all_isdeferred;
02906 int numstates;
02907 int numalloc;
02908 SetConstraintTriggerData trigstates[1];
02909 } SetConstraintStateData;
02910
02911 typedef SetConstraintStateData *SetConstraintState;
02912
02913
02914
02915
02916
02917
02918
02919
02920
02921
02922
02923
02924
02925
02926
02927
02928
02929
02930
02931
02932
02933
02934
02935 typedef uint32 TriggerFlags;
02936
02937 #define AFTER_TRIGGER_OFFSET 0x0FFFFFFF
02938
02939 #define AFTER_TRIGGER_2CTIDS 0x10000000
02940 #define AFTER_TRIGGER_DONE 0x20000000
02941 #define AFTER_TRIGGER_IN_PROGRESS 0x40000000
02942
02943 typedef struct AfterTriggerSharedData *AfterTriggerShared;
02944
02945 typedef struct AfterTriggerSharedData
02946 {
02947 TriggerEvent ats_event;
02948 Oid ats_tgoid;
02949 Oid ats_relid;
02950 CommandId ats_firing_id;
02951 } AfterTriggerSharedData;
02952
02953 typedef struct AfterTriggerEventData *AfterTriggerEvent;
02954
02955 typedef struct AfterTriggerEventData
02956 {
02957 TriggerFlags ate_flags;
02958 ItemPointerData ate_ctid1;
02959 ItemPointerData ate_ctid2;
02960 } AfterTriggerEventData;
02961
02962
02963 typedef struct AfterTriggerEventDataOneCtid
02964 {
02965 TriggerFlags ate_flags;
02966 ItemPointerData ate_ctid1;
02967 } AfterTriggerEventDataOneCtid;
02968
02969 #define SizeofTriggerEvent(evt) \
02970 (((evt)->ate_flags & AFTER_TRIGGER_2CTIDS) ? \
02971 sizeof(AfterTriggerEventData) : sizeof(AfterTriggerEventDataOneCtid))
02972
02973 #define GetTriggerSharedData(evt) \
02974 ((AfterTriggerShared) ((char *) (evt) + ((evt)->ate_flags & AFTER_TRIGGER_OFFSET)))
02975
02976
02977
02978
02979
02980
02981
02982
02983 typedef struct AfterTriggerEventChunk
02984 {
02985 struct AfterTriggerEventChunk *next;
02986 char *freeptr;
02987 char *endfree;
02988 char *endptr;
02989
02990 } AfterTriggerEventChunk;
02991
02992 #define CHUNK_DATA_START(cptr) ((char *) (cptr) + MAXALIGN(sizeof(AfterTriggerEventChunk)))
02993
02994
02995 typedef struct AfterTriggerEventList
02996 {
02997 AfterTriggerEventChunk *head;
02998 AfterTriggerEventChunk *tail;
02999 char *tailfree;
03000 } AfterTriggerEventList;
03001
03002
03003 #define for_each_chunk(cptr, evtlist) \
03004 for (cptr = (evtlist).head; cptr != NULL; cptr = cptr->next)
03005 #define for_each_event(eptr, cptr) \
03006 for (eptr = (AfterTriggerEvent) CHUNK_DATA_START(cptr); \
03007 (char *) eptr < (cptr)->freeptr; \
03008 eptr = (AfterTriggerEvent) (((char *) eptr) + SizeofTriggerEvent(eptr)))
03009
03010 #define for_each_event_chunk(eptr, cptr, evtlist) \
03011 for_each_chunk(cptr, evtlist) for_each_event(eptr, cptr)
03012
03013
03014
03015
03016
03017
03018
03019
03020
03021
03022
03023
03024
03025
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042
03043
03044
03045
03046
03047
03048
03049
03050
03051
03052
03053
03054
03055
03056
03057
03058
03059
03060
03061
03062
03063
03064
03065
03066 typedef struct AfterTriggersData
03067 {
03068 CommandId firing_counter;
03069 SetConstraintState state;
03070 AfterTriggerEventList events;
03071 int query_depth;
03072 AfterTriggerEventList *query_stack;
03073 int maxquerydepth;
03074 MemoryContext event_cxt;
03075
03076
03077
03078 SetConstraintState *state_stack;
03079 AfterTriggerEventList *events_stack;
03080 int *depth_stack;
03081 CommandId *firing_stack;
03082 int maxtransdepth;
03083 } AfterTriggersData;
03084
03085 typedef AfterTriggersData *AfterTriggers;
03086
03087 static AfterTriggers afterTriggers;
03088
03089
03090 static void AfterTriggerExecute(AfterTriggerEvent event,
03091 Relation rel, TriggerDesc *trigdesc,
03092 FmgrInfo *finfo,
03093 Instrumentation *instr,
03094 MemoryContext per_tuple_context);
03095 static SetConstraintState SetConstraintStateCreate(int numalloc);
03096 static SetConstraintState SetConstraintStateCopy(SetConstraintState state);
03097 static SetConstraintState SetConstraintStateAddItem(SetConstraintState state,
03098 Oid tgoid, bool tgisdeferred);
03099
03100
03101
03102
03103
03104
03105
03106
03107 static bool
03108 afterTriggerCheckState(AfterTriggerShared evtshared)
03109 {
03110 Oid tgoid = evtshared->ats_tgoid;
03111 SetConstraintState state = afterTriggers->state;
03112 int i;
03113
03114
03115
03116
03117
03118 if ((evtshared->ats_event & AFTER_TRIGGER_DEFERRABLE) == 0)
03119 return false;
03120
03121
03122
03123
03124 for (i = 0; i < state->numstates; i++)
03125 {
03126 if (state->trigstates[i].sct_tgoid == tgoid)
03127 return state->trigstates[i].sct_tgisdeferred;
03128 }
03129
03130
03131
03132
03133 if (state->all_isset)
03134 return state->all_isdeferred;
03135
03136
03137
03138
03139 return ((evtshared->ats_event & AFTER_TRIGGER_INITDEFERRED) != 0);
03140 }
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150 static void
03151 afterTriggerAddEvent(AfterTriggerEventList *events,
03152 AfterTriggerEvent event, AfterTriggerShared evtshared)
03153 {
03154 Size eventsize = SizeofTriggerEvent(event);
03155 Size needed = eventsize + sizeof(AfterTriggerSharedData);
03156 AfterTriggerEventChunk *chunk;
03157 AfterTriggerShared newshared;
03158 AfterTriggerEvent newevent;
03159
03160
03161
03162
03163
03164 chunk = events->tail;
03165 if (chunk == NULL ||
03166 chunk->endfree - chunk->freeptr < needed)
03167 {
03168 Size chunksize;
03169
03170
03171 if (afterTriggers->event_cxt == NULL)
03172 afterTriggers->event_cxt =
03173 AllocSetContextCreate(TopTransactionContext,
03174 "AfterTriggerEvents",
03175 ALLOCSET_DEFAULT_MINSIZE,
03176 ALLOCSET_DEFAULT_INITSIZE,
03177 ALLOCSET_DEFAULT_MAXSIZE);
03178
03179
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189
03190
03191
03192
03193
03194 #define MIN_CHUNK_SIZE 1024
03195 #define MAX_CHUNK_SIZE (1024*1024)
03196
03197 #if MAX_CHUNK_SIZE > (AFTER_TRIGGER_OFFSET+1)
03198 #error MAX_CHUNK_SIZE must not exceed AFTER_TRIGGER_OFFSET
03199 #endif
03200
03201 if (chunk == NULL)
03202 chunksize = MIN_CHUNK_SIZE;
03203 else
03204 {
03205
03206 chunksize = chunk->endptr - (char *) chunk;
03207
03208 if ((chunk->endptr - chunk->endfree) <=
03209 (100 * sizeof(AfterTriggerSharedData)))
03210 chunksize *= 2;
03211 else
03212 chunksize /= 2;
03213 chunksize = Min(chunksize, MAX_CHUNK_SIZE);
03214 }
03215 chunk = MemoryContextAlloc(afterTriggers->event_cxt, chunksize);
03216 chunk->next = NULL;
03217 chunk->freeptr = CHUNK_DATA_START(chunk);
03218 chunk->endptr = chunk->endfree = (char *) chunk + chunksize;
03219 Assert(chunk->endfree - chunk->freeptr >= needed);
03220
03221 if (events->head == NULL)
03222 events->head = chunk;
03223 else
03224 events->tail->next = chunk;
03225 events->tail = chunk;
03226
03227 }
03228
03229
03230
03231
03232
03233 for (newshared = ((AfterTriggerShared) chunk->endptr) - 1;
03234 (char *) newshared >= chunk->endfree;
03235 newshared--)
03236 {
03237 if (newshared->ats_tgoid == evtshared->ats_tgoid &&
03238 newshared->ats_relid == evtshared->ats_relid &&
03239 newshared->ats_event == evtshared->ats_event &&
03240 newshared->ats_firing_id == 0)
03241 break;
03242 }
03243 if ((char *) newshared < chunk->endfree)
03244 {
03245 *newshared = *evtshared;
03246 newshared->ats_firing_id = 0;
03247 chunk->endfree = (char *) newshared;
03248 }
03249
03250
03251 newevent = (AfterTriggerEvent) chunk->freeptr;
03252 memcpy(newevent, event, eventsize);
03253
03254 newevent->ate_flags &= ~AFTER_TRIGGER_OFFSET;
03255 newevent->ate_flags |= (char *) newshared - (char *) newevent;
03256
03257 chunk->freeptr += eventsize;
03258 events->tailfree = chunk->freeptr;
03259 }
03260
03261
03262
03263
03264
03265
03266
03267 static void
03268 afterTriggerFreeEventList(AfterTriggerEventList *events)
03269 {
03270 AfterTriggerEventChunk *chunk;
03271 AfterTriggerEventChunk *next_chunk;
03272
03273 for (chunk = events->head; chunk != NULL; chunk = next_chunk)
03274 {
03275 next_chunk = chunk->next;
03276 pfree(chunk);
03277 }
03278 events->head = NULL;
03279 events->tail = NULL;
03280 events->tailfree = NULL;
03281 }
03282
03283
03284
03285
03286
03287
03288
03289
03290 static void
03291 afterTriggerRestoreEventList(AfterTriggerEventList *events,
03292 const AfterTriggerEventList *old_events)
03293 {
03294 AfterTriggerEventChunk *chunk;
03295 AfterTriggerEventChunk *next_chunk;
03296
03297 if (old_events->tail == NULL)
03298 {
03299
03300 afterTriggerFreeEventList(events);
03301 }
03302 else
03303 {
03304 *events = *old_events;
03305
03306 for (chunk = events->tail->next; chunk != NULL; chunk = next_chunk)
03307 {
03308 next_chunk = chunk->next;
03309 pfree(chunk);
03310 }
03311
03312 events->tail->next = NULL;
03313 events->tail->freeptr = events->tailfree;
03314
03315
03316
03317
03318
03319 }
03320 }
03321
03322
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343 static void
03344 AfterTriggerExecute(AfterTriggerEvent event,
03345 Relation rel, TriggerDesc *trigdesc,
03346 FmgrInfo *finfo, Instrumentation *instr,
03347 MemoryContext per_tuple_context)
03348 {
03349 AfterTriggerShared evtshared = GetTriggerSharedData(event);
03350 Oid tgoid = evtshared->ats_tgoid;
03351 TriggerData LocTriggerData;
03352 HeapTupleData tuple1;
03353 HeapTupleData tuple2;
03354 HeapTuple rettuple;
03355 Buffer buffer1 = InvalidBuffer;
03356 Buffer buffer2 = InvalidBuffer;
03357 int tgindx;
03358
03359
03360
03361
03362 LocTriggerData.tg_trigger = NULL;
03363 for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
03364 {
03365 if (trigdesc->triggers[tgindx].tgoid == tgoid)
03366 {
03367 LocTriggerData.tg_trigger = &(trigdesc->triggers[tgindx]);
03368 break;
03369 }
03370 }
03371 if (LocTriggerData.tg_trigger == NULL)
03372 elog(ERROR, "could not find trigger %u", tgoid);
03373
03374
03375
03376
03377
03378 if (instr)
03379 InstrStartNode(instr + tgindx);
03380
03381
03382
03383
03384 if (ItemPointerIsValid(&(event->ate_ctid1)))
03385 {
03386 ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
03387 if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer1, false, NULL))
03388 elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
03389 LocTriggerData.tg_trigtuple = &tuple1;
03390 LocTriggerData.tg_trigtuplebuf = buffer1;
03391 }
03392 else
03393 {
03394 LocTriggerData.tg_trigtuple = NULL;
03395 LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
03396 }
03397
03398
03399 if ((event->ate_flags & AFTER_TRIGGER_2CTIDS) &&
03400 ItemPointerIsValid(&(event->ate_ctid2)))
03401 {
03402 ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
03403 if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer2, false, NULL))
03404 elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
03405 LocTriggerData.tg_newtuple = &tuple2;
03406 LocTriggerData.tg_newtuplebuf = buffer2;
03407 }
03408 else
03409 {
03410 LocTriggerData.tg_newtuple = NULL;
03411 LocTriggerData.tg_newtuplebuf = InvalidBuffer;
03412 }
03413
03414
03415
03416
03417 LocTriggerData.type = T_TriggerData;
03418 LocTriggerData.tg_event =
03419 evtshared->ats_event & (TRIGGER_EVENT_OPMASK | TRIGGER_EVENT_ROW);
03420 LocTriggerData.tg_relation = rel;
03421
03422 MemoryContextReset(per_tuple_context);
03423
03424
03425
03426
03427
03428 rettuple = ExecCallTriggerFunc(&LocTriggerData,
03429 tgindx,
03430 finfo,
03431 NULL,
03432 per_tuple_context);
03433 if (rettuple != NULL && rettuple != &tuple1 && rettuple != &tuple2)
03434 heap_freetuple(rettuple);
03435
03436
03437
03438
03439 if (buffer1 != InvalidBuffer)
03440 ReleaseBuffer(buffer1);
03441 if (buffer2 != InvalidBuffer)
03442 ReleaseBuffer(buffer2);
03443
03444
03445
03446
03447
03448 if (instr)
03449 InstrStopNode(instr + tgindx, 1);
03450 }
03451
03452
03453
03454
03455
03456
03457
03458
03459
03460
03461
03462
03463
03464
03465
03466
03467 static bool
03468 afterTriggerMarkEvents(AfterTriggerEventList *events,
03469 AfterTriggerEventList *move_list,
03470 bool immediate_only)
03471 {
03472 bool found = false;
03473 AfterTriggerEvent event;
03474 AfterTriggerEventChunk *chunk;
03475
03476 for_each_event_chunk(event, chunk, *events)
03477 {
03478 AfterTriggerShared evtshared = GetTriggerSharedData(event);
03479 bool defer_it = false;
03480
03481 if (!(event->ate_flags &
03482 (AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS)))
03483 {
03484
03485
03486
03487
03488 if (immediate_only && afterTriggerCheckState(evtshared))
03489 {
03490 defer_it = true;
03491 }
03492 else
03493 {
03494
03495
03496
03497 evtshared->ats_firing_id = afterTriggers->firing_counter;
03498 event->ate_flags |= AFTER_TRIGGER_IN_PROGRESS;
03499 found = true;
03500 }
03501 }
03502
03503
03504
03505
03506 if (defer_it && move_list != NULL)
03507 {
03508
03509 afterTriggerAddEvent(move_list, event, evtshared);
03510
03511 event->ate_flags |= AFTER_TRIGGER_DONE;
03512 }
03513 }
03514
03515 return found;
03516 }
03517
03518
03519
03520
03521
03522
03523
03524
03525
03526
03527
03528
03529
03530
03531
03532
03533
03534
03535
03536
03537
03538
03539 static bool
03540 afterTriggerInvokeEvents(AfterTriggerEventList *events,
03541 CommandId firing_id,
03542 EState *estate,
03543 bool delete_ok)
03544 {
03545 bool all_fired = true;
03546 AfterTriggerEventChunk *chunk;
03547 MemoryContext per_tuple_context;
03548 bool local_estate = false;
03549 Relation rel = NULL;
03550 TriggerDesc *trigdesc = NULL;
03551 FmgrInfo *finfo = NULL;
03552 Instrumentation *instr = NULL;
03553
03554
03555 if (estate == NULL)
03556 {
03557 estate = CreateExecutorState();
03558 local_estate = true;
03559 }
03560
03561
03562 per_tuple_context =
03563 AllocSetContextCreate(CurrentMemoryContext,
03564 "AfterTriggerTupleContext",
03565 ALLOCSET_DEFAULT_MINSIZE,
03566 ALLOCSET_DEFAULT_INITSIZE,
03567 ALLOCSET_DEFAULT_MAXSIZE);
03568
03569 for_each_chunk(chunk, *events)
03570 {
03571 AfterTriggerEvent event;
03572 bool all_fired_in_chunk = true;
03573
03574 for_each_event(event, chunk)
03575 {
03576 AfterTriggerShared evtshared = GetTriggerSharedData(event);
03577
03578
03579
03580
03581 if ((event->ate_flags & AFTER_TRIGGER_IN_PROGRESS) &&
03582 evtshared->ats_firing_id == firing_id)
03583 {
03584
03585
03586
03587
03588 if (rel == NULL || RelationGetRelid(rel) != evtshared->ats_relid)
03589 {
03590 ResultRelInfo *rInfo;
03591
03592 rInfo = ExecGetTriggerResultRel(estate, evtshared->ats_relid);
03593 rel = rInfo->ri_RelationDesc;
03594 trigdesc = rInfo->ri_TrigDesc;
03595 finfo = rInfo->ri_TrigFunctions;
03596 instr = rInfo->ri_TrigInstrument;
03597 if (trigdesc == NULL)
03598 elog(ERROR, "relation %u has no triggers",
03599 evtshared->ats_relid);
03600 }
03601
03602
03603
03604
03605
03606
03607 AfterTriggerExecute(event, rel, trigdesc, finfo, instr,
03608 per_tuple_context);
03609
03610
03611
03612
03613 event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
03614 event->ate_flags |= AFTER_TRIGGER_DONE;
03615 }
03616 else if (!(event->ate_flags & AFTER_TRIGGER_DONE))
03617 {
03618
03619 all_fired = all_fired_in_chunk = false;
03620 }
03621 }
03622
03623
03624 if (delete_ok && all_fired_in_chunk)
03625 {
03626 chunk->freeptr = CHUNK_DATA_START(chunk);
03627 chunk->endfree = chunk->endptr;
03628
03629
03630
03631
03632
03633
03634
03635 if (chunk == events->tail)
03636 events->tailfree = chunk->freeptr;
03637 }
03638 }
03639
03640
03641 MemoryContextDelete(per_tuple_context);
03642
03643 if (local_estate)
03644 {
03645 ListCell *l;
03646
03647 foreach(l, estate->es_trig_target_relations)
03648 {
03649 ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
03650
03651
03652 ExecCloseIndices(resultRelInfo);
03653 heap_close(resultRelInfo->ri_RelationDesc, NoLock);
03654 }
03655 FreeExecutorState(estate);
03656 }
03657
03658 return all_fired;
03659 }
03660
03661
03662
03663
03664
03665
03666
03667
03668
03669 void
03670 AfterTriggerBeginXact(void)
03671 {
03672 Assert(afterTriggers == NULL);
03673
03674
03675
03676
03677 afterTriggers = (AfterTriggers)
03678 MemoryContextAlloc(TopTransactionContext,
03679 sizeof(AfterTriggersData));
03680
03681 afterTriggers->firing_counter = (CommandId) 1;
03682 afterTriggers->state = SetConstraintStateCreate(8);
03683 afterTriggers->events.head = NULL;
03684 afterTriggers->events.tail = NULL;
03685 afterTriggers->events.tailfree = NULL;
03686 afterTriggers->query_depth = -1;
03687
03688
03689 afterTriggers->query_stack = (AfterTriggerEventList *)
03690 MemoryContextAlloc(TopTransactionContext,
03691 8 * sizeof(AfterTriggerEventList));
03692 afterTriggers->maxquerydepth = 8;
03693
03694
03695 afterTriggers->event_cxt = NULL;
03696
03697
03698 afterTriggers->state_stack = NULL;
03699 afterTriggers->events_stack = NULL;
03700 afterTriggers->depth_stack = NULL;
03701 afterTriggers->firing_stack = NULL;
03702 afterTriggers->maxtransdepth = 0;
03703 }
03704
03705
03706
03707
03708
03709
03710
03711
03712
03713
03714
03715 void
03716 AfterTriggerBeginQuery(void)
03717 {
03718 AfterTriggerEventList *events;
03719
03720
03721 Assert(afterTriggers != NULL);
03722
03723
03724 afterTriggers->query_depth++;
03725
03726
03727
03728
03729 if (afterTriggers->query_depth >= afterTriggers->maxquerydepth)
03730 {
03731
03732 int new_alloc = afterTriggers->maxquerydepth * 2;
03733
03734 afterTriggers->query_stack = (AfterTriggerEventList *)
03735 repalloc(afterTriggers->query_stack,
03736 new_alloc * sizeof(AfterTriggerEventList));
03737 afterTriggers->maxquerydepth = new_alloc;
03738 }
03739
03740
03741 events = &afterTriggers->query_stack[afterTriggers->query_depth];
03742 events->head = NULL;
03743 events->tail = NULL;
03744 events->tailfree = NULL;
03745 }
03746
03747
03748
03749
03750
03751
03752
03753
03754
03755
03756
03757
03758
03759
03760 void
03761 AfterTriggerEndQuery(EState *estate)
03762 {
03763 AfterTriggerEventList *events;
03764
03765
03766 Assert(afterTriggers != NULL);
03767
03768
03769 Assert(afterTriggers->query_depth >= 0);
03770
03771
03772
03773
03774
03775
03776
03777
03778
03779
03780
03781
03782
03783
03784
03785
03786
03787
03788
03789 for (;;)
03790 {
03791 events = &afterTriggers->query_stack[afterTriggers->query_depth];
03792 if (afterTriggerMarkEvents(events, &afterTriggers->events, true))
03793 {
03794 CommandId firing_id = afterTriggers->firing_counter++;
03795
03796
03797 if (afterTriggerInvokeEvents(events, firing_id, estate, true))
03798 break;
03799 }
03800 else
03801 break;
03802 }
03803
03804
03805 afterTriggerFreeEventList(&afterTriggers->query_stack[afterTriggers->query_depth]);
03806
03807 afterTriggers->query_depth--;
03808 }
03809
03810
03811
03812
03813
03814
03815
03816
03817
03818
03819
03820
03821
03822 void
03823 AfterTriggerFireDeferred(void)
03824 {
03825 AfterTriggerEventList *events;
03826 bool snap_pushed = false;
03827
03828
03829 Assert(afterTriggers != NULL);
03830
03831
03832 Assert(afterTriggers->query_depth == -1);
03833
03834
03835
03836
03837
03838
03839 events = &afterTriggers->events;
03840 if (events->head != NULL)
03841 {
03842 PushActiveSnapshot(GetTransactionSnapshot());
03843 snap_pushed = true;
03844 }
03845
03846
03847
03848
03849
03850 while (afterTriggerMarkEvents(events, NULL, false))
03851 {
03852 CommandId firing_id = afterTriggers->firing_counter++;
03853
03854 if (afterTriggerInvokeEvents(events, firing_id, NULL, true))
03855 break;
03856 }
03857
03858
03859
03860
03861
03862
03863 if (snap_pushed)
03864 PopActiveSnapshot();
03865 }
03866
03867
03868
03869
03870
03871
03872
03873
03874
03875
03876
03877
03878
03879
03880
03881 void
03882 AfterTriggerEndXact(bool isCommit)
03883 {
03884
03885
03886
03887
03888
03889
03890
03891
03892
03893 if (afterTriggers && afterTriggers->event_cxt)
03894 MemoryContextDelete(afterTriggers->event_cxt);
03895
03896 afterTriggers = NULL;
03897 }
03898
03899
03900
03901
03902
03903
03904 void
03905 AfterTriggerBeginSubXact(void)
03906 {
03907 int my_level = GetCurrentTransactionNestLevel();
03908
03909
03910
03911
03912
03913 if (afterTriggers == NULL)
03914 return;
03915
03916
03917
03918
03919
03920
03921 while (my_level >= afterTriggers->maxtransdepth)
03922 {
03923 if (afterTriggers->maxtransdepth == 0)
03924 {
03925 MemoryContext old_cxt;
03926
03927 old_cxt = MemoryContextSwitchTo(TopTransactionContext);
03928
03929 #define DEFTRIG_INITALLOC 8
03930 afterTriggers->state_stack = (SetConstraintState *)
03931 palloc(DEFTRIG_INITALLOC * sizeof(SetConstraintState));
03932 afterTriggers->events_stack = (AfterTriggerEventList *)
03933 palloc(DEFTRIG_INITALLOC * sizeof(AfterTriggerEventList));
03934 afterTriggers->depth_stack = (int *)
03935 palloc(DEFTRIG_INITALLOC * sizeof(int));
03936 afterTriggers->firing_stack = (CommandId *)
03937 palloc(DEFTRIG_INITALLOC * sizeof(CommandId));
03938 afterTriggers->maxtransdepth = DEFTRIG_INITALLOC;
03939
03940 MemoryContextSwitchTo(old_cxt);
03941 }
03942 else
03943 {
03944
03945 int new_alloc = afterTriggers->maxtransdepth * 2;
03946
03947 afterTriggers->state_stack = (SetConstraintState *)
03948 repalloc(afterTriggers->state_stack,
03949 new_alloc * sizeof(SetConstraintState));
03950 afterTriggers->events_stack = (AfterTriggerEventList *)
03951 repalloc(afterTriggers->events_stack,
03952 new_alloc * sizeof(AfterTriggerEventList));
03953 afterTriggers->depth_stack = (int *)
03954 repalloc(afterTriggers->depth_stack,
03955 new_alloc * sizeof(int));
03956 afterTriggers->firing_stack = (CommandId *)
03957 repalloc(afterTriggers->firing_stack,
03958 new_alloc * sizeof(CommandId));
03959 afterTriggers->maxtransdepth = new_alloc;
03960 }
03961 }
03962
03963
03964
03965
03966
03967
03968 afterTriggers->state_stack[my_level] = NULL;
03969 afterTriggers->events_stack[my_level] = afterTriggers->events;
03970 afterTriggers->depth_stack[my_level] = afterTriggers->query_depth;
03971 afterTriggers->firing_stack[my_level] = afterTriggers->firing_counter;
03972 }
03973
03974
03975
03976
03977
03978
03979 void
03980 AfterTriggerEndSubXact(bool isCommit)
03981 {
03982 int my_level = GetCurrentTransactionNestLevel();
03983 SetConstraintState state;
03984 AfterTriggerEvent event;
03985 AfterTriggerEventChunk *chunk;
03986 CommandId subxact_firing_id;
03987
03988
03989
03990
03991
03992 if (afterTriggers == NULL)
03993 return;
03994
03995
03996
03997
03998 if (isCommit)
03999 {
04000 Assert(my_level < afterTriggers->maxtransdepth);
04001
04002 state = afterTriggers->state_stack[my_level];
04003 if (state != NULL)
04004 pfree(state);
04005
04006 afterTriggers->state_stack[my_level] = NULL;
04007 Assert(afterTriggers->query_depth ==
04008 afterTriggers->depth_stack[my_level]);
04009 }
04010 else
04011 {
04012
04013
04014
04015
04016
04017 if (my_level >= afterTriggers->maxtransdepth)
04018 return;
04019
04020
04021
04022
04023
04024 while (afterTriggers->query_depth > afterTriggers->depth_stack[my_level])
04025 {
04026 afterTriggerFreeEventList(&afterTriggers->query_stack[afterTriggers->query_depth]);
04027 afterTriggers->query_depth--;
04028 }
04029 Assert(afterTriggers->query_depth ==
04030 afterTriggers->depth_stack[my_level]);
04031
04032
04033
04034
04035
04036 afterTriggerRestoreEventList(&afterTriggers->events,
04037 &afterTriggers->events_stack[my_level]);
04038
04039
04040
04041
04042
04043 state = afterTriggers->state_stack[my_level];
04044 if (state != NULL)
04045 {
04046 pfree(afterTriggers->state);
04047 afterTriggers->state = state;
04048 }
04049
04050 afterTriggers->state_stack[my_level] = NULL;
04051
04052
04053
04054
04055
04056
04057
04058
04059
04060 subxact_firing_id = afterTriggers->firing_stack[my_level];
04061 for_each_event_chunk(event, chunk, afterTriggers->events)
04062 {
04063 AfterTriggerShared evtshared = GetTriggerSharedData(event);
04064
04065 if (event->ate_flags &
04066 (AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS))
04067 {
04068 if (evtshared->ats_firing_id >= subxact_firing_id)
04069 event->ate_flags &=
04070 ~(AFTER_TRIGGER_DONE | AFTER_TRIGGER_IN_PROGRESS);
04071 }
04072 }
04073 }
04074 }
04075
04076
04077
04078
04079 static SetConstraintState
04080 SetConstraintStateCreate(int numalloc)
04081 {
04082 SetConstraintState state;
04083
04084
04085 if (numalloc <= 0)
04086 numalloc = 1;
04087
04088
04089
04090
04091 state = (SetConstraintState)
04092 MemoryContextAllocZero(TopTransactionContext,
04093 sizeof(SetConstraintStateData) +
04094 (numalloc - 1) *sizeof(SetConstraintTriggerData));
04095
04096 state->numalloc = numalloc;
04097
04098 return state;
04099 }
04100
04101
04102
04103
04104 static SetConstraintState
04105 SetConstraintStateCopy(SetConstraintState origstate)
04106 {
04107 SetConstraintState state;
04108
04109 state = SetConstraintStateCreate(origstate->numstates);
04110
04111 state->all_isset = origstate->all_isset;
04112 state->all_isdeferred = origstate->all_isdeferred;
04113 state->numstates = origstate->numstates;
04114 memcpy(state->trigstates, origstate->trigstates,
04115 origstate->numstates * sizeof(SetConstraintTriggerData));
04116
04117 return state;
04118 }
04119
04120
04121
04122
04123
04124 static SetConstraintState
04125 SetConstraintStateAddItem(SetConstraintState state,
04126 Oid tgoid, bool tgisdeferred)
04127 {
04128 if (state->numstates >= state->numalloc)
04129 {
04130 int newalloc = state->numalloc * 2;
04131
04132 newalloc = Max(newalloc, 8);
04133 state = (SetConstraintState)
04134 repalloc(state,
04135 sizeof(SetConstraintStateData) +
04136 (newalloc - 1) *sizeof(SetConstraintTriggerData));
04137 state->numalloc = newalloc;
04138 Assert(state->numstates < state->numalloc);
04139 }
04140
04141 state->trigstates[state->numstates].sct_tgoid = tgoid;
04142 state->trigstates[state->numstates].sct_tgisdeferred = tgisdeferred;
04143 state->numstates++;
04144
04145 return state;
04146 }
04147
04148
04149
04150
04151
04152
04153
04154 void
04155 AfterTriggerSetState(ConstraintsSetStmt *stmt)
04156 {
04157 int my_level = GetCurrentTransactionNestLevel();
04158
04159
04160
04161
04162 if (afterTriggers == NULL)
04163 return;
04164
04165
04166
04167
04168
04169 if (my_level > 1 &&
04170 afterTriggers->state_stack[my_level] == NULL)
04171 {
04172 afterTriggers->state_stack[my_level] =
04173 SetConstraintStateCopy(afterTriggers->state);
04174 }
04175
04176
04177
04178
04179 if (stmt->constraints == NIL)
04180 {
04181
04182
04183
04184 afterTriggers->state->numstates = 0;
04185
04186
04187
04188
04189 afterTriggers->state->all_isset = true;
04190 afterTriggers->state->all_isdeferred = stmt->deferred;
04191 }
04192 else
04193 {
04194 Relation conrel;
04195 Relation tgrel;
04196 List *conoidlist = NIL;
04197 List *tgoidlist = NIL;
04198 ListCell *lc;
04199
04200
04201
04202
04203
04204
04205
04206
04207
04208
04209
04210
04211 conrel = heap_open(ConstraintRelationId, AccessShareLock);
04212
04213 foreach(lc, stmt->constraints)
04214 {
04215 RangeVar *constraint = lfirst(lc);
04216 bool found;
04217 List *namespacelist;
04218 ListCell *nslc;
04219
04220 if (constraint->catalogname)
04221 {
04222 if (strcmp(constraint->catalogname, get_database_name(MyDatabaseId)) != 0)
04223 ereport(ERROR,
04224 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04225 errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
04226 constraint->catalogname, constraint->schemaname,
04227 constraint->relname)));
04228 }
04229
04230
04231
04232
04233
04234
04235 if (constraint->schemaname)
04236 {
04237 Oid namespaceId = LookupExplicitNamespace(constraint->schemaname,
04238 false);
04239
04240 namespacelist = list_make1_oid(namespaceId);
04241 }
04242 else
04243 {
04244 namespacelist = fetch_search_path(true);
04245 }
04246
04247 found = false;
04248 foreach(nslc, namespacelist)
04249 {
04250 Oid namespaceId = lfirst_oid(nslc);
04251 SysScanDesc conscan;
04252 ScanKeyData skey[2];
04253 HeapTuple tup;
04254
04255 ScanKeyInit(&skey[0],
04256 Anum_pg_constraint_conname,
04257 BTEqualStrategyNumber, F_NAMEEQ,
04258 CStringGetDatum(constraint->relname));
04259 ScanKeyInit(&skey[1],
04260 Anum_pg_constraint_connamespace,
04261 BTEqualStrategyNumber, F_OIDEQ,
04262 ObjectIdGetDatum(namespaceId));
04263
04264 conscan = systable_beginscan(conrel, ConstraintNameNspIndexId,
04265 true, SnapshotNow, 2, skey);
04266
04267 while (HeapTupleIsValid(tup = systable_getnext(conscan)))
04268 {
04269 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
04270
04271 if (con->condeferrable)
04272 conoidlist = lappend_oid(conoidlist,
04273 HeapTupleGetOid(tup));
04274 else if (stmt->deferred)
04275 ereport(ERROR,
04276 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
04277 errmsg("constraint \"%s\" is not deferrable",
04278 constraint->relname)));
04279 found = true;
04280 }
04281
04282 systable_endscan(conscan);
04283
04284
04285
04286
04287
04288 if (found)
04289 break;
04290 }
04291
04292 list_free(namespacelist);
04293
04294
04295
04296
04297 if (!found)
04298 ereport(ERROR,
04299 (errcode(ERRCODE_UNDEFINED_OBJECT),
04300 errmsg("constraint \"%s\" does not exist",
04301 constraint->relname)));
04302 }
04303
04304 heap_close(conrel, AccessShareLock);
04305
04306
04307
04308
04309
04310 tgrel = heap_open(TriggerRelationId, AccessShareLock);
04311
04312 foreach(lc, conoidlist)
04313 {
04314 Oid conoid = lfirst_oid(lc);
04315 bool found;
04316 ScanKeyData skey;
04317 SysScanDesc tgscan;
04318 HeapTuple htup;
04319
04320 found = false;
04321
04322 ScanKeyInit(&skey,
04323 Anum_pg_trigger_tgconstraint,
04324 BTEqualStrategyNumber, F_OIDEQ,
04325 ObjectIdGetDatum(conoid));
04326
04327 tgscan = systable_beginscan(tgrel, TriggerConstraintIndexId, true,
04328 SnapshotNow, 1, &skey);
04329
04330 while (HeapTupleIsValid(htup = systable_getnext(tgscan)))
04331 {
04332 Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
04333
04334
04335
04336
04337
04338
04339
04340 if (pg_trigger->tgdeferrable)
04341 tgoidlist = lappend_oid(tgoidlist,
04342 HeapTupleGetOid(htup));
04343
04344 found = true;
04345 }
04346
04347 systable_endscan(tgscan);
04348
04349
04350 if (!found)
04351 elog(ERROR, "no triggers found for constraint with OID %u",
04352 conoid);
04353 }
04354
04355 heap_close(tgrel, AccessShareLock);
04356
04357
04358
04359
04360
04361 foreach(lc, tgoidlist)
04362 {
04363 Oid tgoid = lfirst_oid(lc);
04364 SetConstraintState state = afterTriggers->state;
04365 bool found = false;
04366 int i;
04367
04368 for (i = 0; i < state->numstates; i++)
04369 {
04370 if (state->trigstates[i].sct_tgoid == tgoid)
04371 {
04372 state->trigstates[i].sct_tgisdeferred = stmt->deferred;
04373 found = true;
04374 break;
04375 }
04376 }
04377 if (!found)
04378 {
04379 afterTriggers->state =
04380 SetConstraintStateAddItem(state, tgoid, stmt->deferred);
04381 }
04382 }
04383 }
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393
04394
04395
04396 if (!stmt->deferred)
04397 {
04398 AfterTriggerEventList *events = &afterTriggers->events;
04399 bool snapshot_set = false;
04400
04401 while (afterTriggerMarkEvents(events, NULL, true))
04402 {
04403 CommandId firing_id = afterTriggers->firing_counter++;
04404
04405
04406
04407
04408
04409
04410
04411
04412
04413
04414 if (!snapshot_set)
04415 {
04416 PushActiveSnapshot(GetTransactionSnapshot());
04417 snapshot_set = true;
04418 }
04419
04420
04421
04422
04423
04424
04425 if (afterTriggerInvokeEvents(events, firing_id, NULL,
04426 !IsSubTransaction()))
04427 break;
04428 }
04429
04430 if (snapshot_set)
04431 PopActiveSnapshot();
04432 }
04433 }
04434
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447
04448
04449
04450 bool
04451 AfterTriggerPendingOnRel(Oid relid)
04452 {
04453 AfterTriggerEvent event;
04454 AfterTriggerEventChunk *chunk;
04455 int depth;
04456
04457
04458 if (afterTriggers == NULL)
04459 return false;
04460
04461
04462 for_each_event_chunk(event, chunk, afterTriggers->events)
04463 {
04464 AfterTriggerShared evtshared = GetTriggerSharedData(event);
04465
04466
04467
04468
04469
04470
04471 if (event->ate_flags & AFTER_TRIGGER_DONE)
04472 continue;
04473
04474 if (evtshared->ats_relid == relid)
04475 return true;
04476 }
04477
04478
04479
04480
04481
04482
04483 for (depth = 0; depth <= afterTriggers->query_depth; depth++)
04484 {
04485 for_each_event_chunk(event, chunk, afterTriggers->query_stack[depth])
04486 {
04487 AfterTriggerShared evtshared = GetTriggerSharedData(event);
04488
04489 if (event->ate_flags & AFTER_TRIGGER_DONE)
04490 continue;
04491
04492 if (evtshared->ats_relid == relid)
04493 return true;
04494 }
04495 }
04496
04497 return false;
04498 }
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512 static void
04513 AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
04514 int event, bool row_trigger,
04515 HeapTuple oldtup, HeapTuple newtup,
04516 List *recheckIndexes, Bitmapset *modifiedCols)
04517 {
04518 Relation rel = relinfo->ri_RelationDesc;
04519 TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
04520 AfterTriggerEventData new_event;
04521 AfterTriggerSharedData new_shared;
04522 int tgtype_event;
04523 int tgtype_level;
04524 int i;
04525
04526
04527
04528
04529
04530
04531 if (afterTriggers == NULL)
04532 elog(ERROR, "AfterTriggerSaveEvent() called outside of transaction");
04533 if (afterTriggers->query_depth < 0)
04534 elog(ERROR, "AfterTriggerSaveEvent() called outside of query");
04535
04536
04537
04538
04539
04540
04541
04542
04543 new_event.ate_flags = 0;
04544 switch (event)
04545 {
04546 case TRIGGER_EVENT_INSERT:
04547 tgtype_event = TRIGGER_TYPE_INSERT;
04548 if (row_trigger)
04549 {
04550 Assert(oldtup == NULL);
04551 Assert(newtup != NULL);
04552 ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid1));
04553 ItemPointerSetInvalid(&(new_event.ate_ctid2));
04554 }
04555 else
04556 {
04557 Assert(oldtup == NULL);
04558 Assert(newtup == NULL);
04559 ItemPointerSetInvalid(&(new_event.ate_ctid1));
04560 ItemPointerSetInvalid(&(new_event.ate_ctid2));
04561 }
04562 break;
04563 case TRIGGER_EVENT_DELETE:
04564 tgtype_event = TRIGGER_TYPE_DELETE;
04565 if (row_trigger)
04566 {
04567 Assert(oldtup != NULL);
04568 Assert(newtup == NULL);
04569 ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
04570 ItemPointerSetInvalid(&(new_event.ate_ctid2));
04571 }
04572 else
04573 {
04574 Assert(oldtup == NULL);
04575 Assert(newtup == NULL);
04576 ItemPointerSetInvalid(&(new_event.ate_ctid1));
04577 ItemPointerSetInvalid(&(new_event.ate_ctid2));
04578 }
04579 break;
04580 case TRIGGER_EVENT_UPDATE:
04581 tgtype_event = TRIGGER_TYPE_UPDATE;
04582 if (row_trigger)
04583 {
04584 Assert(oldtup != NULL);
04585 Assert(newtup != NULL);
04586 ItemPointerCopy(&(oldtup->t_self), &(new_event.ate_ctid1));
04587 ItemPointerCopy(&(newtup->t_self), &(new_event.ate_ctid2));
04588 new_event.ate_flags |= AFTER_TRIGGER_2CTIDS;
04589 }
04590 else
04591 {
04592 Assert(oldtup == NULL);
04593 Assert(newtup == NULL);
04594 ItemPointerSetInvalid(&(new_event.ate_ctid1));
04595 ItemPointerSetInvalid(&(new_event.ate_ctid2));
04596 }
04597 break;
04598 case TRIGGER_EVENT_TRUNCATE:
04599 tgtype_event = TRIGGER_TYPE_TRUNCATE;
04600 Assert(oldtup == NULL);
04601 Assert(newtup == NULL);
04602 ItemPointerSetInvalid(&(new_event.ate_ctid1));
04603 ItemPointerSetInvalid(&(new_event.ate_ctid2));
04604 break;
04605 default:
04606 elog(ERROR, "invalid after-trigger event code: %d", event);
04607 tgtype_event = 0;
04608 break;
04609 }
04610
04611 tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
04612
04613 for (i = 0; i < trigdesc->numtriggers; i++)
04614 {
04615 Trigger *trigger = &trigdesc->triggers[i];
04616
04617 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
04618 tgtype_level,
04619 TRIGGER_TYPE_AFTER,
04620 tgtype_event))
04621 continue;
04622 if (!TriggerEnabled(estate, relinfo, trigger, event,
04623 modifiedCols, oldtup, newtup))
04624 continue;
04625
04626
04627
04628
04629
04630
04631 if (TRIGGER_FIRED_BY_UPDATE(event))
04632 {
04633 switch (RI_FKey_trigger_type(trigger->tgfoid))
04634 {
04635 case RI_TRIGGER_PK:
04636
04637 if (!RI_FKey_pk_upd_check_required(trigger, rel,
04638 oldtup, newtup))
04639 {
04640
04641 continue;
04642 }
04643 break;
04644
04645 case RI_TRIGGER_FK:
04646
04647 if (!RI_FKey_fk_upd_check_required(trigger, rel,
04648 oldtup, newtup))
04649 {
04650
04651 continue;
04652 }
04653 break;
04654
04655 case RI_TRIGGER_NONE:
04656
04657 break;
04658 }
04659 }
04660
04661
04662
04663
04664
04665
04666 if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK)
04667 {
04668 if (!list_member_oid(recheckIndexes, trigger->tgconstrindid))
04669 continue;
04670 }
04671
04672
04673
04674
04675 new_shared.ats_event =
04676 (event & TRIGGER_EVENT_OPMASK) |
04677 (row_trigger ? TRIGGER_EVENT_ROW : 0) |
04678 (trigger->tgdeferrable ? AFTER_TRIGGER_DEFERRABLE : 0) |
04679 (trigger->tginitdeferred ? AFTER_TRIGGER_INITDEFERRED : 0);
04680 new_shared.ats_tgoid = trigger->tgoid;
04681 new_shared.ats_relid = RelationGetRelid(rel);
04682 new_shared.ats_firing_id = 0;
04683
04684 afterTriggerAddEvent(&afterTriggers->query_stack[afterTriggers->query_depth],
04685 &new_event, &new_shared);
04686 }
04687 }
04688
04689 Datum
04690 pg_trigger_depth(PG_FUNCTION_ARGS)
04691 {
04692 PG_RETURN_INT32(MyTriggerDepth);
04693 }