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")));

395 if (stmt->columns != NIL)

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

504 if (stmt->columns != NIL)

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 (stmt->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 && OidIsValid(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 {

953 if (columns[j] == attnum)

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 (ExecQual(*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{

3578 int numstates;

3579 int numalloc;

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{

3713 char *freeptr;

3714 char *endfree;

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{

3849 List *tables;

3850};

3851

3853{

3854

3859};

3860

3862{

3863

3866 bool closed;

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 (table->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 (stmt->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 (TriggerEnabled(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()