PostgreSQL Source Code: src/include/commands/trigger.h File Reference (original) (raw)
182{
184 int ncolumns;
187 List *whenRtable;
188 char *qual;
190 bool nulls[Natts_pg_trigger];
196 Oid funcrettype;
199 char *trigname;
202 referenced;
203 char *oldtablename = NULL;
204 char *newtablename = NULL;
205 bool partition_recurse;
206 bool trigger_exists = false;
208 bool existing_isInternal = false;
209 bool existing_isClone = false;
210
213 else
215
216
217
218
219
220 if (rel->rd_rel->relkind == RELKIND_RELATION)
221 {
222
223 if (stmt->timing != TRIGGER_TYPE_BEFORE &&
224 stmt->timing != TRIGGER_TYPE_AFTER)
226 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
227 errmsg("\"%s\" is a table",
229 errdetail("Tables cannot have INSTEAD OF triggers.")));
230 }
231 else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
232 {
233
234 if (stmt->timing != TRIGGER_TYPE_BEFORE &&
235 stmt->timing != TRIGGER_TYPE_AFTER)
237 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
238 errmsg("\"%s\" is a table",
240 errdetail("Tables cannot have INSTEAD OF triggers.")));
241
242
243
244
245 if (stmt->row)
246 {
247
248
249
250
251
252
253
254
255
256
257
258 if (stmt->transitionRels != NIL)
260 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
261 errmsg("\"%s\" is a partitioned table",
263 errdetail("ROW triggers with transition tables are not supported on partitioned tables.")));
264 }
265 }
266 else if (rel->rd_rel->relkind == RELKIND_VIEW)
267 {
268
269
270
271
272 if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
274 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
275 errmsg("\"%s\" is a view",
277 errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
278
279 if (TRIGGER_FOR_TRUNCATE(stmt->events))
281 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
282 errmsg("\"%s\" is a view",
284 errdetail("Views cannot have TRUNCATE triggers.")));
285 }
286 else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
287 {
288 if (stmt->timing != TRIGGER_TYPE_BEFORE &&
289 stmt->timing != TRIGGER_TYPE_AFTER)
291 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
292 errmsg("\"%s\" is a foreign table",
294 errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
295
296
297
298
299
300
301 if (stmt->isconstraint)
303 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
304 errmsg("\"%s\" is a foreign table",
306 errdetail("Foreign tables cannot have constraint triggers.")));
307 }
308 else
310 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
311 errmsg("relation \"%s\" cannot have triggers",
314
317 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
318 errmsg("permission denied: \"%s\" is a system catalog",
320
321 if (stmt->isconstraint)
322 {
323
324
325
326
327
328
329
331 {
333 constrrelid = refRelOid;
334 }
335 else if (stmt->constrrel != NULL)
337 false);
338 }
339
340
341 if (!isInternal)
342 {
348
350 {
356 }
357 }
358
359
360
361
362
363
364
365 partition_recurse = !isInternal && stmt->row &&
366 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
367 if (partition_recurse)
370
371
372 TRIGGER_CLEAR_TYPE(tgtype);
373 if (stmt->row)
374 TRIGGER_SETT_ROW(tgtype);
375 tgtype |= stmt->timing;
376 tgtype |= stmt->events;
377
378
379 if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))
381 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
382 errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));
383
384
385 if (TRIGGER_FOR_INSTEAD(tgtype))
386 {
387 if (!TRIGGER_FOR_ROW(tgtype))
389 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
390 errmsg("INSTEAD OF triggers must be FOR EACH ROW")));
391 if (stmt->whenClause)
393 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
394 errmsg("INSTEAD OF triggers cannot have WHEN conditions")));
397 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
398 errmsg("INSTEAD OF triggers cannot have column lists")));
399 }
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415 if (stmt->transitionRels != NIL)
416 {
417 List *varList = stmt->transitionRels;
419
420 foreach(lc, varList)
421 {
423
426 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
427 errmsg("ROW variable naming in the REFERENCING clause is not supported"),
428 errhint("Use OLD TABLE or NEW TABLE for naming transition tables.")));
429
430
431
432
433
434
435
436 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
438 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
439 errmsg("\"%s\" is a foreign table",
441 errdetail("Triggers on foreign tables cannot have transition tables.")));
442
443 if (rel->rd_rel->relkind == RELKIND_VIEW)
445 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
446 errmsg("\"%s\" is a view",
448 errdetail("Triggers on views cannot have transition tables.")));
449
450
451
452
453
454
455
456
457
459 {
460
461 if (rel->rd_rel->relispartition)
463 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
464 errmsg("ROW triggers with transition tables are not supported on partitions")));
465 else
467 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
468 errmsg("ROW triggers with transition tables are not supported on inheritance children")));
469 }
470
471 if (stmt->timing != TRIGGER_TYPE_AFTER)
473 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
474 errmsg("transition table name can only be specified for an AFTER trigger")));
475
476 if (TRIGGER_FOR_TRUNCATE(tgtype))
478 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
479 errmsg("TRUNCATE triggers with transition tables are not supported")));
480
481
482
483
484
485
486
487
488
489
490
491 if (((TRIGGER_FOR_INSERT(tgtype) ? 1 : 0) +
492 (TRIGGER_FOR_UPDATE(tgtype) ? 1 : 0) +
493 (TRIGGER_FOR_DELETE(tgtype) ? 1 : 0)) != 1)
495 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
496 errmsg("transition tables cannot be specified for triggers with more than one event")));
497
498
499
500
501
502
503
506 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
507 errmsg("transition tables cannot be specified for triggers with column lists")));
508
509
510
511
512
513
514
515
517
519 {
520 if (!(TRIGGER_FOR_INSERT(tgtype) ||
521 TRIGGER_FOR_UPDATE(tgtype)))
523 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
524 errmsg("NEW TABLE can only be specified for an INSERT or UPDATE trigger")));
525
526 if (newtablename != NULL)
528 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
529 errmsg("NEW TABLE cannot be specified multiple times")));
530
531 newtablename = tt->name;
532 }
533 else
534 {
535 if (!(TRIGGER_FOR_DELETE(tgtype) ||
536 TRIGGER_FOR_UPDATE(tgtype)))
538 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
539 errmsg("OLD TABLE can only be specified for a DELETE or UPDATE trigger")));
540
541 if (oldtablename != NULL)
543 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
544 errmsg("OLD TABLE cannot be specified multiple times")));
545
546 oldtablename = tt->name;
547 }
548 }
549
550 if (newtablename != NULL && oldtablename != NULL &&
551 strcmp(newtablename, oldtablename) == 0)
553 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
554 errmsg("OLD TABLE name and NEW TABLE name cannot be the same")));
555 }
556
557
558
559
560
561
562
563
564
565 if (!whenClause && stmt->whenClause)
566 {
569 List *varList;
571
572
575
576
577
578
579
580
584 false, false);
589 false, false);
591
592
596 "WHEN");
597
599
600
601
602
603
604
605
606
608 foreach(lc, varList)
609 {
611
612 switch (var->varno)
613 {
615 if (!TRIGGER_FOR_ROW(tgtype))
617 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
618 errmsg("statement trigger's WHEN condition cannot reference column values"),
620 if (TRIGGER_FOR_INSERT(tgtype))
622 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
623 errmsg("INSERT trigger's WHEN condition cannot reference OLD values"),
625
626 break;
628 if (!TRIGGER_FOR_ROW(tgtype))
630 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
631 errmsg("statement trigger's WHEN condition cannot reference column values"),
633 if (TRIGGER_FOR_DELETE(tgtype))
635 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
636 errmsg("DELETE trigger's WHEN condition cannot reference NEW values"),
638 if (var->varattno < 0 && TRIGGER_FOR_BEFORE(tgtype))
640 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
641 errmsg("BEFORE trigger's WHEN condition cannot reference NEW system columns"),
643 if (TRIGGER_FOR_BEFORE(tgtype) &&
649 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
650 errmsg("BEFORE trigger's WHEN condition cannot reference NEW generated columns"),
651 errdetail("A whole-row reference is used and the table contains generated columns."),
653 if (TRIGGER_FOR_BEFORE(tgtype) &&
657 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
658 errmsg("BEFORE trigger's WHEN condition cannot reference NEW generated columns"),
659 errdetail("Column \"%s\" is a generated column.",
662 break;
663 default:
664
665 elog(ERROR, "trigger WHEN condition cannot contain references to other relations");
666 break;
667 }
668 }
669
670
671 whenRtable = pstate->p_rtable;
672
674
676 }
677 else if (!whenClause)
678 {
679 whenClause = NULL;
680 whenRtable = NIL;
681 qual = NULL;
682 }
683 else
684 {
686 whenRtable = NIL;
687 }
688
689
690
691
694 if (!isInternal)
695 {
700 }
702 if (funcrettype != TRIGGEROID)
704 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
705 errmsg("function %s must return type %s",
707
708
709
710
711
712
713
714
715
717 if (!isInternal)
718 {
721
723 Anum_pg_trigger_tgrelid,
726
728 Anum_pg_trigger_tgname,
731
733 NULL, 2, skeys);
734
735
737 {
739
740 trigoid = oldtrigger->oid;
741 existing_constraint_oid = oldtrigger->tgconstraint;
742 existing_isInternal = oldtrigger->tgisinternal;
743 existing_isClone = OidIsValid(oldtrigger->tgparentid);
744 trigger_exists = true;
745
747 }
749 }
750
751 if (!trigger_exists)
752 {
753
755 Anum_pg_trigger_oid);
756 }
757 else
758 {
759
760
761
762
763 if (->replace)
766 errmsg("trigger \"%s\" for relation \"%s\" already exists",
768
769
770
771
772
773
774
775 if ((existing_isInternal || existing_isClone) &&
776 !isInternal && !in_partition)
779 errmsg("trigger \"%s\" for relation \"%s\" is an internal or a child trigger",
781
782
783
784
785
787
788
789
790
791
792
793
794
795 if (OidIsValid(existing_constraint_oid))
798 errmsg("trigger \"%s\" for relation \"%s\" is a constraint trigger",
800 }
801
802
803
804
805
806 if (stmt->isconstraint && (constraintOid))
807 {
808
812 CONSTRAINT_TRIGGER,
813 stmt->deferrable,
814 stmt->initdeferred,
815 true,
816 true,
819 NULL,
820 0,
821 0,
825 NULL,
826 NULL,
827 NULL,
828 NULL,
829 0,
830 ' ',
831 ' ',
832 NULL,
833 0,
834 ' ',
835 NULL,
836 NULL,
837 NULL,
838 true,
839 0,
840 true,
841 false,
842 isInternal);
843 }
844
845
846
847
848
849
850 if (isInternal)
851 {
852 snprintf(internaltrigname, sizeof(internaltrigname),
853 "%s_%u", stmt->trigname, trigoid);
854 trigname = internaltrigname;
855 }
856 else
857 {
858
859 trigname = stmt->trigname;
860 }
861
862
863
864
865 memset(nulls, false, sizeof(nulls));
866
874 values[Anum_pg_trigger_tgenabled - 1] = trigger_fires_when;
881
882 if (stmt->args)
883 {
887 int len = 0;
888
889 foreach(le, stmt->args)
890 {
892
893 len += strlen(ar) + 4;
894 for (; *ar; ar++)
895 {
896 if (*ar == '\\')
898 }
899 }
901 args[0] = '\0';
902 foreach(le, stmt->args)
903 {
905 char *d = args + strlen(args);
906
907 while (*s)
908 {
909 if (*s == '\\')
910 *d++ = '\\';
911 *d++ = *s++;
912 }
913 strcpy(d, "\\000");
914 }
918 }
919 else
920 {
924 }
925
926
928 if (ncolumns == 0)
929 columns = NULL;
930 else
931 {
933 int i = 0;
934
936 foreach(cell, stmt->columns)
937 {
940 int j;
941
942
946 (errcode(ERRCODE_UNDEFINED_COLUMN),
947 errmsg("column \"%s\" of relation \"%s\" does not exist",
949
950
951 for (j = i - 1; j >= 0; j--)
952 {
955 (errcode(ERRCODE_DUPLICATE_COLUMN),
956 errmsg("column \"%s\" specified more than once",
958 }
959
961 }
962 }
965
966
967 if (qual)
969 else
970 nulls[Anum_pg_trigger_tgqual - 1] = true;
971
972 if (oldtablename)
975 else
976 nulls[Anum_pg_trigger_tgoldtable - 1] = true;
977 if (newtablename)
980 else
981 nulls[Anum_pg_trigger_tgnewtable - 1] = true;
982
983
984
985
986 if (!trigger_exists)
987 {
990 }
991 else
992 {
994
998 }
999
1000 heap_freetuple(tuple);
1002
1006 if (oldtablename)
1008 if (newtablename)
1010
1011
1012
1013
1014
1019 elog(ERROR, "cache lookup failed for relation %u",
1022 {
1024
1026
1028 }
1029 else
1031
1034
1035
1036
1037
1038
1039 if (trigger_exists)
1041
1042
1043
1044
1045
1046 myself.classId = TriggerRelationId;
1049
1050 referenced.classId = ProcedureRelationId;
1051 referenced.objectId = funcoid;
1054
1055 if (isInternal && OidIsValid(constraintOid))
1056 {
1057
1058
1059
1060
1061
1062
1063 referenced.classId = ConstraintRelationId;
1064 referenced.objectId = constraintOid;
1067 }
1068 else
1069 {
1070
1071
1072
1073
1074
1075 referenced.classId = RelationRelationId;
1079
1081 {
1082 referenced.classId = RelationRelationId;
1083 referenced.objectId = constrrelid;
1086 }
1087
1089
1090
1091
1092
1093
1095 {
1096 referenced.classId = ConstraintRelationId;
1097 referenced.objectId = constraintOid;
1100 }
1101
1102
1103
1104
1106 {
1107 ObjectAddressSet(referenced, TriggerRelationId, parentTriggerOid);
1111 }
1112 }
1113
1114
1115 if (columns != NULL)
1116 {
1117 int i;
1118
1119 referenced.classId = RelationRelationId;
1121 for (i = 0; i < ncolumns; i++)
1122 {
1125 }
1126 }
1127
1128
1129
1130
1131
1132 if (whenRtable != NIL)
1135
1136
1138 isInternal);
1139
1140
1141
1142
1143 if (partition_recurse)
1144 {
1146 int i;
1148 perChildCxt;
1149
1151 "part trig clone",
1153
1154
1155
1156
1157
1158
1160
1162
1163
1164 for (i = 0; i < partdesc->nparts; i++)
1165 {
1169
1171
1172
1173
1174
1175
1179
1180
1182 qual = (Node *)
1184 childTbl, rel);
1185 qual = (Node *)
1187 childTbl, rel);
1188
1190 partdesc->oids[i], refRelOid,
1192 funcoid, trigoid, qual,
1193 isInternal, true, trigger_fires_when);
1194
1196
1198 }
1199
1202 }
1203
1204
1206
1207 return myself;
1208}
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
#define InvalidAttrNumber
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
#define OidIsValid(objectId)
bool IsSystemRelation(Relation relation)
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)
@ DEPENDENCY_PARTITION_PRI
@ DEPENDENCY_PARTITION_SEC
int errdetail(const char *fmt,...)
int errhint(const char *fmt,...)
#define DirectFunctionCall1(func, arg1)
bool allowSystemTableMods
HeapTuple heap_copytuple(HeapTuple tuple)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
void heap_freetuple(HeapTuple htup)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
int2vector * buildint2vector(const int16 *int2s, int n)
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
void LockRelationOid(Oid relid, LOCKMODE lockmode)
#define ShareRowExclusiveLock
char * get_rel_name(Oid relid)
char get_rel_relkind(Oid relid)
Oid get_func_rettype(Oid funcid)
Alias * makeAlias(const char *aliasname, List *colnames)
void MemoryContextReset(MemoryContext context)
MemoryContext CurrentMemoryContext
#define AllocSetContextCreate
#define ALLOCSET_SMALL_SIZES
Datum namein(PG_FUNCTION_ARGS)
char * NameListToString(const List *names)
#define RangeVarGetRelid(relation, lockmode, missing_ok)
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
ObjectType get_relkind_objtype(char relkind)
#define ObjectAddressSet(addr, class_id, object_id)
char * nodeToString(const void *obj)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
void free_parsestate(ParseState *pstate)
int parser_errposition(ParseState *pstate, int location)
ParseState * make_parsestate(ParseState *parentParseState)
ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)
void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
int attnameAttNum(Relation rd, const char *attname, bool sysColOK)
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
int errdetail_relkind_not_supported(char relkind)
FormData_pg_class * Form_pg_class
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isEnforced, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int16 conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
bool has_superclass(Oid relationId)
#define lfirst_node(type, lc)
static int list_length(const List *l)
static Datum PointerGetDatum(const void *X)
static Datum Int16GetDatum(int16 X)
static Datum BoolGetDatum(bool X)
static Pointer DatumGetPointer(Datum X)
#define RelationGetRelid(relation)
#define RelationGetDescr(relation)
#define RelationGetRelationName(relation)
#define RelationGetNamespace(relation)
#define ERRCODE_DUPLICATE_OBJECT
const char * p_sourcetext
#define SearchSysCacheCopy1(cacheId, key1)
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
List * pull_var_clause(Node *node, int flags)
Datum byteain(PG_FUNCTION_ARGS)
void CommandCounterIncrement(void)