PostgreSQL Source Code: src/include/commands/trigger.h File Reference (original) (raw)

182{

184 int ncolumns;

187 List *whenRtable;

188 char *qual;

190 bool nulls[Natts_pg_trigger];

196 Oid funcrettype;

199 char *trigname;

202 referenced;

203 char *oldtablename = NULL;

204 char *newtablename = NULL;

205 bool partition_recurse;

206 bool trigger_exists = false;

208 bool existing_isInternal = false;

209 bool existing_isClone = false;

210

213 else

215

216

217

218

219

220 if (rel->rd_rel->relkind == RELKIND_RELATION)

221 {

222

223 if (stmt->timing != TRIGGER_TYPE_BEFORE &&

224 stmt->timing != TRIGGER_TYPE_AFTER)

226 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

227 errmsg("\"%s\" is a table",

229 errdetail("Tables cannot have INSTEAD OF triggers.")));

230 }

231 else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)

232 {

233

234 if (stmt->timing != TRIGGER_TYPE_BEFORE &&

235 stmt->timing != TRIGGER_TYPE_AFTER)

237 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

238 errmsg("\"%s\" is a table",

240 errdetail("Tables cannot have INSTEAD OF triggers.")));

241

242

243

244

245 if (stmt->row)

246 {

247

248

249

250

251

252

253

254

255

256

257

258 if (stmt->transitionRels != NIL)

260 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

261 errmsg("\"%s\" is a partitioned table",

263 errdetail("ROW triggers with transition tables are not supported on partitioned tables.")));

264 }

265 }

266 else if (rel->rd_rel->relkind == RELKIND_VIEW)

267 {

268

269

270

271

272 if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)

274 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

275 errmsg("\"%s\" is a view",

277 errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));

278

279 if (TRIGGER_FOR_TRUNCATE(stmt->events))

281 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

282 errmsg("\"%s\" is a view",

284 errdetail("Views cannot have TRUNCATE triggers.")));

285 }

286 else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)

287 {

288 if (stmt->timing != TRIGGER_TYPE_BEFORE &&

289 stmt->timing != TRIGGER_TYPE_AFTER)

291 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

292 errmsg("\"%s\" is a foreign table",

294 errdetail("Foreign tables cannot have INSTEAD OF triggers.")));

295

296

297

298

299

300

301 if (stmt->isconstraint)

303 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

304 errmsg("\"%s\" is a foreign table",

306 errdetail("Foreign tables cannot have constraint triggers.")));

307 }

308 else

310 (errcode(ERRCODE_WRONG_OBJECT_TYPE),

311 errmsg("relation \"%s\" cannot have triggers",

314

317 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),

318 errmsg("permission denied: \"%s\" is a system catalog",

320

321 if (stmt->isconstraint)

322 {

323

324

325

326

327

328

329

331 {

333 constrrelid = refRelOid;

334 }

335 else if (stmt->constrrel != NULL)

337 false);

338 }

339

340

341 if (!isInternal)

342 {

348

350 {

356 }

357 }

358

359

360

361

362

363

364

365 partition_recurse = !isInternal && stmt->row &&

366 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;

367 if (partition_recurse)

370

371

372 TRIGGER_CLEAR_TYPE(tgtype);

373 if (stmt->row)

374 TRIGGER_SETT_ROW(tgtype);

375 tgtype |= stmt->timing;

376 tgtype |= stmt->events;

377

378

379 if (TRIGGER_FOR_ROW(tgtype) && TRIGGER_FOR_TRUNCATE(tgtype))

381 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

382 errmsg("TRUNCATE FOR EACH ROW triggers are not supported")));

383

384

385 if (TRIGGER_FOR_INSTEAD(tgtype))

386 {

387 if (!TRIGGER_FOR_ROW(tgtype))

389 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

390 errmsg("INSTEAD OF triggers must be FOR EACH ROW")));

391 if (stmt->whenClause)

393 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),

394 errmsg("INSTEAD OF triggers cannot have WHEN conditions")));

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}

void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)

AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)

AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)

#define InvalidAttrNumber

static Datum values[MAXATTR]

#define CStringGetTextDatum(s)

#define OidIsValid(objectId)

bool IsSystemRelation(Relation relation)

Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)

void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, DependencyType behavior)

@ DEPENDENCY_PARTITION_PRI

@ DEPENDENCY_PARTITION_SEC

int errdetail(const char *fmt,...)

int errhint(const char *fmt,...)

#define DirectFunctionCall1(func, arg1)

bool allowSystemTableMods

HeapTuple heap_copytuple(HeapTuple tuple)

HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)

void heap_freetuple(HeapTuple htup)

void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)

void CatalogTupleInsert(Relation heapRel, HeapTuple tup)

int2vector * buildint2vector(const int16 *int2s, int n)

void CacheInvalidateRelcacheByTuple(HeapTuple classTuple)

void LockRelationOid(Oid relid, LOCKMODE lockmode)

#define ShareRowExclusiveLock

char * get_rel_name(Oid relid)

char get_rel_relkind(Oid relid)

Oid get_func_rettype(Oid funcid)

Alias * makeAlias(const char *aliasname, List *colnames)

void MemoryContextReset(MemoryContext context)

MemoryContext CurrentMemoryContext

#define AllocSetContextCreate

#define ALLOCSET_SMALL_SIZES

Datum namein(PG_FUNCTION_ARGS)

char * NameListToString(const List *names)

#define RangeVarGetRelid(relation, lockmode, missing_ok)

#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)

ObjectType get_relkind_objtype(char relkind)

#define ObjectAddressSet(addr, class_id, object_id)

char * nodeToString(const void *obj)

static MemoryContext MemoryContextSwitchTo(MemoryContext context)

Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)

void assign_expr_collations(ParseState *pstate, Node *expr)

Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)

void free_parsestate(ParseState *pstate)

int parser_errposition(ParseState *pstate, int location)

ParseState * make_parsestate(ParseState *parentParseState)

ParseNamespaceItem * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, int lockmode, Alias *alias, bool inh, bool inFromCl)

void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)

int attnameAttNum(Relation rd, const char *attname, bool sysColOK)

PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)

List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)

int errdetail_relkind_not_supported(char relkind)

FormData_pg_class * Form_pg_class

Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isEnforced, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int16 conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)

void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)

long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)

List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)

bool has_superclass(Oid relationId)

#define lfirst_node(type, lc)

static int list_length(const List *l)

static Datum PointerGetDatum(const void *X)

static Datum Int16GetDatum(int16 X)

static Datum BoolGetDatum(bool X)

static Pointer DatumGetPointer(Datum X)

#define RelationGetRelid(relation)

#define RelationGetDescr(relation)

#define RelationGetRelationName(relation)

#define RelationGetNamespace(relation)

#define ERRCODE_DUPLICATE_OBJECT

const char * p_sourcetext

#define SearchSysCacheCopy1(cacheId, key1)

Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode)

static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)

List * pull_var_clause(Node *node, int flags)

Datum byteain(PG_FUNCTION_ARGS)

void CommandCounterIncrement(void)