51#include "utils/fmgroids.h"
72 const char *expected_name);
74 Oid parentTriggerOid,
const char *newname,
75 const char *expected_name);
98 int event,
bool row_trigger,
102 bool is_crosspart_update);
161 Oid relOid,
Oid refRelOid,
Oid constraintOid,
Oid indexOid,
162 Oid funcoid,
Oid parentTriggerOid,
Node *whenClause,
163 bool isInternal,
bool in_partition)
167 constraintOid, indexOid, funcoid,
168 parentTriggerOid, whenClause, isInternal,
178 Oid relOid,
Oid refRelOid,
Oid constraintOid,
179 Oid indexOid,
Oid funcoid,
Oid parentTriggerOid,
180 Node *whenClause,
bool isInternal,
bool in_partition,
181 char trigger_fires_when)
190 bool nulls[Natts_pg_trigger];
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;
220 if (rel->
rd_rel->relkind == RELKIND_RELATION)
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.")));
231 else if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
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.")));
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.")));
266 else if (rel->
rd_rel->relkind == RELKIND_VIEW)
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.")));
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.")));
286 else if (rel->
rd_rel->relkind == RELKIND_FOREIGN_TABLE)
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.")));
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.")));
310 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
311 errmsg(
"relation \"%s\" cannot have triggers",
317 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
318 errmsg(
"permission denied: \"%s\" is a system catalog",
321 if (
stmt->isconstraint)
333 constrrelid = refRelOid;
335 else if (
stmt->constrrel != NULL)
365 partition_recurse = !isInternal &&
stmt->row &&
366 rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
367 if (partition_recurse)
372 TRIGGER_CLEAR_TYPE(tgtype);
374 TRIGGER_SETT_ROW(tgtype);
375 tgtype |=
stmt->timing;
376 tgtype |=
stmt->events;
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")));
385 if (TRIGGER_FOR_INSTEAD(tgtype))
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")));
415 if (
stmt->transitionRels !=
NIL)
417 List *varList =
stmt->transitionRels;
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.")));
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.")));
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.")));
461 if (rel->
rd_rel->relispartition)
463 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
464 errmsg(
"ROW triggers with transition tables are not supported on partitions")));
467 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
468 errmsg(
"ROW triggers with transition tables are not supported on inheritance children")));
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")));
476 if (TRIGGER_FOR_TRUNCATE(tgtype))
478 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
479 errmsg(
"TRUNCATE triggers with transition tables are not supported")));
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")));
506 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
507 errmsg(
"transition tables cannot be specified for triggers with column lists")));
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")));
526 if (newtablename != NULL)
528 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
529 errmsg(
"NEW TABLE cannot be specified multiple times")));
531 newtablename = tt->
name;
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")));
541 if (oldtablename != NULL)
543 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
544 errmsg(
"OLD TABLE cannot be specified multiple times")));
546 oldtablename = tt->
name;
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")));
565 if (!whenClause &&
stmt->whenClause)
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"),
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.",
665 elog(
ERROR,
"trigger WHEN condition cannot contain references to other relations");
677 else if (!whenClause)
702 if (funcrettype != TRIGGEROID)
704 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
705 errmsg(
"function %s must return type %s",
723 Anum_pg_trigger_tgrelid,
728 Anum_pg_trigger_tgname,
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;
755 Anum_pg_trigger_oid);
766 errmsg(
"trigger \"%s\" for relation \"%s\" already exists",
775 if ((existing_isInternal || existing_isClone) &&
776 !isInternal && !in_partition)
779 errmsg(
"trigger \"%s\" for relation \"%s\" is an internal or a child trigger",
798 errmsg(
"trigger \"%s\" for relation \"%s\" is a constraint trigger",
852 snprintf(internaltrigname,
sizeof(internaltrigname),
853 "%s_%u",
stmt->trigname, trigoid);
854 trigname = internaltrigname;
859 trigname =
stmt->trigname;
865 memset(nulls,
false,
sizeof(nulls));
874 values[Anum_pg_trigger_tgenabled - 1] = trigger_fires_when;
889 foreach(le,
stmt->args)
893 len += strlen(ar) + 4;
902 foreach(le,
stmt->args)
936 foreach(cell,
stmt->columns)
946 (
errcode(ERRCODE_UNDEFINED_COLUMN),
947 errmsg(
"column \"%s\" of relation \"%s\" does not exist",
951 for (
j =
i - 1;
j >= 0;
j--)
955 (
errcode(ERRCODE_DUPLICATE_COLUMN),
956 errmsg(
"column \"%s\" specified more than once",
970 nulls[Anum_pg_trigger_tgqual - 1] =
true;
976 nulls[Anum_pg_trigger_tgoldtable - 1] =
true;
981 nulls[Anum_pg_trigger_tgnewtable - 1] =
true;
1019 elog(
ERROR,
"cache lookup failed for relation %u",
1046 myself.
classId = TriggerRelationId;
1050 referenced.
classId = ProcedureRelationId;
1063 referenced.
classId = ConstraintRelationId;
1064 referenced.
objectId = constraintOid;
1075 referenced.
classId = RelationRelationId;
1082 referenced.
classId = RelationRelationId;
1096 referenced.
classId = ConstraintRelationId;
1097 referenced.
objectId = constraintOid;
1115 if (columns != NULL)
1119 referenced.
classId = RelationRelationId;
1121 for (
i = 0;
i < ncolumns;
i++)
1132 if (whenRtable !=
NIL)
1143 if (partition_recurse)
1190 partdesc->
oids[
i], refRelOid,
1192 funcoid, trigoid, qual,
1193 isInternal,
true, trigger_fires_when);
1237 Anum_pg_trigger_oid,
1246 elog(
ERROR,
"could not find tuple for trigger %u", childTrigId);
1253 elog(
ERROR,
"trigger %u already has a parent trigger",
1256 trigForm->tgparentid = parentTrigId;
1306 Anum_pg_trigger_oid,
1315 elog(
ERROR,
"could not find tuple for trigger %u", trigOid);
1324 if (rel->
rd_rel->relkind != RELKIND_RELATION &&
1325 rel->
rd_rel->relkind != RELKIND_VIEW &&
1326 rel->
rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
1327 rel->
rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1329 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
1330 errmsg(
"relation \"%s\" cannot have triggers",
1336 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1337 errmsg(
"permission denied: \"%s\" is a system catalog",
1384 Anum_pg_trigger_tgrelid,
1388 Anum_pg_trigger_tgname,
1401 (
errcode(ERRCODE_UNDEFINED_OBJECT),
1402 errmsg(
"trigger \"%s\" for table \"%s\" does not exist",
1432 if (form->relkind != RELKIND_RELATION && form->relkind != RELKIND_VIEW &&
1433 form->relkind != RELKIND_FOREIGN_TABLE &&
1434 form->relkind != RELKIND_PARTITIONED_TABLE)
1436 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
1437 errmsg(
"relation \"%s\" cannot have triggers",
1446 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1447 errmsg(
"permission denied: \"%s\" is a system catalog",
1494 if (targetrel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1503 Anum_pg_trigger_tgrelid,
1507 Anum_pg_trigger_tgname,
1517 tgoid = trigform->oid;
1527 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1528 errmsg(
"cannot rename trigger \"%s\" on table \"%s\"",
1530 errhint(
"Rename the trigger on the partitioned table \"%s\" instead.",
1539 if (targetrel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1543 for (
int i = 0;
i < partdesc->
nparts;
i++)
1545 Oid partitionId = partdesc->
oids[
i];
1555 (
errcode(ERRCODE_UNDEFINED_OBJECT),
1556 errmsg(
"trigger \"%s\" for table \"%s\" does not exist",
1583 const char *newname,
const char *expected_name)
1592 if (strcmp(
NameStr(tgform->tgname), newname) == 0)
1601 Anum_pg_trigger_tgrelid,
1605 Anum_pg_trigger_tgname,
1613 errmsg(
"trigger \"%s\" for relation \"%s\" already exists",
1628 if (strcmp(
NameStr(tgform->tgname), expected_name) != 0)
1630 errmsg(
"renamed trigger \"%s\" on relation \"%s\"",
1654 const char *newname,
const char *expected_name)
1666 Anum_pg_trigger_tgrelid,
1676 if (tgform->tgparentid != parentTriggerOid)
1685 if (partitionRel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1690 for (
int i = 0;
i < partdesc->
nparts;
i++)
1727 char fires_when,
bool skip_system,
bool recurse,
1742 Anum_pg_trigger_tgrelid,
1748 Anum_pg_trigger_tgname,
1759 found = changed =
false;
1765 if (
OidIsValid(tgparent) && tgparent != oldtrig->tgparentid)
1768 if (oldtrig->tgisinternal)
1775 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1776 errmsg(
"permission denied: \"%s\" is a system trigger",
1782 if (oldtrig->tgenabled != fires_when)
1788 newtrig->tgenabled = fires_when;
1807 rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
1808 (TRIGGER_FOR_ROW(oldtrig->tgtype)))
1820 fires_when, skip_system, recurse,
1834 if (tgname && !found)
1836 (
errcode(ERRCODE_UNDEFINED_OBJECT),
1837 errmsg(
"trigger \"%s\" for table \"%s\" does not exist",
1889 Anum_pg_trigger_tgrelid,
1904 if (numtrigs >= maxtrigs)
1909 build = &(triggers[numtrigs]);
1911 build->
tgoid = pg_trigger->oid;
1914 build->
tgfoid = pg_trigger->tgfoid;
1915 build->
tgtype = pg_trigger->tgtype;
1916 build->
tgenabled = pg_trigger->tgenabled;
1924 build->
tgnargs = pg_trigger->tgnargs;
1926 build->
tgnattr = pg_trigger->tgattr.dim1;
1930 memcpy(build->
tgattr, &(pg_trigger->tgattr.values),
1941 Anum_pg_trigger_tgargs,
1942 tgrel->
rd_att, &isnull));
1944 elog(
ERROR,
"tgargs is null in trigger for relation \"%s\"",
1957 datum =
fastgetattr(htup, Anum_pg_trigger_tgoldtable,
1965 datum =
fastgetattr(htup, Anum_pg_trigger_tgnewtable,
1997 for (
i = 0;
i < numtrigs;
i++)
2018 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
2019 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSERT);
2021 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
2022 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_INSERT);
2024 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
2025 TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_INSERT);
2027 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
2028 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_INSERT);
2030 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
2031 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_INSERT);
2033 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
2034 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_UPDATE);
2036 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
2037 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_UPDATE);
2039 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
2040 TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_UPDATE);
2042 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
2043 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_UPDATE);
2045 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
2046 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_UPDATE);
2048 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
2049 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_DELETE);
2051 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
2052 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_DELETE);
2054 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_ROW,
2055 TRIGGER_TYPE_INSTEAD, TRIGGER_TYPE_DELETE);
2057 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
2058 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_DELETE);
2060 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
2061 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_DELETE);
2064 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
2065 TRIGGER_TYPE_BEFORE, TRIGGER_TYPE_TRUNCATE);
2067 TRIGGER_TYPE_MATCHES(tgtype, TRIGGER_TYPE_STATEMENT,
2068 TRIGGER_TYPE_AFTER, TRIGGER_TYPE_TRUNCATE);
2071 (TRIGGER_FOR_INSERT(tgtype) &&
2072 TRIGGER_USES_TRANSITION_TABLE(trigger->
tgnewtable));
2074 (TRIGGER_FOR_UPDATE(tgtype) &&
2075 TRIGGER_USES_TRANSITION_TABLE(trigger->
tgoldtable));
2077 (TRIGGER_FOR_UPDATE(tgtype) &&
2078 TRIGGER_USES_TRANSITION_TABLE(trigger->
tgnewtable));
2080 (TRIGGER_FOR_DELETE(tgtype) &&
2081 TRIGGER_USES_TRANSITION_TABLE(trigger->
tgoldtable));
2096 if (trigdesc == NULL || trigdesc->
numtriggers <= 0)
2103 memcpy(trigger, trigdesc->
triggers,
2115 memcpy(newattr, trigger->
tgattr,
2117 trigger->
tgattr = newattr;
2124 newargs = (
char **)
palloc(trigger->
tgnargs *
sizeof(
char *));
2127 trigger->
tgargs = newargs;
2150 if (trigdesc == NULL)
2161 while (--(trigger->
tgnargs) >= 0)
2199 if (trigdesc1 != NULL)
2201 if (trigdesc2 == NULL)
2247 else if (trig1->
tgqual == NULL || trig2->
tgqual == NULL)
2265 else if (trigdesc2 != NULL)
2279 if (trigdesc != NULL)
2384 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2385 errmsg(
"trigger function %u returned null value",
2386 fcinfo->flinfo->fn_oid)));
2407 if (trigdesc == NULL)
2417 LocTriggerData.
type = T_TriggerData;
2426 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
2427 TRIGGER_TYPE_STATEMENT,
2428 TRIGGER_TYPE_BEFORE,
2429 TRIGGER_TYPE_INSERT))
2444 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2445 errmsg(
"BEFORE STATEMENT trigger cannot return a value")));
2458 false, NULL, NULL,
NIL, NULL, transition_capture,
2472 LocTriggerData.
type = T_TriggerData;
2482 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
2484 TRIGGER_TYPE_BEFORE,
2485 TRIGGER_TYPE_INSERT))
2502 if (newtuple == NULL)
2508 else if (newtuple != oldtuple)
2522 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2523 errmsg(
"moving row to another partition during a BEFORE FOR EACH ROW trigger is not supported"),
2524 errdetail(
"Before executing trigger \"%s\", the row was to be in partition \"%s.%s\".",
2552 recheckIndexes, NULL,
2567 LocTriggerData.
type = T_TriggerData;
2577 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
2579 TRIGGER_TYPE_INSTEAD,
2580 TRIGGER_TYPE_INSERT))
2597 if (newtuple == NULL)
2603 else if (newtuple != oldtuple)
2627 if (trigdesc == NULL)
2637 LocTriggerData.
type = T_TriggerData;
2646 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
2647 TRIGGER_TYPE_STATEMENT,
2648 TRIGGER_TYPE_BEFORE,
2649 TRIGGER_TYPE_DELETE))
2664 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2665 errmsg(
"BEFORE STATEMENT trigger cannot return a value")));
2678 false, NULL, NULL,
NIL, NULL, transition_capture,
2703 bool should_free =
false;
2707 if (fdw_trigtuple == NULL)
2721 if (epqslot_candidate != NULL && epqslot != NULL)
2723 *epqslot = epqslot_candidate;
2731 trigtuple = fdw_trigtuple;
2735 LocTriggerData.
type = T_TriggerData;
2745 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
2747 TRIGGER_TYPE_BEFORE,
2748 TRIGGER_TYPE_DELETE))
2762 if (newtuple == NULL)
2767 if (newtuple != trigtuple)
2786 bool is_crosspart_update)
2796 if (fdw_trigtuple == NULL)
2811 true, slot, NULL,
NIL, NULL,
2813 is_crosspart_update);
2826 LocTriggerData.
type = T_TriggerData;
2839 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
2841 TRIGGER_TYPE_INSTEAD,
2842 TRIGGER_TYPE_DELETE))
2856 if (rettuple == NULL)
2858 if (rettuple != trigtuple)
2874 if (trigdesc == NULL)
2889 LocTriggerData.
type = T_TriggerData;
2899 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
2900 TRIGGER_TYPE_STATEMENT,
2901 TRIGGER_TYPE_BEFORE,
2902 TRIGGER_TYPE_UPDATE))
2905 updatedCols, NULL, NULL))
2917 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2918 errmsg(
"BEFORE STATEMENT trigger cannot return a value")));
2934 false, NULL, NULL,
NIL,
2953 bool should_free_trig =
false;
2954 bool should_free_new =
false;
2964 if (fdw_trigtuple == NULL)
2970 lockmode, oldslot, &epqslot_candidate,
2983 if (epqslot_candidate != NULL)
2996 if (
unlikely(newslot != epqslot_clean))
3021 trigtuple = fdw_trigtuple;
3024 LocTriggerData.
type = T_TriggerData;
3036 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
3038 TRIGGER_TYPE_BEFORE,
3039 TRIGGER_TYPE_UPDATE))
3042 updatedCols, oldslot, newslot))
3059 if (newtuple == NULL)
3061 if (should_free_trig)
3063 if (should_free_new)
3067 else if (newtuple != oldtuple)
3079 if (should_free_trig && newtuple == trigtuple)
3082 if (should_free_new)
3089 if (should_free_trig)
3112 List *recheckIndexes,
3114 bool is_crosspart_update)
3119 (transition_capture &&
3132 Assert((src_partinfo != NULL && dst_partinfo != NULL) ||
3133 !is_crosspart_update);
3135 tupsrc = src_partinfo ? src_partinfo : relinfo;
3148 else if (fdw_trigtuple != NULL)
3154 src_partinfo, dst_partinfo,
3157 oldslot, newslot, recheckIndexes,
3160 is_crosspart_update);
3175 LocTriggerData.
type = T_TriggerData;
3188 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
3190 TRIGGER_TYPE_INSTEAD,
3191 TRIGGER_TYPE_UPDATE))
3194 NULL, oldslot, newslot))
3211 if (newtuple == NULL)
3215 else if (newtuple != oldtuple)
3239 if (trigdesc == NULL)
3244 LocTriggerData.
type = T_TriggerData;
3254 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
3255 TRIGGER_TYPE_STATEMENT,
3256 TRIGGER_TYPE_BEFORE,
3257 TRIGGER_TYPE_TRUNCATE))
3272 (
errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
3273 errmsg(
"BEFORE STATEMENT trigger cannot return a value")));
3286 false, NULL, NULL,
NIL, NULL, NULL,
3307 if (epqslot != NULL)
3316 Assert(epqstate != NULL);
3349 (
errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
3350 errmsg(
"tuple to be updated was already modified by an operation triggered by the current command"),
3351 errhint(
"Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.")));
3392 errmsg(
"could not serialize access due to concurrent update")));
3393 elog(
ERROR,
"unexpected table_tuple_lock status: %u",
test);
3400 errmsg(
"could not serialize access due to concurrent delete")));
3405 elog(
ERROR,
"attempted to lock invisible tuple");
3409 elog(
ERROR,
"unrecognized table_tuple_lock status: %u",
test);
3421 elog(
ERROR,
"failed to fetch tuple for trigger");
3495 if (*predicate == NULL)
3524 if (!
ExecQual(*predicate, econtext))
3630#define AFTER_TRIGGER_OFFSET 0x07FFFFFF
3631#define AFTER_TRIGGER_DONE 0x80000000
3632#define AFTER_TRIGGER_IN_PROGRESS 0x40000000
3634#define AFTER_TRIGGER_FDW_REUSE 0x00000000
3635#define AFTER_TRIGGER_FDW_FETCH 0x20000000
3636#define AFTER_TRIGGER_1CTID 0x10000000
3637#define AFTER_TRIGGER_2CTID 0x30000000
3638#define AFTER_TRIGGER_CP_UPDATE 0x08000000
3639#define AFTER_TRIGGER_TUP_BITS 0x38000000
3691#define SizeofTriggerEvent(evt) \
3692 (((evt)->ate_flags & AFTER_TRIGGER_TUP_BITS) == AFTER_TRIGGER_CP_UPDATE ? \
3693 sizeof(AfterTriggerEventData) : \
3694 (((evt)->ate_flags & AFTER_TRIGGER_TUP_BITS) == AFTER_TRIGGER_2CTID ? \
3695 sizeof(AfterTriggerEventDataNoOids) : \
3696 (((evt)->ate_flags & AFTER_TRIGGER_TUP_BITS) == AFTER_TRIGGER_1CTID ? \
3697 sizeof(AfterTriggerEventDataOneCtid) : \
3698 sizeof(AfterTriggerEventDataZeroCtids))))
3700#define GetTriggerSharedData(evt) \
3701 ((AfterTriggerShared) ((char *) (evt) + ((evt)->ate_flags & AFTER_TRIGGER_OFFSET)))
3719#define CHUNK_DATA_START(cptr) ((char *) (cptr) + MAXALIGN(sizeof(AfterTriggerEventChunk)))
3730#define for_each_chunk(cptr, evtlist) \
3731 for (cptr = (evtlist).head; cptr != NULL; cptr = cptr->next)
3732#define for_each_event(eptr, cptr) \
3733 for (eptr = (AfterTriggerEvent) CHUNK_DATA_START(cptr); \
3734 (char *) eptr < (cptr)->freeptr; \
3735 eptr = (AfterTriggerEvent) (((char *) eptr) + SizeofTriggerEvent(eptr)))
3737#define for_each_event_chunk(eptr, cptr, evtlist) \
3738 for_each_chunk(cptr, evtlist) for_each_event(eptr, cptr)
3741#define for_each_chunk_from(cptr) \
3742 for (; cptr != NULL; cptr = cptr->next)
3743#define for_each_event_from(eptr, cptr) \
3745 (char *) eptr < (cptr)->freeptr; \
3746 eptr = (AfterTriggerEvent) (((char *) eptr) + SizeofTriggerEvent(eptr)))
3921 Oid tgoid,
bool tgisdeferred);
3986 for (
i = 0;
i <
state->numstates;
i++)
3988 if (
state->trigstates[
i].sct_tgoid == tgoid)
3989 return state->trigstates[
i].sct_tgisdeferred;
3993 if (
state->all_isset)
3994 return state->all_isdeferred;
4049 chunk = events->
tail;
4050 if (chunk == NULL ||
4051 chunk->endfree - chunk->freeptr < needed)
4059 "AfterTriggerEvents",
4077#define MIN_CHUNK_SIZE 1024
4078#define MAX_CHUNK_SIZE (1024*1024)
4080#if MAX_CHUNK_SIZE > (AFTER_TRIGGER_OFFSET+1)
4081#error MAX_CHUNK_SIZE must not exceed AFTER_TRIGGER_OFFSET
4089 chunksize = chunk->endptr - (
char *) chunk;
4091 if ((chunk->endptr - chunk->endfree) <=
4101 chunk->endptr = chunk->endfree = (
char *) chunk + chunksize;
4102 Assert(chunk->endfree - chunk->freeptr >= needed);
4104 if (events->
tail == NULL)
4107 events->
head = chunk;
4111 events->
tail = chunk;
4121 (
char *) newshared < chunk->endptr;
4135 if ((
char *) newshared >= chunk->endptr)
4138 *newshared = *evtshared;
4142 chunk->endfree = (
char *) newshared;
4147 memcpy(newevent, event, eventsize);
4149 newevent->
ate_flags &= ~AFTER_TRIGGER_OFFSET;
4150 newevent->
ate_flags |= (
char *) newshared - (
char *) newevent;
4152 chunk->freeptr += eventsize;
4167 while ((chunk = events->
head) != NULL)
4172 events->
tail = NULL;
4190 if (old_events->
tail == NULL)
4197 *events = *old_events;
4199 for (chunk = events->
tail->
next; chunk != NULL; chunk = next_chunk)
4201 next_chunk = chunk->
next;
4240 if (
table->after_trig_done &&
4241 table->after_trig_events.tail == target)
4243 table->after_trig_events.head = NULL;
4244 table->after_trig_events.tail = NULL;
4245 table->after_trig_events.tailfree = NULL;
4304 int save_sec_context;
4307 bool should_free_trig =
false;
4308 bool should_free_new =
false;
4315 if (trigdesc == NULL)
4317 for (tgindx = 0; tgindx < trigdesc->
numtriggers; tgindx++)
4346 elog(
ERROR,
"failed to fetch tuple1 for AFTER trigger");
4352 elog(
ERROR,
"failed to fetch tuple2 for AFTER trigger");
4373 LocTriggerData.
tg_newslot = trig_tuple_slot2;
4393 elog(
ERROR,
"failed to fetch tuple1 for AFTER trigger");
4399 if (src_relInfo != relInfo)
4435 elog(
ERROR,
"failed to fetch tuple2 for AFTER trigger");
4442 if (dst_relInfo != relInfo)
4499 LocTriggerData.
type = T_TriggerData;
4528 if (rettuple != NULL &&
4540 if (should_free_trig)
4542 if (should_free_new)
4546 if (trig_tuple_slot1 == NULL)
4580 bool immediate_only)
4583 bool deferred_found =
false;
4590 bool defer_it =
false;
4617 if (defer_it && move_list != NULL)
4619 deferred_found =
true;
4634 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4635 errmsg(
"cannot fire deferred trigger within security-restricted operation")));
4667 bool all_fired =
true;
4670 bool local_estate =
false;
4683 local_estate =
true;
4689 "AfterTriggerTupleContext",
4695 bool all_fired_in_chunk =
true;
4729 slot1 = slot2 = NULL;
4731 if (rel->
rd_rel->relkind == RELKIND_FOREIGN_TABLE)
4757 src_rInfo = dst_rInfo = rInfo;
4765 src_rInfo, dst_rInfo,
4766 trigdesc, finfo, instr,
4767 per_tuple_context, slot1, slot2);
4772 event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
4778 all_fired = all_fired_in_chunk =
false;
4783 if (delete_ok && all_fired_in_chunk)
4794 if (chunk == events->
tail)
4846 if (
table->relid == relid &&
table->cmdType == cmdType &&
4854 table->relid = relid;
4855 table->cmdType = cmdType;
4872 if (!
table->storeslot)
4888 return table->storeslot;
4928 if (trigdesc == NULL)
4935 need_old_upd = need_old_del = need_new_upd =
false;
4941 need_old_del = need_new_ins =
false;
4945 need_old_upd = need_new_upd = need_new_ins =
false;
4954 elog(
ERROR,
"unexpected CmdType: %d", (
int) cmdType);
4956 need_old_upd = need_new_upd = need_old_del = need_new_ins =
false;
4959 if (!need_old_upd && !need_new_upd && !need_new_ins && !need_old_del)
4964 elog(
ERROR,
"MakeTransitionCaptureState() called outside of query");
4989 if (need_old_upd &&
table->old_upd_tuplestore == NULL)
4991 if (need_new_upd &&
table->new_upd_tuplestore == NULL)
4993 if (need_old_del &&
table->old_del_tuplestore == NULL)
4995 if (need_new_ins &&
table->new_ins_tuplestore == NULL)
5003 state->tcs_delete_old_table = need_old_del;
5004 state->tcs_update_old_table = need_old_upd;
5005 state->tcs_update_new_table = need_new_upd;
5006 state->tcs_insert_new_table = need_new_ins;
5200 ts =
table->old_upd_tuplestore;
5201 table->old_upd_tuplestore = NULL;
5204 ts =
table->new_upd_tuplestore;
5205 table->new_upd_tuplestore = NULL;
5208 ts =
table->old_del_tuplestore;
5209 table->old_del_tuplestore = NULL;
5212 ts =
table->new_ins_tuplestore;
5213 table->new_ins_tuplestore = NULL;
5216 if (
table->storeslot)
5220 table->storeslot = NULL;
5250 bool snap_pushed =
false;
5261 if (events->
head != NULL)
5559 if (tuplestore == NULL)
5562 if (original_insert_tuple)
5650 state->numalloc = numalloc;
5680 Oid tgoid,
bool tgisdeferred)
5684 int newalloc =
state->numalloc * 2;
5686 newalloc =
Max(newalloc, 8);
5691 state->numalloc = newalloc;
5695 state->trigstates[
state->numstates].sct_tgoid = tgoid;
5696 state->trigstates[
state->numstates].sct_tgisdeferred = tgisdeferred;
5768 foreach(lc,
stmt->constraints)
5772 List *namespacelist;
5779 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5780 errmsg(
"cross-database references are not implemented: \"%s.%s.%s\"",
5803 foreach(nslc, namespacelist)
5811 Anum_pg_constraint_conname,
5815 Anum_pg_constraint_connamespace,
5820 true, NULL, 2, skey);
5826 if (con->condeferrable)
5828 else if (
stmt->deferred)
5830 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
5831 errmsg(
"constraint \"%s\" is not deferrable",
5853 (
errcode(ERRCODE_UNDEFINED_OBJECT),
5854 errmsg(
"constraint \"%s\" does not exist",
5864 foreach(lc, conoidlist)
5872 Anum_pg_constraint_conparentid,
5896 foreach(lc, conoidlist)
5904 Anum_pg_trigger_tgconstraint,
5921 if (pg_trigger->tgdeferrable)
5922 tgoidlist =
lappend_oid(tgoidlist, pg_trigger->oid);
5934 foreach(lc, tgoidlist)
5941 for (
i = 0;
i <
state->numstates;
i++)
5943 if (
state->trigstates[
i].sct_tgoid == tgoid)
5945 state->trigstates[
i].sct_tgisdeferred =
stmt->deferred;
5969 if (!
stmt->deferred)
5972 bool snapshot_set =
false;
5990 snapshot_set =
true;
6114 int event,
bool row_trigger,
6118 bool is_crosspart_update)
6124 char relkind = rel->
rd_rel->relkind;
6136 elog(
ERROR,
"AfterTriggerSaveEvent() called outside of query");
6146 if (row_trigger && transition_capture != NULL)
6161 transition_capture);
6163 oldslot, NULL, old_tuplestore);
6177 transition_capture);
6179 newslot, original_insert_tuple, new_tuplestore);
6189 if (trigdesc == NULL ||
6205 rel->
rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
6206 (is_crosspart_update &&
6208 src_partinfo != NULL && dst_partinfo != NULL));
6225 tgtype_event = TRIGGER_TYPE_INSERT;
6244 tgtype_event = TRIGGER_TYPE_DELETE;
6263 tgtype_event = TRIGGER_TYPE_UPDATE;
6275 if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6277 Assert(src_partinfo != NULL && dst_partinfo != NULL);
6295 tgtype_event = TRIGGER_TYPE_TRUNCATE;
6302 elog(
ERROR,
"invalid after-trigger event code: %d", event);
6308 if (!(relkind == RELKIND_FOREIGN_TABLE && row_trigger))
6312 if (relkind == RELKIND_PARTITIONED_TABLE)
6323 tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
6330 if (row_trigger && rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6358 if (!TRIGGER_TYPE_MATCHES(trigger->
tgtype,
6364 modifiedCols, oldslot, newslot))
6367 if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
6369 if (fdw_tuplestore == NULL)
6401 if (is_crosspart_update &&
6428 if (rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
6448 rel->
rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6459 if (trigger->
tgfoid == F_UNIQUE_KEY_RECHECK)
6480 transition_capture != NULL)
6487 &new_event, &new_shared);
6497 if (oldslot != NULL)
6499 if (newslot != NULL)
6516 elog(
ERROR,
"before_stmt_triggers_fired() called outside of query");
6530 result =
table->before_trig_done;
6531 table->before_trig_done =
true;
6569 if (
table->after_trig_done)
6580 if (
table->after_trig_events.tail)
6582 chunk =
table->after_trig_events.tail;
6612 event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
6622 table->after_trig_done =
true;
6665 for (
int i = 0;
i < tupdesc->
natts;
i++)
6667 if (
TupleDescAttr(tupdesc,
i)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
6671 int replCol =
i + 1;
6672 Datum replValue = 0;
6673 bool replIsnull =
true;
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
#define InvalidAttrNumber
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
bool bms_is_member(int x, const Bitmapset *a)
Bitmapset * bms_copy(const Bitmapset *a)
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
#define TextDatumGetCString(d)
#define FLEXIBLE_ARRAY_MEMBER
#define OidIsValid(objectId)
bool IsSystemRelation(Relation relation)
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
char * get_database_name(Oid dbid)
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,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
ExprState * ExecPrepareQual(List *qual, EState *estate)
LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
ResultRelInfo * ExecGetTriggerResultRel(EState *estate, Oid relid, ResultRelInfo *rootRelInfo)
bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
TupleTableSlot * EvalPlanQual(EPQState *epqstate, Relation relation, Index rti, TupleTableSlot *inputslot)
void ExecCloseResultRelations(EState *estate)
void ExecResetTupleTable(List *tupleTable, bool shouldFree)
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
const TupleTableSlotOps TTSOpsVirtual
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
const TupleTableSlotOps TTSOpsMinimalTuple
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
TupleTableSlot * ExecGetTriggerNewSlot(EState *estate, ResultRelInfo *relInfo)
TupleConversionMap * ExecGetChildToRootMap(ResultRelInfo *resultRelInfo)
TupleTableSlot * ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
void FreeExecutorState(EState *estate)
Bitmapset * ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
EState * CreateExecutorState(void)
#define GetPerTupleExprContext(estate)
#define GetPerTupleMemoryContext(estate)
static bool ExecQual(ExprState *state, ExprContext *econtext)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
#define DatumGetByteaPP(X)
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
#define DirectFunctionCall1(func, arg1)
#define LOCAL_FCINFO(name, nargs)
#define FunctionCallInvoke(fcinfo)
#define PG_RETURN_INT32(x)
void systable_endscan(SysScanDesc sysscan)
HeapTuple systable_getnext(SysScanDesc sysscan)
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
bool allowSystemTableMods
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_copytuple(HeapTuple tuple)
HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, TupleDesc tupleDesc, int nCols, const int *replCols, const Datum *replValues, const bool *replIsnull)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
void heap_freetuple(HeapTuple htup)
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
void InstrStartNode(Instrumentation *instr)
void InstrStopNode(Instrumentation *instr, double nTuples)
int2vector * buildint2vector(const int16 *int2s, int n)
void CacheInvalidateRelcache(Relation relation)
void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
static void ItemPointerSetInvalid(ItemPointerData *pointer)
static void ItemPointerCopy(const ItemPointerData *fromPointer, ItemPointerData *toPointer)
static bool ItemPointerIsValid(const ItemPointerData *pointer)
List * lappend(List *list, void *datum)
List * lappend_oid(List *list, Oid datum)
void list_free(List *list)
bool list_member_oid(const List *list, Oid datum)
void list_free_deep(List *list)
void LockRelationOid(Oid relid, LOCKMODE lockmode)
#define AccessExclusiveLock
#define ShareRowExclusiveLock
char * get_rel_name(Oid relid)
char get_rel_relkind(Oid relid)
char * get_namespace_name(Oid nspid)
Oid get_func_rettype(Oid funcid)
Alias * makeAlias(const char *aliasname, List *colnames)
List * make_ands_implicit(Expr *clause)
void * MemoryContextAlloc(MemoryContext context, Size size)
void MemoryContextReset(MemoryContext context)
void * MemoryContextAllocZero(MemoryContext context, Size size)
MemoryContext TopTransactionContext
char * pstrdup(const char *in)
void * repalloc(void *pointer, Size size)
void pfree(void *pointer)
void * palloc0(Size size)
MemoryContext CurTransactionContext
MemoryContext CurrentMemoryContext
MemoryContext CacheMemoryContext
void MemoryContextDelete(MemoryContext context)
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define ALLOCSET_SMALL_SIZES
#define SECURITY_LOCAL_USERID_CHANGE
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
bool InSecurityRestrictedOperation(void)
void SetUserIdAndSecContext(Oid userid, int sec_context)
Datum nameout(PG_FUNCTION_ARGS)
void namestrcpy(Name name, const char *str)
Datum namein(PG_FUNCTION_ARGS)
char * NameListToString(const List *names)
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
List * fetch_search_path(bool includeImplicit)
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
#define RangeVarGetRelid(relation, lockmode, missing_ok)
TupleTableSlot * ExecGetUpdateNewTuple(ResultRelInfo *relinfo, TupleTableSlot *planSlot, TupleTableSlot *oldSlot)
#define InvokeObjectPostAlterHook(classId, objectId, subId)
#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)
Oid get_partition_parent(Oid relid, bool even_if_detached)
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)
FormData_pg_constraint * Form_pg_constraint
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
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)
#define list_make1_oid(x1)
static const struct lconv_member_info table[]
FormData_pg_trigger * Form_pg_trigger
#define ERRCODE_T_R_SERIALIZATION_FAILURE
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
void ResetPlanCache(void)
static Datum PointerGetDatum(const void *X)
static Datum Int16GetDatum(int16 X)
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
static char * DatumGetCString(Datum X)
static Datum NameGetDatum(const NameData *X)
static Pointer DatumGetPointer(Datum X)
static Datum CStringGetDatum(const char *X)
void * stringToNode(const char *str)
#define RelationHasReferenceCountZero(relation)
#define RelationGetRelid(relation)
#define RelationGetDescr(relation)
#define RelationGetRelationName(relation)
#define RelationGetNamespace(relation)
ResourceOwner CurrentResourceOwner
ResourceOwner CurTransactionResourceOwner
Node * expand_generated_columns_in_expr(Node *node, Relation rel, int rt_index)
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
bool RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel, TupleTableSlot *oldslot, TupleTableSlot *newslot)
bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, TupleTableSlot *oldslot, TupleTableSlot *newslot)
int RI_FKey_trigger_type(Oid tgfoid)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Snapshot GetTransactionSnapshot(void)
void PushActiveSnapshot(Snapshot snapshot)
void PopActiveSnapshot(void)
void relation_close(Relation relation, LOCKMODE lockmode)
Relation relation_open(Oid relationId, LOCKMODE lockmode)
#define BTEqualStrategyNumber
#define ERRCODE_DUPLICATE_OBJECT
struct AfterTriggerEventChunk * next
ItemPointerData ate_ctid1
ItemPointerData ate_ctid2
ItemPointerData ate_ctid1
ItemPointerData ate_ctid2
ItemPointerData ate_ctid1
AfterTriggerEventChunk * head
AfterTriggerEventChunk * tail
struct AfterTriggersTableData * ats_table
Bitmapset * ats_modifiedcols
AfterTriggersQueryData * query_stack
AfterTriggersTransData * trans_stack
AfterTriggerEventList events
Tuplestorestate * fdw_tuplestore
AfterTriggerEventList events
TupleTableSlot * storeslot
Tuplestorestate * old_upd_tuplestore
Tuplestorestate * new_upd_tuplestore
Tuplestorestate * old_del_tuplestore
Tuplestorestate * new_ins_tuplestore
AfterTriggerEventList after_trig_events
AfterTriggerEventList events
PlannedStmt * es_plannedstmt
MemoryContext es_query_cxt
TupleTableSlot * ecxt_innertuple
TupleTableSlot * ecxt_outertuple
const char * p_sourcetext
struct ResultRelInfo * ri_RootResultRelInfo
Instrumentation * ri_TrigInstrument
TriggerDesc * ri_TrigDesc
ExprState ** ri_TrigWhenExprs
FmgrInfo * ri_TrigFunctions
SetConstraintTriggerData trigstates[FLEXIBLE_ARRAY_MEMBER]
struct AfterTriggersTableData * tcs_private
TupleTableSlot * tcs_original_insert_tuple
bool tcs_update_new_table
bool tcs_delete_old_table
bool tcs_insert_new_table
bool tcs_update_old_table
Tuplestorestate * tg_oldtable
const Bitmapset * tg_updatedcols
Tuplestorestate * tg_newtable
TupleTableSlot * tg_trigslot
TupleTableSlot * tg_newslot
bool trig_delete_before_row
bool trig_update_instead_row
bool trig_delete_instead_row
bool trig_update_after_row
bool trig_insert_instead_row
bool trig_update_new_table
bool trig_insert_after_row
bool trig_update_after_statement
bool trig_update_before_row
bool trig_truncate_before_statement
bool trig_insert_new_table
bool trig_update_before_statement
bool trig_truncate_after_statement
bool trig_insert_before_statement
bool trig_delete_old_table
bool trig_delete_after_row
bool trig_insert_before_row
bool trig_delete_after_statement
bool trig_delete_before_statement
bool trig_update_old_table
bool trig_insert_after_statement
bool has_generated_virtual
#define FirstLowInvalidHeapAttributeNumber
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
#define SearchSysCacheCopy1(cacheId, key1)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)
static TM_Result table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, uint8 flags, TM_FailureData *tmfd)
#define TUPLE_LOCK_FLAG_FIND_LAST_VERSION
static bool table_tuple_fetch_row_version(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot)
static SetConstraintState SetConstraintStateCopy(SetConstraintState origstate)
struct AfterTriggerSharedData AfterTriggerSharedData
static void cancel_prior_stmt_triggers(Oid relid, CmdType cmdType, int tgevent)
static AfterTriggersData afterTriggers
#define AFTER_TRIGGER_FDW_FETCH
bool ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *newslot, TM_Result *tmresult, TM_FailureData *tmfd)
struct AfterTriggerEventData AfterTriggerEventData
static SetConstraintState SetConstraintStateAddItem(SetConstraintState state, Oid tgoid, bool tgisdeferred)
#define AFTER_TRIGGER_IN_PROGRESS
static void renametrig_internal(Relation tgrel, Relation targetrel, HeapTuple trigtup, const char *newname, const char *expected_name)
TransitionCaptureState * MakeTransitionCaptureState(TriggerDesc *trigdesc, Oid relid, CmdType cmdType)
void AfterTriggerBeginXact(void)
void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TransitionCaptureState *transition_capture, bool is_crosspart_update)
void ExecBSInsertTriggers(EState *estate, ResultRelInfo *relinfo)
static void afterTriggerDeleteHeadEventChunk(AfterTriggersQueryData *qs)
static AfterTriggersTableData * GetAfterTriggersTableData(Oid relid, CmdType cmdType)
static Bitmapset * afterTriggerCopyBitmap(Bitmapset *src)
#define CHUNK_DATA_START(cptr)
static void RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
bool ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
void AfterTriggerEndSubXact(bool isCommit)
void ExecBSTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
#define AFTER_TRIGGER_TUP_BITS
static bool TriggerEnabled(EState *estate, ResultRelInfo *relinfo, Trigger *trigger, TriggerEvent event, Bitmapset *modifiedCols, TupleTableSlot *oldslot, TupleTableSlot *newslot)
void FreeTriggerDesc(TriggerDesc *trigdesc)
bool ExecIRDeleteTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple)
#define AFTER_TRIGGER_1CTID
Datum pg_trigger_depth(PG_FUNCTION_ARGS)
void ExecBSDeleteTriggers(EState *estate, ResultRelInfo *relinfo)
void EnableDisableTrigger(Relation rel, const char *tgname, Oid tgparent, char fires_when, bool skip_system, bool recurse, LOCKMODE lockmode)
static void AfterTriggerFreeQuery(AfterTriggersQueryData *qs)
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata, int tgindx, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context)
static void afterTriggerFreeEventList(AfterTriggerEventList *events)
const char * FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc)
bool ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
#define GetTriggerSharedData(evt)
static int MyTriggerDepth
#define for_each_chunk_from(cptr)
static bool afterTriggerMarkEvents(AfterTriggerEventList *events, AfterTriggerEventList *move_list, bool immediate_only)
static Tuplestorestate * GetAfterTriggersTransitionTable(int event, TupleTableSlot *oldslot, TupleTableSlot *newslot, TransitionCaptureState *transition_capture)
void ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
static bool afterTriggerInvokeEvents(AfterTriggerEventList *events, CommandId firing_id, EState *estate, bool delete_ok)
void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ResultRelInfo *src_partinfo, ResultRelInfo *dst_partinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *newslot, List *recheckIndexes, TransitionCaptureState *transition_capture, bool is_crosspart_update)
struct AfterTriggerSharedData * AfterTriggerShared
void AfterTriggerSetState(ConstraintsSetStmt *stmt)
Oid get_trigger_oid(Oid relid, const char *trigname, bool missing_ok)
ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, bool isInternal, bool in_partition)
static bool before_stmt_triggers_fired(Oid relid, CmdType cmdType)
static void afterTriggerAddEvent(AfterTriggerEventList *events, AfterTriggerEvent event, AfterTriggerShared evtshared)
struct SetConstraintTriggerData * SetConstraintTrigger
struct AfterTriggersData AfterTriggersData
struct AfterTriggerEventDataNoOids AfterTriggerEventDataNoOids
#define AFTER_TRIGGER_2CTID
#define SizeofTriggerEvent(evt)
int SessionReplicationRole
static bool afterTriggerCheckState(AfterTriggerShared evtshared)
struct AfterTriggerEventChunk AfterTriggerEventChunk
static void AfterTriggerExecute(EState *estate, AfterTriggerEvent event, ResultRelInfo *relInfo, ResultRelInfo *src_relInfo, ResultRelInfo *dst_relInfo, TriggerDesc *trigdesc, FmgrInfo *finfo, Instrumentation *instr, MemoryContext per_tuple_context, TupleTableSlot *trig_tuple_slot1, TupleTableSlot *trig_tuple_slot2)
void ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
static SetConstraintState SetConstraintStateCreate(int numalloc)
void ExecASDeleteTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
bool ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot **epqslot, TM_Result *tmresult, TM_FailureData *tmfd)
ObjectAddress renametrig(RenameStmt *stmt)
void AfterTriggerFireDeferred(void)
void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot, List *recheckIndexes, TransitionCaptureState *transition_capture)
struct SetConstraintTriggerData SetConstraintTriggerData
void TriggerSetParentTrigger(Relation trigRel, Oid childTrigId, Oid parentTrigId, Oid childTableId)
static void afterTriggerRestoreEventList(AfterTriggerEventList *events, const AfterTriggerEventList *old_events)
static void SetTriggerFlags(TriggerDesc *trigdesc, Trigger *trigger)
#define for_each_event_from(eptr, cptr)
static void TransitionTableAddTuple(EState *estate, TransitionCaptureState *transition_capture, ResultRelInfo *relinfo, TupleTableSlot *slot, TupleTableSlot *original_insert_tuple, Tuplestorestate *tuplestore)
static void renametrig_partition(Relation tgrel, Oid partitionId, Oid parentTriggerOid, const char *newname, const char *expected_name)
struct AfterTriggerEventDataZeroCtids AfterTriggerEventDataZeroCtids
void ExecASInsertTriggers(EState *estate, ResultRelInfo *relinfo, TransitionCaptureState *transition_capture)
static Tuplestorestate * GetCurrentFDWTuplestore(void)
ObjectAddress CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, Oid funcoid, Oid parentTriggerOid, Node *whenClause, bool isInternal, bool in_partition, char trigger_fires_when)
TriggerDesc * CopyTriggerDesc(TriggerDesc *trigdesc)
void assign_session_replication_role(int newval, void *extra)
bool ExecIRUpdateTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, TupleTableSlot *newslot)
void AfterTriggerEndXact(bool isCommit)
struct AfterTriggerEventDataOneCtid AfterTriggerEventDataOneCtid
bool AfterTriggerPendingOnRel(Oid relid)
struct SetConstraintStateData SetConstraintStateData
#define AFTER_TRIGGER_FDW_REUSE
void RelationBuildTriggers(Relation relation)
void AfterTriggerBeginSubXact(void)
static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, ResultRelInfo *src_partinfo, ResultRelInfo *dst_partinfo, int event, bool row_trigger, TupleTableSlot *oldslot, TupleTableSlot *newslot, List *recheckIndexes, Bitmapset *modifiedCols, TransitionCaptureState *transition_capture, bool is_crosspart_update)
static HeapTuple check_modified_virtual_generated(TupleDesc tupdesc, HeapTuple tuple)
static bool GetTupleForTrigger(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tid, LockTupleMode lockmode, TupleTableSlot *oldslot, TupleTableSlot **epqslot, TM_Result *tmresultp, TM_FailureData *tmfdp)
struct AfterTriggerEventList AfterTriggerEventList
static TupleTableSlot * GetAfterTriggersStoreSlot(AfterTriggersTableData *table, TupleDesc tupdesc)
#define AFTER_TRIGGER_CP_UPDATE
void AfterTriggerEndQuery(EState *estate)
void RemoveTriggerById(Oid trigOid)
#define AFTER_TRIGGER_DONE
#define for_each_event_chunk(eptr, cptr, evtlist)
SetConstraintStateData * SetConstraintState
static void AfterTriggerEnlargeQueryState(void)
#define for_each_event(eptr, cptr)
struct AfterTriggerEventData * AfterTriggerEvent
#define for_each_chunk(cptr, evtlist)
void ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
void AfterTriggerAbortQuery(void)
void AfterTriggerBeginQuery(void)
#define AFTER_TRIGGER_DEFERRABLE
#define TRIGGER_FIRED_FOR_STATEMENT(event)
#define TRIGGER_EVENT_UPDATE
#define TRIGGER_FIRED_BY_DELETE(event)
#define SESSION_REPLICATION_ROLE_REPLICA
#define TRIGGER_EVENT_DELETE
#define TRIGGER_FIRES_ON_ORIGIN
#define TRIGGER_EVENT_OPMASK
#define TRIGGER_FIRES_ON_REPLICA
#define AFTER_TRIGGER_INITDEFERRED
#define TRIGGER_EVENT_INSTEAD
#define TRIGGER_EVENT_ROW
#define TRIGGER_FIRED_AFTER(event)
#define TRIGGER_EVENT_BEFORE
#define TRIGGER_FIRED_BY_INSERT(event)
#define SESSION_REPLICATION_ROLE_ORIGIN
#define TRIGGER_EVENT_INSERT
#define TRIGGER_FIRED_BY_UPDATE(event)
#define TRIGGER_EVENT_TRUNCATE
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
void tuplestore_end(Tuplestorestate *state)
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
static void ExecMaterializeSlot(TupleTableSlot *slot)
List * pull_var_clause(Node *node, int flags)
Datum byteain(PG_FUNCTION_ARGS)
int GetCurrentTransactionNestLevel(void)
void CommandCounterIncrement(void)
bool IsSubTransaction(void)
#define IsolationUsesXactSnapshot()