PostgreSQL Source Code: src/backend/commands/trigger.c Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
15
51#include "utils/fmgroids.h"
61
62
63
65
66
68
69
71 HeapTuple trigtup, const char *newname,
72 const char *expected_name);
74 Oid parentTriggerOid, const char *newname,
75 const char *expected_name);
91 int tgindx,
98 int event, bool row_trigger,
102 bool is_crosspart_update);
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
161 Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
162 Oid funcoid, Oid parentTriggerOid, Node *whenClause,
163 bool isInternal, bool in_partition)
164{
165 return
167 constraintOid, indexOid, funcoid,
168 parentTriggerOid, whenClause, isInternal,
170}
171
172
173
174
175
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)
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}
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219void
1221 Oid childTrigId,
1222 Oid parentTrigId,
1223 Oid childTableId)
1224{
1229 newtup;
1232
1233
1234
1235
1237 Anum_pg_trigger_oid,
1240
1242 NULL, 1, skey);
1243
1246 elog(ERROR, "could not find tuple for trigger %u", childTrigId);
1250 {
1251
1252 if (OidIsValid(trigForm->tgparentid))
1253 elog(ERROR, "trigger %u already has a parent trigger",
1254 childTrigId);
1255
1256 trigForm->tgparentid = parentTrigId;
1257
1259
1261
1262 ObjectAddressSet(referenced, TriggerRelationId, parentTrigId);
1264
1265 ObjectAddressSet(referenced, RelationRelationId, childTableId);
1267 }
1268 else
1269 {
1271
1273
1275 TriggerRelationId,
1278 RelationRelationId,
1280 }
1281
1284}
1285
1286
1287
1288
1289
1290void
1292{
1297 Oid relid;
1299
1301
1302
1303
1304
1306 Anum_pg_trigger_oid,
1309
1311 NULL, 1, skey);
1312
1315 elog(ERROR, "could not find tuple for trigger %u", trigOid);
1316
1317
1318
1319
1321
1323
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",
1333
1336 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1337 errmsg("permission denied: \"%s\" is a system catalog",
1339
1340
1341
1342
1344
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1358
1359
1361}
1362
1363
1364
1365
1366
1367
1368
1371{
1376 Oid oid;
1377
1378
1379
1380
1382
1384 Anum_pg_trigger_tgrelid,
1388 Anum_pg_trigger_tgname,
1391
1393 NULL, 2, skey);
1394
1396
1398 {
1399 if (!missing_ok)
1401 (errcode(ERRCODE_UNDEFINED_OBJECT),
1402 errmsg("trigger \"%s\" for table \"%s\" does not exist",
1405 }
1406 else
1407 {
1409 }
1410
1413 return oid;
1414}
1415
1416
1417
1418
1419static void
1421 void *arg)
1422{
1425
1428 return;
1430
1431
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",
1440
1441
1446 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1447 errmsg("permission denied: \"%s\" is a system catalog",
1449
1451}
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1468{
1469 Oid tgoid;
1475 Oid relid;
1477
1478
1479
1480
1481
1483 0,
1485 NULL);
1486
1487
1489
1490
1491
1492
1493
1494 if (targetrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1496
1498
1499
1500
1501
1503 Anum_pg_trigger_tgrelid,
1507 Anum_pg_trigger_tgname,
1511 NULL, 2, key);
1513 {
1515
1517 tgoid = trigform->oid;
1518
1519
1520
1521
1522
1523
1524
1525 if (OidIsValid(trigform->tgparentid))
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.",
1532
1533
1534
1536 stmt->subname);
1537
1538
1539 if (targetrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1540 {
1542
1543 for (int i = 0; i < partdesc->nparts; i++)
1544 {
1545 Oid partitionId = partdesc->oids[i];
1546
1548 stmt->newname, stmt->subname);
1549 }
1550 }
1551 }
1552 else
1553 {
1555 (errcode(ERRCODE_UNDEFINED_OBJECT),
1556 errmsg("trigger \"%s\" for table \"%s\" does not exist",
1558 }
1559
1561
1563
1565
1566
1567
1568
1570
1571 return address;
1572}
1573
1574
1575
1576
1577
1578
1579
1580
1581static void
1583 const char *newname, const char *expected_name)
1584{
1589
1590
1592 if (strcmp(NameStr(tgform->tgname), newname) == 0)
1593 return;
1594
1595
1596
1597
1598
1599
1601 Anum_pg_trigger_tgrelid,
1605 Anum_pg_trigger_tgname,
1609 NULL, 2, key);
1613 errmsg("trigger \"%s\" for relation \"%s\" already exists",
1616
1617
1618
1619
1620 tuple = heap_copytuple(trigtup);
1622
1623
1624
1625
1626
1627
1628 if (strcmp(NameStr(tgform->tgname), expected_name) != 0)
1630 errmsg("renamed trigger \"%s\" on relation \"%s\"",
1631 NameStr(tgform->tgname),
1633
1634 namestrcpy(&tgform->tgname, newname);
1635
1637
1639
1640
1641
1642
1643
1644
1646}
1647
1648
1649
1650
1651
1652static void
1654 const char *newname, const char *expected_name)
1655{
1659
1660
1661
1662
1663
1664
1666 Anum_pg_trigger_tgrelid,
1670 NULL, 1, &key);
1672 {
1675
1676 if (tgform->tgparentid != parentTriggerOid)
1677 continue;
1678
1680
1681
1682 renametrig_internal(tgrel, partitionRel, tuple, newname, expected_name);
1683
1684
1685 if (partitionRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1686 {
1688 true);
1689
1690 for (int i = 0; i < partdesc->nparts; i++)
1691 {
1692 Oid partoid = partdesc->oids[i];
1693
1695 NameStr(tgform->tgname));
1696 }
1697 }
1699
1700
1701 break;
1702 }
1704}
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725void
1727 char fires_when, bool skip_system, bool recurse,
1729{
1731 int nkeys;
1735 bool found;
1736 bool changed;
1737
1738
1740
1742 Anum_pg_trigger_tgrelid,
1745 if (tgname)
1746 {
1748 Anum_pg_trigger_tgname,
1751 nkeys = 2;
1752 }
1753 else
1754 nkeys = 1;
1755
1757 NULL, nkeys, keys);
1758
1759 found = changed = false;
1760
1762 {
1764
1765 if (OidIsValid(tgparent) && tgparent != oldtrig->tgparentid)
1766 continue;
1767
1768 if (oldtrig->tgisinternal)
1769 {
1770
1771 if (skip_system)
1772 continue;
1775 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1776 errmsg("permission denied: \"%s\" is a system trigger",
1777 NameStr(oldtrig->tgname))));
1778 }
1779
1780 found = true;
1781
1782 if (oldtrig->tgenabled != fires_when)
1783 {
1784
1787
1788 newtrig->tgenabled = fires_when;
1789
1791
1793
1794 changed = true;
1795 }
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806 if (recurse &&
1807 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
1808 (TRIGGER_FOR_ROW(oldtrig->tgtype)))
1809 {
1811 int i;
1812
1813 for (i = 0; i < partdesc->nparts; i++)
1814 {
1816
1818
1820 fires_when, skip_system, recurse,
1821 lockmode);
1823 }
1824 }
1825
1827 oldtrig->oid, 0);
1828 }
1829
1831
1833
1834 if (tgname && !found)
1836 (errcode(ERRCODE_UNDEFINED_OBJECT),
1837 errmsg("trigger \"%s\" for table \"%s\" does not exist",
1839
1840
1841
1842
1843
1844
1845 if (changed)
1847}
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860void
1862{
1864 int numtrigs;
1865 int maxtrigs;
1872 int i;
1873
1874
1875
1876
1877
1878 maxtrigs = 16;
1880 numtrigs = 0;
1881
1882
1883
1884
1885
1886
1887
1889 Anum_pg_trigger_tgrelid,
1892
1895 NULL, 1, &skey);
1896
1898 {
1902 bool isnull;
1903
1904 if (numtrigs >= maxtrigs)
1905 {
1906 maxtrigs *= 2;
1908 }
1909 build = &(triggers[numtrigs]);
1910
1911 build->tgoid = pg_trigger->oid;
1914 build->tgfoid = pg_trigger->tgfoid;
1915 build->tgtype = pg_trigger->tgtype;
1916 build->tgenabled = pg_trigger->tgenabled;
1917 build->tgisinternal = pg_trigger->tgisinternal;
1919 build->tgconstrrelid = pg_trigger->tgconstrrelid;
1920 build->tgconstrindid = pg_trigger->tgconstrindid;
1921 build->tgconstraint = pg_trigger->tgconstraint;
1922 build->tgdeferrable = pg_trigger->tgdeferrable;
1924 build->tgnargs = pg_trigger->tgnargs;
1925
1926 build->tgnattr = pg_trigger->tgattr.dim1;
1928 {
1930 memcpy(build->tgattr, &(pg_trigger->tgattr.values),
1932 }
1933 else
1934 build->tgattr = NULL;
1936 {
1938 char *p;
1939
1941 Anum_pg_trigger_tgargs,
1942 tgrel->rd_att, &isnull));
1943 if (isnull)
1944 elog(ERROR, "tgargs is null in trigger for relation \"%s\"",
1948 for (i = 0; i < build->tgnargs; i++)
1949 {
1951 p += strlen(p) + 1;
1952 }
1953 }
1954 else
1955 build->tgargs = NULL;
1956
1957 datum = fastgetattr(htup, Anum_pg_trigger_tgoldtable,
1958 tgrel->rd_att, &isnull);
1959 if (!isnull)
1962 else
1964
1965 datum = fastgetattr(htup, Anum_pg_trigger_tgnewtable,
1966 tgrel->rd_att, &isnull);
1967 if (!isnull)
1970 else
1972
1973 datum = fastgetattr(htup, Anum_pg_trigger_tgqual,
1974 tgrel->rd_att, &isnull);
1975 if (!isnull)
1977 else
1978 build->tgqual = NULL;
1979
1980 numtrigs++;
1981 }
1982
1985
1986
1987 if (numtrigs == 0)
1988 {
1989 pfree(triggers);
1990 return;
1991 }
1992
1993
1995 trigdesc->triggers = triggers;
1997 for (i = 0; i < numtrigs; i++)
1999
2000
2004
2005
2007}
2008
2009
2010
2011
2012static void
2014{
2016
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);
2062
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);
2069
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));
2082}
2083
2084
2085
2086
2087
2088
2091{
2094 int i;
2095
2096 if (trigdesc == NULL || trigdesc->numtriggers <= 0)
2097 return NULL;
2098
2100 memcpy(newdesc, trigdesc, sizeof(TriggerDesc));
2101
2103 memcpy(trigger, trigdesc->triggers,
2105 newdesc->triggers = trigger;
2106
2108 {
2110 if (trigger->tgnattr > 0)
2111 {
2113
2115 memcpy(newattr, trigger->tgattr,
2117 trigger->tgattr = newattr;
2118 }
2119 if (trigger->tgnargs > 0)
2120 {
2121 char **newargs;
2123
2124 newargs = (char **) palloc(trigger->tgnargs * sizeof(char *));
2125 for (j = 0; j < trigger->tgnargs; j++)
2127 trigger->tgargs = newargs;
2128 }
2129 if (trigger->tgqual)
2135 trigger++;
2136 }
2137
2138 return newdesc;
2139}
2140
2141
2142
2143
2144void
2146{
2148 int i;
2149
2150 if (trigdesc == NULL)
2151 return;
2152
2153 trigger = trigdesc->triggers;
2155 {
2157 if (trigger->tgnattr > 0)
2159 if (trigger->tgnargs > 0)
2160 {
2161 while (--(trigger->tgnargs) >= 0)
2164 }
2165 if (trigger->tgqual)
2171 trigger++;
2172 }
2174 pfree(trigdesc);
2175}
2176
2177
2178
2179
2180#ifdef NOT_USED
2181bool
2183{
2184 int i,
2185 j;
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199 if (trigdesc1 != NULL)
2200 {
2201 if (trigdesc2 == NULL)
2202 return false;
2204 return false;
2206 {
2209
2211 return false;
2212 if (strcmp(trig1->tgname, trig2->tgname) != 0)
2213 return false;
2215 return false;
2217 return false;
2219 return false;
2221 return false;
2223 return false;
2225 return false;
2227 return false;
2229 return false;
2231 return false;
2233 return false;
2235 return false;
2237 return false;
2238 if (trig1->tgnattr > 0 &&
2241 return false;
2242 for (j = 0; j < trig1->tgnargs; j++)
2243 if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0)
2244 return false;
2245 if (trig1->tgqual == NULL && trig2->tgqual == NULL)
2246 ;
2247 else if (trig1->tgqual == NULL || trig2->tgqual == NULL)
2248 return false;
2249 else if (strcmp(trig1->tgqual, trig2->tgqual) != 0)
2250 return false;
2252 ;
2254 return false;
2256 return false;
2258 ;
2260 return false;
2262 return false;
2263 }
2264 }
2265 else if (trigdesc2 != NULL)
2266 return false;
2267 return true;
2268}
2269#endif
2270
2271
2272
2273
2274
2275
2276const char *
2278{
2279 if (trigdesc != NULL)
2280 {
2281 int i;
2282
2284 {
2286
2288 return trigger->tgname;
2289 }
2290 }
2291
2292 return NULL;
2293}
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2308 int tgindx,
2312{
2317
2318
2319
2320
2321
2329
2330 finfo += tgindx;
2331
2332
2333
2334
2335
2338
2340
2341
2342
2343
2344 if (instr)
2346
2347
2348
2349
2350
2351
2352
2354
2355
2356
2357
2360
2362
2365 {
2367 }
2369 {
2371 }
2373
2375
2377
2378
2379
2380
2381
2382 if (fcinfo->isnull)
2384 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2385 errmsg("trigger function %u returned null value",
2386 fcinfo->flinfo->fn_oid)));
2387
2388
2389
2390
2391
2392 if (instr)
2394
2396}
2397
2398void
2400{
2402 int i;
2404
2406
2407 if (trigdesc == NULL)
2408 return;
2410 return;
2411
2412
2415 return;
2416
2417 LocTriggerData.type = T_TriggerData;
2422 {
2425
2426 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2427 TRIGGER_TYPE_STATEMENT,
2428 TRIGGER_TYPE_BEFORE,
2429 TRIGGER_TYPE_INSERT))
2430 continue;
2432 NULL, NULL, NULL))
2433 continue;
2434
2435 LocTriggerData.tg_trigger = trigger;
2437 i,
2441
2442 if (newtuple)
2444 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2445 errmsg("BEFORE STATEMENT trigger cannot return a value")));
2446 }
2447}
2448
2449void
2452{
2454
2458 false, NULL, NULL, NIL, NULL, transition_capture,
2459 false);
2460}
2461
2462bool
2465{
2468 bool should_free;
2470 int i;
2471
2472 LocTriggerData.type = T_TriggerData;
2478 {
2481
2482 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2483 TRIGGER_TYPE_ROW,
2484 TRIGGER_TYPE_BEFORE,
2485 TRIGGER_TYPE_INSERT))
2486 continue;
2488 NULL, NULL, slot))
2489 continue;
2490
2491 if (!newtuple)
2493
2495 LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2496 LocTriggerData.tg_trigger = trigger;
2498 i,
2502 if (newtuple == NULL)
2503 {
2504 if (should_free)
2506 return false;
2507 }
2508 else if (newtuple != oldtuple)
2509 {
2511
2513
2514
2515
2516
2517
2518
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\".",
2528
2529 if (should_free)
2531
2532
2533 newtuple = NULL;
2534 }
2535 }
2536
2537 return true;
2538}
2539
2540void
2544{
2546
2551 true, NULL, slot,
2552 recheckIndexes, NULL,
2553 transition_capture,
2554 false);
2555}
2556
2557bool
2560{
2563 bool should_free;
2565 int i;
2566
2567 LocTriggerData.type = T_TriggerData;
2573 {
2576
2577 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2578 TRIGGER_TYPE_ROW,
2579 TRIGGER_TYPE_INSTEAD,
2580 TRIGGER_TYPE_INSERT))
2581 continue;
2583 NULL, NULL, slot))
2584 continue;
2585
2586 if (!newtuple)
2588
2590 LocTriggerData.tg_trigtuple = oldtuple = newtuple;
2591 LocTriggerData.tg_trigger = trigger;
2593 i,
2597 if (newtuple == NULL)
2598 {
2599 if (should_free)
2601 return false;
2602 }
2603 else if (newtuple != oldtuple)
2604 {
2606
2607 if (should_free)
2609
2610
2611 newtuple = NULL;
2612 }
2613 }
2614
2615 return true;
2616}
2617
2618void
2620{
2622 int i;
2624
2626
2627 if (trigdesc == NULL)
2628 return;
2630 return;
2631
2632
2635 return;
2636
2637 LocTriggerData.type = T_TriggerData;
2642 {
2645
2646 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2647 TRIGGER_TYPE_STATEMENT,
2648 TRIGGER_TYPE_BEFORE,
2649 TRIGGER_TYPE_DELETE))
2650 continue;
2652 NULL, NULL, NULL))
2653 continue;
2654
2655 LocTriggerData.tg_trigger = trigger;
2657 i,
2661
2662 if (newtuple)
2664 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2665 errmsg("BEFORE STATEMENT trigger cannot return a value")));
2666 }
2667}
2668
2669void
2672{
2674
2678 false, NULL, NULL, NIL, NULL, transition_capture,
2679 false);
2680}
2681
2682
2683
2684
2685
2686
2687
2688
2689bool
2697{
2700 bool result = true;
2703 bool should_free = false;
2704 int i;
2705
2707 if (fdw_trigtuple == NULL)
2708 {
2710
2713 tmresult, tmfd))
2714 return false;
2715
2716
2717
2718
2719
2720
2721 if (epqslot_candidate != NULL && epqslot != NULL)
2722 {
2723 *epqslot = epqslot_candidate;
2724 return false;
2725 }
2726
2728 }
2729 else
2730 {
2731 trigtuple = fdw_trigtuple;
2733 }
2734
2735 LocTriggerData.type = T_TriggerData;
2741 {
2744
2745 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2746 TRIGGER_TYPE_ROW,
2747 TRIGGER_TYPE_BEFORE,
2748 TRIGGER_TYPE_DELETE))
2749 continue;
2751 NULL, slot, NULL))
2752 continue;
2753
2756 LocTriggerData.tg_trigger = trigger;
2758 i,
2762 if (newtuple == NULL)
2763 {
2764 result = false;
2765 break;
2766 }
2767 if (newtuple != trigtuple)
2769 }
2770 if (should_free)
2772
2773 return result;
2774}
2775
2776
2777
2778
2779
2780void
2786 bool is_crosspart_update)
2787{
2789
2792 {
2794
2796 if (fdw_trigtuple == NULL)
2798 NULL,
2799 relinfo,
2800 tupleid,
2802 slot,
2803 NULL,
2804 NULL,
2805 NULL);
2806 else
2808
2811 true, slot, NULL, NIL, NULL,
2812 transition_capture,
2813 is_crosspart_update);
2814 }
2815}
2816
2817bool
2820{
2824 int i;
2825
2826 LocTriggerData.type = T_TriggerData;
2831
2833
2835 {
2838
2839 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2840 TRIGGER_TYPE_ROW,
2841 TRIGGER_TYPE_INSTEAD,
2842 TRIGGER_TYPE_DELETE))
2843 continue;
2845 NULL, slot, NULL))
2846 continue;
2847
2850 LocTriggerData.tg_trigger = trigger;
2852 i,
2856 if (rettuple == NULL)
2857 return false;
2858 if (rettuple != trigtuple)
2860 }
2861 return true;
2862}
2863
2864void
2866{
2868 int i;
2871
2873
2874 if (trigdesc == NULL)
2875 return;
2877 return;
2878
2879
2882 return;
2883
2884
2886
2888
2889 LocTriggerData.type = T_TriggerData;
2895 {
2898
2899 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
2900 TRIGGER_TYPE_STATEMENT,
2901 TRIGGER_TYPE_BEFORE,
2902 TRIGGER_TYPE_UPDATE))
2903 continue;
2905 updatedCols, NULL, NULL))
2906 continue;
2907
2908 LocTriggerData.tg_trigger = trigger;
2910 i,
2914
2915 if (newtuple)
2917 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2918 errmsg("BEFORE STATEMENT trigger cannot return a value")));
2919 }
2920}
2921
2922void
2925{
2927
2928
2930
2934 false, NULL, NULL, NIL,
2936 transition_capture,
2937 false);
2938}
2939
2940bool
2948{
2953 bool should_free_trig = false;
2954 bool should_free_new = false;
2956 int i;
2959
2960
2962
2964 if (fdw_trigtuple == NULL)
2965 {
2967
2968
2970 lockmode, oldslot, &epqslot_candidate,
2971 tmresult, tmfd))
2972 return false;
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983 if (epqslot_candidate != NULL)
2984 {
2986
2988 oldslot);
2989
2990
2991
2992
2993
2994
2995
2996 if (unlikely(newslot != epqslot_clean))
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3009 }
3010
3011
3012
3013
3014
3016 }
3017 else
3018 {
3019
3021 trigtuple = fdw_trigtuple;
3022 }
3023
3024 LocTriggerData.type = T_TriggerData;
3032 {
3035
3036 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3037 TRIGGER_TYPE_ROW,
3038 TRIGGER_TYPE_BEFORE,
3039 TRIGGER_TYPE_UPDATE))
3040 continue;
3042 updatedCols, oldslot, newslot))
3043 continue;
3044
3045 if (!newtuple)
3047
3050 LocTriggerData.tg_newtuple = oldtuple = newtuple;
3051 LocTriggerData.tg_newslot = newslot;
3052 LocTriggerData.tg_trigger = trigger;
3054 i,
3058
3059 if (newtuple == NULL)
3060 {
3061 if (should_free_trig)
3063 if (should_free_new)
3065 return false;
3066 }
3067 else if (newtuple != oldtuple)
3068 {
3070
3072
3073
3074
3075
3076
3077
3078
3079 if (should_free_trig && newtuple == trigtuple)
3081
3082 if (should_free_new)
3084
3085
3086 newtuple = NULL;
3087 }
3088 }
3089 if (should_free_trig)
3091
3092 return true;
3093}
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105void
3112 List *recheckIndexes,
3114 bool is_crosspart_update)
3115{
3117
3119 (transition_capture &&
3122 {
3123
3124
3125
3126
3127
3128
3131
3132 Assert((src_partinfo != NULL && dst_partinfo != NULL) ||
3133 !is_crosspart_update);
3134
3135 tupsrc = src_partinfo ? src_partinfo : relinfo;
3137
3140 NULL,
3141 tupsrc,
3142 tupleid,
3144 oldslot,
3145 NULL,
3146 NULL,
3147 NULL);
3148 else if (fdw_trigtuple != NULL)
3150 else
3152
3154 src_partinfo, dst_partinfo,
3156 true,
3157 oldslot, newslot, recheckIndexes,
3159 transition_capture,
3160 is_crosspart_update);
3161 }
3162}
3163
3164bool
3167{
3171 bool should_free;
3173 int i;
3174
3175 LocTriggerData.type = T_TriggerData;
3180
3182
3184 {
3187
3188 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3189 TRIGGER_TYPE_ROW,
3190 TRIGGER_TYPE_INSTEAD,
3191 TRIGGER_TYPE_UPDATE))
3192 continue;
3194 NULL, oldslot, newslot))
3195 continue;
3196
3197 if (!newtuple)
3199
3202 LocTriggerData.tg_newslot = newslot;
3203 LocTriggerData.tg_newtuple = oldtuple = newtuple;
3204
3205 LocTriggerData.tg_trigger = trigger;
3207 i,
3211 if (newtuple == NULL)
3212 {
3213 return false;
3214 }
3215 else if (newtuple != oldtuple)
3216 {
3218
3219 if (should_free)
3221
3222
3223 newtuple = NULL;
3224 }
3225 }
3226
3227 return true;
3228}
3229
3230void
3232{
3234 int i;
3236
3238
3239 if (trigdesc == NULL)
3240 return;
3242 return;
3243
3244 LocTriggerData.type = T_TriggerData;
3248
3250 {
3253
3254 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
3255 TRIGGER_TYPE_STATEMENT,
3256 TRIGGER_TYPE_BEFORE,
3257 TRIGGER_TYPE_TRUNCATE))
3258 continue;
3260 NULL, NULL, NULL))
3261 continue;
3262
3263 LocTriggerData.tg_trigger = trigger;
3265 i,
3269
3270 if (newtuple)
3272 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
3273 errmsg("BEFORE STATEMENT trigger cannot return a value")));
3274 }
3275}
3276
3277void
3279{
3281
3284 NULL, NULL,
3286 false, NULL, NULL, NIL, NULL, NULL,
3287 false);
3288}
3289
3290
3291
3292
3293
3294static bool
3304{
3306
3307 if (epqslot != NULL)
3308 {
3311 int lockflags = 0;
3312
3313 *epqslot = NULL;
3314
3315
3316 Assert(epqstate != NULL);
3317
3318
3319
3320
3326 lockflags,
3327 &tmfd);
3328
3329
3330 if (tmresultp)
3331 *tmresultp = test;
3332 if (tmfdp)
3333 *tmfdp = tmfd;
3334
3335 switch (test)
3336 {
3338
3339
3340
3341
3342
3343
3344
3345
3346
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.")));
3352
3353
3354 return false;
3355
3358 {
3359
3360
3361
3362
3363
3365 {
3366 if (tmresultp)
3368 return false;
3369 }
3370
3372 relation,
3374 oldslot);
3375
3376
3377
3378
3379
3381 {
3382 *epqslot = NULL;
3383 return false;
3384 }
3385 }
3386 break;
3387
3392 errmsg("could not serialize access due to concurrent update")));
3393 elog(ERROR, "unexpected table_tuple_lock status: %u", test);
3394 break;
3395
3400 errmsg("could not serialize access due to concurrent delete")));
3401
3402 return false;
3403
3405 elog(ERROR, "attempted to lock invisible tuple");
3406 break;
3407
3408 default:
3409 elog(ERROR, "unrecognized table_tuple_lock status: %u", test);
3410 return false;
3411 }
3412 }
3413 else
3414 {
3415
3416
3417
3418
3420 oldslot))
3421 elog(ERROR, "failed to fetch tuple for trigger");
3422 }
3423
3424 return true;
3425}
3426
3427
3428
3429
3430static bool
3435{
3436
3438 {
3441 return false;
3442 }
3443 else
3444 {
3447 return false;
3448 }
3449
3450
3451
3452
3453
3455 {
3456 int i;
3457 bool modified;
3458
3459 modified = false;
3460 for (i = 0; i < trigger->tgnattr; i++)
3461 {
3463 modifiedCols))
3464 {
3465 modified = true;
3466 break;
3467 }
3468 }
3469 if (!modified)
3470 return false;
3471 }
3472
3473
3474 if (trigger->tgqual)
3475 {
3479 int i;
3480
3481 Assert(estate != NULL);
3482
3483
3484
3485
3486
3489
3490
3491
3492
3493
3494
3495 if (*predicate == NULL)
3496 {
3497 Node *tgqual;
3498
3503
3506
3510 }
3511
3512
3513
3514
3515
3517
3518
3519
3520
3521
3524 if ((*predicate, econtext))
3525 return false;
3526 }
3527
3528 return true;
3529}
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3557{
3561
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3575{
3582
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3629
3630#define AFTER_TRIGGER_OFFSET 0x07FFFFFF
3631#define AFTER_TRIGGER_DONE 0x80000000
3632#define AFTER_TRIGGER_IN_PROGRESS 0x40000000
3633
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
3641
3643{
3652
3654
3656{
3660
3661
3662
3663
3664
3665
3669
3670
3672{
3677
3678
3680{
3684
3685
3687{
3690
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))))
3699
3700#define GetTriggerSharedData(evt) \
3701 ((AfterTriggerShared) ((char *) (evt) + ((evt)->ate_flags & AFTER_TRIGGER_OFFSET)))
3702
3703
3704
3705
3706
3707
3708
3709
3711{
3716
3718
3719#define CHUNK_DATA_START(cptr) ((char *) (cptr) + MAXALIGN(sizeof(AfterTriggerEventChunk)))
3720
3721
3723{
3728
3729
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)))
3736
3737#define for_each_event_chunk(eptr, cptr, evtlist) \
3738 for_each_chunk(cptr, evtlist) for_each_event(eptr, cptr)
3739
3740
3741#define for_each_chunk_from(cptr) \
3742 for (; cptr != NULL; cptr = cptr->next)
3743#define for_each_event_from(eptr, cptr) \
3744 for (; \
3745 (char *) eptr < (cptr)->freeptr; \
3746 eptr = (AfterTriggerEvent) (((char *) eptr) + SizeofTriggerEvent(eptr)))
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3827
3829{
3834
3835
3839
3840
3844
3846{
3850};
3851
3853{
3854
3859};
3860
3862{
3863
3870
3871
3872
3873
3874
3875
3876
3877
3878
3880
3882
3884
3886
3888};
3889
3891
3921 Oid tgoid, bool tgisdeferred);
3923
3924
3925
3926
3927
3928
3931{
3933
3935 if (ret == NULL)
3936 {
3939
3940
3941
3942
3943
3947
3949
3952
3954 }
3955
3956 return ret;
3957}
3958
3959
3960
3961
3962
3963
3964
3965static bool
3967{
3970 int i;
3971
3972
3973
3974
3975
3977 return false;
3978
3979
3980
3981
3982
3983 if (state != NULL)
3984 {
3985
3986 for (i = 0; i < state->numstates; i++)
3987 {
3988 if (state->trigstates[i].sct_tgoid == tgoid)
3989 return state->trigstates[i].sct_tgisdeferred;
3990 }
3991
3992
3993 if (state->all_isset)
3994 return state->all_isdeferred;
3995 }
3996
3997
3998
3999
4001}
4002
4003
4004
4005
4006
4007
4008
4009
4012{
4015
4016 if (src == NULL)
4017 return NULL;
4018
4020
4022
4024
4025 return dst;
4026}
4027
4028
4029
4030
4031
4032
4033
4034
4035static void
4038{
4044
4045
4046
4047
4048
4049 chunk = events->tail;
4050 if (chunk == NULL ||
4051 chunk->endfree - chunk->freeptr < needed)
4052 {
4053 Size chunksize;
4054
4055
4059 "AfterTriggerEvents",
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077#define MIN_CHUNK_SIZE 1024
4078#define MAX_CHUNK_SIZE (1024*1024)
4079
4080#if MAX_CHUNK_SIZE > (AFTER_TRIGGER_OFFSET+1)
4081#error MAX_CHUNK_SIZE must not exceed AFTER_TRIGGER_OFFSET
4082#endif
4083
4084 if (chunk == NULL)
4086 else
4087 {
4088
4089 chunksize = chunk->endptr - (char *) chunk;
4090
4091 if ((chunk->endptr - chunk->endfree) <=
4093 chunksize *= 2;
4094 else
4095 chunksize /= 2;
4097 }
4099 chunk->next = NULL;
4101 chunk->endptr = chunk->endfree = (char *) chunk + chunksize;
4102 Assert(chunk->endfree - chunk->freeptr >= needed);
4103
4104 if (events->tail == NULL)
4105 {
4107 events->head = chunk;
4108 }
4109 else
4111 events->tail = chunk;
4112
4113 }
4114
4115
4116
4117
4118
4119
4121 (char *) newshared < chunk->endptr;
4122 newshared++)
4123 {
4124
4133 break;
4134 }
4135 if ((char *) newshared >= chunk->endptr)
4136 {
4138 *newshared = *evtshared;
4139
4141 newshared->ats_firing_id = 0;
4142 chunk->endfree = (char *) newshared;
4143 }
4144
4145
4147 memcpy(newevent, event, eventsize);
4148
4149 newevent->ate_flags &= ~AFTER_TRIGGER_OFFSET;
4150 newevent->ate_flags |= (char *) newshared - (char *) newevent;
4151
4152 chunk->freeptr += eventsize;
4153 events->tailfree = chunk->freeptr;
4154}
4155
4156
4157
4158
4159
4160
4161
4162static void
4164{
4166
4167 while ((chunk = events->head) != NULL)
4168 {
4171 }
4172 events->tail = NULL;
4174}
4175
4176
4177
4178
4179
4180
4181
4182
4183static void
4186{
4189
4190 if (old_events->tail == NULL)
4191 {
4192
4194 }
4195 else
4196 {
4197 *events = *old_events;
4198
4199 for (chunk = events->tail->next; chunk != NULL; chunk = next_chunk)
4200 {
4201 next_chunk = chunk->next;
4203 }
4204
4207
4208
4209
4210
4211
4212 }
4213}
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223static void
4225{
4228
4230
4231
4232
4233
4234
4235
4236 foreach(lc, qs->tables)
4237 {
4239
4240 if (table->after_trig_done &&
4241 table->after_trig_events.tail == target)
4242 {
4243 table->after_trig_events.head = NULL;
4244 table->after_trig_events.tail = NULL;
4245 table->after_trig_events.tailfree = NULL;
4246 }
4247 }
4248
4249
4252}
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285static void
4296{
4303 Oid save_rolid;
4304 int save_sec_context;
4306 int tgindx;
4307 bool should_free_trig = false;
4308 bool should_free_new = false;
4309
4310
4311
4312
4313
4314
4315 if (trigdesc == NULL)
4316 return;
4317 for (tgindx = 0; tgindx < trigdesc->numtriggers; tgindx++)
4318 {
4320 {
4322 break;
4323 }
4324 }
4325 if (LocTriggerData.tg_trigger == NULL)
4326 return;
4327
4328
4329
4330
4331
4332 if (instr)
4334
4335
4336
4337
4339 {
4341 {
4343
4345 trig_tuple_slot1))
4346 elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
4347
4351 trig_tuple_slot2))
4352 elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
4353 }
4354
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366 LocTriggerData.tg_trigslot = trig_tuple_slot1;
4369
4372 {
4373 LocTriggerData.tg_newslot = trig_tuple_slot2;
4376 }
4377 else
4378 {
4380 }
4381 break;
4382
4383 default:
4385 {
4387 src_relInfo);
4388
4392 src_slot))
4393 elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
4394
4395
4396
4397
4398
4399 if (src_relInfo != relInfo)
4400 {
4402
4404 if (map)
4405 {
4407 src_slot,
4409 }
4410 else
4412 }
4413 else
4417 }
4418 else
4419 {
4421 }
4422
4423
4427 {
4429 dst_relInfo);
4430
4434 dst_slot))
4435 elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
4436
4437
4438
4439
4440
4441
4442 if (dst_relInfo != relInfo)
4443 {
4445
4447 if (map)
4448 {
4450 dst_slot,
4452 }
4453 else
4455 }
4456 else
4457 LocTriggerData.tg_newslot = dst_slot;
4460 }
4461 else
4462 {
4464 }
4465 }
4466
4467
4468
4469
4470
4471
4472
4473
4476 {
4478 {
4481 else
4484 }
4485
4487 {
4490 else
4493 }
4494 }
4495
4496
4497
4498
4499 LocTriggerData.type = T_TriggerData;
4505
4507
4508
4509
4510
4511
4512
4513
4515 if (save_rolid != evtshared->ats_rolid)
4518
4519
4520
4521
4522
4524 tgindx,
4525 finfo,
4526 NULL,
4527 per_tuple_context);
4528 if (rettuple != NULL &&
4532
4533
4534 if (save_rolid != evtshared->ats_rolid)
4536
4537
4538
4539
4540 if (should_free_trig)
4542 if (should_free_new)
4544
4545
4546 if (trig_tuple_slot1 == NULL)
4547 {
4552 }
4553
4554
4555
4556
4557
4558 if (instr)
4560}
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577static bool
4580 bool immediate_only)
4581{
4582 bool found = false;
4583 bool deferred_found = false;
4586
4588 {
4590 bool defer_it = false;
4591
4594 {
4595
4596
4597
4598
4600 {
4601 defer_it = true;
4602 }
4603 else
4604 {
4605
4606
4607
4610 found = true;
4611 }
4612 }
4613
4614
4615
4616
4617 if (defer_it && move_list != NULL)
4618 {
4619 deferred_found = true;
4620
4622
4624 }
4625 }
4626
4627
4628
4629
4630
4631
4634 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4635 errmsg("cannot fire deferred trigger within security-restricted operation")));
4636
4637 return found;
4638}
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661static bool
4665 bool delete_ok)
4666{
4667 bool all_fired = true;
4670 bool local_estate = false;
4677 *slot2 = NULL;
4678
4679
4680 if (estate == NULL)
4681 {
4683 local_estate = true;
4684 }
4685
4686
4687 per_tuple_context =
4689 "AfterTriggerTupleContext",
4691
4693 {
4695 bool all_fired_in_chunk = true;
4696
4698 {
4700
4701
4702
4703
4706 {
4708 *dst_rInfo;
4709
4710
4711
4712
4713
4715 {
4717 NULL);
4719
4722
4725 if (slot1 != NULL)
4726 {
4729 slot1 = slot2 = NULL;
4730 }
4731 if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
4732 {
4737 }
4738 }
4739
4740
4741
4742
4743
4746 {
4751 rInfo);
4754 rInfo);
4755 }
4756 else
4757 src_rInfo = dst_rInfo = rInfo;
4758
4759
4760
4761
4762
4763
4765 src_rInfo, dst_rInfo,
4766 trigdesc, finfo, instr,
4767 per_tuple_context, slot1, slot2);
4768
4769
4770
4771
4772 event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
4774 }
4776 {
4777
4778 all_fired = all_fired_in_chunk = false;
4779 }
4780 }
4781
4782
4783 if (delete_ok && all_fired_in_chunk)
4784 {
4787
4788
4789
4790
4791
4792
4793
4794 if (chunk == events->tail)
4796 }
4797 }
4798 if (slot1 != NULL)
4799 {
4802 }
4803
4804
4806
4807 if (local_estate)
4808 {
4812 }
4813
4814 return all_fired;
4815}
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4832{
4837
4838
4842
4843 foreach(lc, qs->tables)
4844 {
4846 if (table->relid == relid && table->cmdType == cmdType &&
4849 }
4850
4852
4854 table->relid = relid;
4855 table->cmdType = cmdType;
4857
4859
4861}
4862
4863
4864
4865
4866
4870{
4871
4872 if (->storeslot)
4873 {
4875
4876
4877
4878
4879
4880
4881
4886 }
4887
4888 return table->storeslot;
4889}
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4918{
4920 bool need_old_upd,
4921 need_new_upd,
4922 need_old_del,
4923 need_new_ins;
4927
4928 if (trigdesc == NULL)
4929 return NULL;
4930
4931
4932 switch (cmdType)
4933 {
4935 need_old_upd = need_old_del = need_new_upd = false;
4937 break;
4941 need_old_del = need_new_ins = false;
4942 break;
4945 need_old_upd = need_new_upd = need_new_ins = false;
4946 break;
4952 break;
4953 default:
4954 elog(ERROR, "unexpected CmdType: %d", (int) cmdType);
4955
4956 need_old_upd = need_new_upd = need_old_del = need_new_ins = false;
4957 break;
4958 }
4959 if (!need_old_upd && !need_new_upd && !need_new_ins && !need_old_del)
4960 return NULL;
4961
4962
4964 elog(ERROR, "MakeTransitionCaptureState() called outside of query");
4965
4966
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4983
4984
4988
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)
4997
5000
5001
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;
5008
5010}
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020void
5022{
5023
5024
5025
5028
5029
5030
5031
5032
5033
5041}
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052void
5054{
5055
5057}
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072void
5074{
5076
5077
5079
5080
5081
5082
5083
5085 {
5087 return;
5088 }
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5111
5112 for (;;)
5113 {
5115 {
5118
5120 break;
5121
5122
5123
5124
5125
5126
5127
5128
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141 Assert(oldtail != NULL);
5144 }
5145 else
5146 break;
5147 }
5148
5149
5151
5153}
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163static void
5165{
5167 List *tables;
5169
5170
5172
5173
5176 if (ts)
5178
5179
5180 tables = qs->tables;
5181 foreach(lc, tables)
5182 {
5184
5185 ts = table->old_upd_tuplestore;
5186 table->old_upd_tuplestore = NULL;
5187 if (ts)
5189 ts = table->new_upd_tuplestore;
5190 table->new_upd_tuplestore = NULL;
5191 if (ts)
5193 ts = table->old_del_tuplestore;
5194 table->old_del_tuplestore = NULL;
5195 if (ts)
5197 ts = table->new_ins_tuplestore;
5198 table->new_ins_tuplestore = NULL;
5199 if (ts)
5201 if (table->storeslot)
5202 {
5204
5205 table->storeslot = NULL;
5207 }
5208 }
5209
5210
5211
5212
5213
5214
5217}
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231void
5233{
5235 bool snap_pushed = false;
5236
5237
5239
5240
5241
5242
5243
5244
5246 if (events->head != NULL)
5247 {
5249 snap_pushed = true;
5250 }
5251
5252
5253
5254
5255
5257 {
5259
5261 break;
5262 }
5263
5264
5265
5266
5267
5268
5269 if (snap_pushed)
5271}
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287void
5289{
5290
5291
5292
5293
5294
5295
5296
5297
5298
5300 {
5306 }
5307
5308
5309
5310
5311
5312
5315
5316
5317
5318
5319
5320
5321
5325
5326
5328}
5329
5330
5331
5332
5333
5334
5335void
5337{
5339
5340
5341
5342
5343
5344
5346 {
5348 {
5349
5354 }
5355 else
5356 {
5357
5359
5364 }
5365 }
5366
5367
5368
5369
5370
5371
5376}
5377
5378
5379
5380
5381
5382
5383void
5385{
5391
5392
5393
5394
5395 if (isCommit)
5396 {
5398
5400 if (state != NULL)
5402
5406 }
5407 else
5408 {
5409
5410
5411
5412
5413
5415 return;
5416
5417
5418
5419
5420
5421
5422
5424 {
5428 }
5431
5432
5433
5434
5435
5438
5439
5440
5441
5442
5444 if (state != NULL)
5445 {
5448 }
5449
5451
5452
5453
5454
5455
5456
5457
5458
5459
5462 {
5464
5467 {
5468 if (evtshared->ats_firing_id >= subxact_firing_id)
5469 event->ate_flags &=
5471 }
5472 }
5473 }
5474}
5475
5476
5477
5478
5479
5485{
5491
5492
5493
5494
5495
5496
5497
5498
5499
5504
5506 {
5512 }
5514 {
5520 }
5521
5522 return tuplestore;
5523}
5524
5525
5526
5527
5528
5529
5530
5531static void
5538{
5540
5541
5542
5543
5544 if (tuplestore == NULL)
5545 return;
5546
5547 if (original_insert_tuple)
5550 {
5553
5557 }
5558 else
5560}
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571static void
5573{
5575
5577
5579 {
5581
5586 }
5587 else
5588 {
5589
5592 old_alloc * 2);
5593
5598 }
5599
5600
5602 {
5604
5610
5611 ++init_depth;
5612 }
5613}
5614
5615
5616
5617
5620{
5622
5623
5624 if (numalloc <= 0)
5625 numalloc = 1;
5626
5627
5628
5629
5634
5635 state->numalloc = numalloc;
5636
5638}
5639
5640
5641
5642
5645{
5647
5649
5655
5657}
5658
5659
5660
5661
5662
5665 Oid tgoid, bool tgisdeferred)
5666{
5667 if (state->numstates >= state->numalloc)
5668 {
5669 int newalloc = state->numalloc * 2;
5670
5671 newalloc = Max(newalloc, 8);
5676 state->numalloc = newalloc;
5678 }
5679
5680 state->trigstates[state->numstates].sct_tgoid = tgoid;
5681 state->trigstates[state->numstates].sct_tgisdeferred = tgisdeferred;
5682 state->numstates++;
5683
5685}
5686
5687
5688
5689
5690
5691
5692
5693void
5695{
5697
5698
5701
5702
5703
5704
5705
5706 if (my_level > 1 &&
5708 {
5711 }
5712
5713
5714
5715
5716 if (stmt->constraints == NIL)
5717 {
5718
5719
5720
5722
5723
5724
5725
5728 }
5729 else
5730 {
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5752
5753 foreach(lc, stmt->constraints)
5754 {
5756 bool found;
5757 List *namespacelist;
5759
5761 {
5764 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5765 errmsg("cross-database references are not implemented: \"%s.%s.%s\"",
5768 }
5769
5770
5771
5772
5773
5774
5776 {
5778 false);
5779
5781 }
5782 else
5783 {
5785 }
5786
5787 found = false;
5788 foreach(nslc, namespacelist)
5789 {
5794
5796 Anum_pg_constraint_conname,
5800 Anum_pg_constraint_connamespace,
5803
5805 true, NULL, 2, skey);
5806
5808 {
5810
5811 if (con->condeferrable)
5812 conoidlist = lappend_oid(conoidlist, con->oid);
5813 else if (stmt->deferred)
5815 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
5816 errmsg("constraint \"%s\" is not deferrable",
5818 found = true;
5819 }
5820
5822
5823
5824
5825
5826
5827 if (found)
5828 break;
5829 }
5830
5832
5833
5834
5835
5836 if (!found)
5838 (errcode(ERRCODE_UNDEFINED_OBJECT),
5839 errmsg("constraint \"%s\" does not exist",
5841 }
5842
5843
5844
5845
5846
5847
5848
5849 foreach(lc, conoidlist)
5850 {
5855
5857 Anum_pg_constraint_conparentid,
5860
5861 scan = systable_beginscan(conrel, ConstraintParentIndexId, true, NULL, 1, &key);
5862
5864 {
5866
5867 conoidlist = lappend_oid(conoidlist, con->oid);
5868 }
5869
5871 }
5872
5874
5875
5876
5877
5878
5880
5881 foreach(lc, conoidlist)
5882 {
5887
5889 Anum_pg_trigger_tgconstraint,
5892
5894 NULL, 1, &skey);
5895
5897 {
5899
5900
5901
5902
5903
5904
5905
5906 if (pg_trigger->tgdeferrable)
5907 tgoidlist = lappend_oid(tgoidlist, pg_trigger->oid);
5908 }
5909
5911 }
5912
5914
5915
5916
5917
5918
5919 foreach(lc, tgoidlist)
5920 {
5923 bool found = false;
5924 int i;
5925
5926 for (i = 0; i < state->numstates; i++)
5927 {
5928 if (state->trigstates[i].sct_tgoid == tgoid)
5929 {
5930 state->trigstates[i].sct_tgisdeferred = stmt->deferred;
5931 found = true;
5932 break;
5933 }
5934 }
5935 if (!found)
5936 {
5939 }
5940 }
5941 }
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954 if (->deferred)
5955 {
5957 bool snapshot_set = false;
5958
5960 {
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972 if (!snapshot_set)
5973 {
5975 snapshot_set = true;
5976 }
5977
5978
5979
5980
5981
5982
5985 break;
5986 }
5987
5988 if (snapshot_set)
5990 }
5991}
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008bool
6010{
6013 int depth;
6014
6015
6017 {
6019
6020
6021
6022
6023
6024
6026 continue;
6027
6028 if (evtshared->ats_relid == relid)
6029 return true;
6030 }
6031
6032
6033
6034
6035
6036
6038 {
6040 {
6042
6044 continue;
6045
6046 if (evtshared->ats_relid == relid)
6047 return true;
6048 }
6049 }
6050
6051 return false;
6052}
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095static void
6099 int event, bool row_trigger,
6103 bool is_crosspart_update)
6104{
6109 char relkind = rel->rd_rel->relkind;
6110 int tgtype_event;
6111 int tgtype_level;
6112 int i;
6114
6115
6116
6117
6118
6119
6121 elog(ERROR, "AfterTriggerSaveEvent() called outside of query");
6122
6123
6126
6127
6128
6129
6130
6131 if (row_trigger && transition_capture != NULL)
6132 {
6134
6135
6136
6137
6138
6140 {
6142
6144 oldslot,
6145 NULL,
6146 transition_capture);
6148 oldslot, NULL, old_tuplestore);
6149 }
6150
6151
6152
6153
6154
6156 {
6158
6160 NULL,
6161 newslot,
6162 transition_capture);
6164 newslot, original_insert_tuple, new_tuplestore);
6165 }
6166
6167
6168
6169
6170
6171
6172
6173
6174 if (trigdesc == NULL ||
6179 return;
6180 }
6181
6182
6183
6184
6185
6186
6187
6188
6189 Assert(!row_trigger ||
6190 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
6191 (is_crosspart_update &&
6193 src_partinfo != NULL && dst_partinfo != NULL));
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207 switch (event)
6208 {
6210 tgtype_event = TRIGGER_TYPE_INSERT;
6211 if (row_trigger)
6212 {
6213 Assert(oldslot == NULL);
6214 Assert(newslot != NULL);
6217 }
6218 else
6219 {
6220 Assert(oldslot == NULL);
6221 Assert(newslot == NULL);
6226 }
6227 break;
6229 tgtype_event = TRIGGER_TYPE_DELETE;
6230 if (row_trigger)
6231 {
6232 Assert(oldslot != NULL);
6233 Assert(newslot == NULL);
6236 }
6237 else
6238 {
6239 Assert(oldslot == NULL);
6240 Assert(newslot == NULL);
6245 }
6246 break;
6248 tgtype_event = TRIGGER_TYPE_UPDATE;
6249 if (row_trigger)
6250 {
6251 Assert(oldslot != NULL);
6252 Assert(newslot != NULL);
6255
6256
6257
6258
6259
6260 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6261 {
6262 Assert(src_partinfo != NULL && dst_partinfo != NULL);
6267 }
6268 }
6269 else
6270 {
6271 Assert(oldslot == NULL);
6272 Assert(newslot == NULL);
6277 }
6278 break;
6280 tgtype_event = TRIGGER_TYPE_TRUNCATE;
6281 Assert(oldslot == NULL);
6282 Assert(newslot == NULL);
6285 break;
6286 default:
6287 elog(ERROR, "invalid after-trigger event code: %d", event);
6288 tgtype_event = 0;
6289 break;
6290 }
6291
6292
6293 if (!(relkind == RELKIND_FOREIGN_TABLE && row_trigger))
6294 {
6296 {
6297 if (relkind == RELKIND_PARTITIONED_TABLE)
6299 else
6301 }
6302 else
6304 }
6305
6306
6307
6308 tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
6309
6310
6311
6312
6313
6314
6315 if (row_trigger && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6316 {
6319
6322 if (map)
6324 oldslot,
6325 rootslot);
6326 else
6328
6331 if (map)
6333 newslot,
6334 rootslot);
6335 else
6337 }
6338
6340 {
6342
6343 if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
6344 tgtype_level,
6345 TRIGGER_TYPE_AFTER,
6346 tgtype_event))
6347 continue;
6348 if ((estate, relinfo, trigger, event,
6349 modifiedCols, oldslot, newslot))
6350 continue;
6351
6352 if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
6353 {
6354 if (fdw_tuplestore == NULL)
6355 {
6358 }
6359 else
6360
6362 }
6363
6364
6365
6366
6367
6368
6369
6370
6372 {
6374 {
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386 if (is_crosspart_update &&
6389 continue;
6390
6391
6393 oldslot, newslot))
6394 {
6395
6396 continue;
6397 }
6398 break;
6399
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413 if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
6415 oldslot, newslot))
6416 {
6417
6418 continue;
6419 }
6420 break;
6421
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432 if (row_trigger &&
6433 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6434 continue;
6435 break;
6436 }
6437 }
6438
6439
6440
6441
6442
6443
6444 if (trigger->tgfoid == F_UNIQUE_KEY_RECHECK)
6445 {
6447 continue;
6448 }
6449
6450
6451
6452
6453
6454
6465 transition_capture != NULL)
6467 else
6470
6472 &new_event, &new_shared);
6473 }
6474
6475
6476
6477
6478
6479
6480 if (fdw_tuplestore)
6481 {
6482 if (oldslot != NULL)
6484 if (newslot != NULL)
6486 }
6487}
6488
6489
6490
6491
6492
6493static bool
6495{
6496 bool result;
6498
6499
6501 elog(ERROR, "before_stmt_triggers_fired() called outside of query");
6502
6503
6506
6507
6508
6509
6510
6511
6512
6513
6515 result = table->before_trig_done;
6516 table->before_trig_done = true;
6517 return result;
6518}
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539static void
6541{
6544
6545
6546
6547
6548
6549
6550
6551
6553
6554 if (table->after_trig_done)
6555 {
6556
6557
6558
6559
6560
6561
6564
6565 if (table->after_trig_events.tail)
6566 {
6567 chunk = table->after_trig_events.tail;
6569 }
6570 else
6571 {
6573 event = NULL;
6574 }
6575
6577 {
6578 if (event == NULL)
6581 {
6583
6584
6585
6586
6587
6588 if (evtshared->ats_relid != relid)
6589 goto done;
6591 goto done;
6593 goto done;
6595 goto done;
6596
6597 event->ate_flags &= ~AFTER_TRIGGER_IN_PROGRESS;
6599 }
6600
6601 event = NULL;
6602 }
6603 }
6604done:
6605
6606
6607 table->after_trig_done = true;
6609}
6610
6611
6612
6613
6614void
6616{
6617
6618
6619
6620
6623}
6624
6625
6626
6627
6630{
6632}
6633
6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6646{
6648 return tuple;
6649
6650 for (int i = 0; i < tupdesc->natts; i++)
6651 {
6652 if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
6653 {
6655 {
6656 int replCol = i + 1;
6657 Datum replValue = 0;
6658 bool replIsnull = true;
6659
6661 }
6662 }
6663 }
6664
6665 return tuple;
6666}
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
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 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()