From c18ea0dbc66832a5eba9ce9cf959583dfc2d594c Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Sat, 27 Dec 2025 13:55:59 +0800
Subject: [PATCH v3 1/3] add relOid field to CreateTrigStmt
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

add the relOid field to CreateTrigStmt is very useful for copying or recreating
a CreateTrigStmt.
Copying CreateTrigStmt node can happen like CREATE TABLE LIKE INCLUDING TRIGGERS.
To let ALTER COLUMN SET DATA TYPE cope with trigger dependencies, we need get
the trigger definition then do parse analysis for CreateTrigStmt again.

in function CreateTrigger, we have below comments:
```
* relOid, if nonzero, is the relation on which the trigger should be * created.
If zero, the name provided in the statement will be looked up.
```

We can move the "relOid" argument out of the CreateTrigger function’s parameter
list and instead store it in CreateTrigStmt.
The following are the reason why:

1. CreateTrigger has too many arguments; reducing the argument list by one is a good thing.
2. To implement CREATE TABLE LIKE INCLUDING TRIGGERS, we need to pass the new
relation OID to CreateTrigger, but it's not doable from
ProcessUtilitySlow->CreateTrigger.
3. To allow ALTER COLUMN SET DATA TYPE to cope with trigger dependencies, we
also need to pass the new relation OID to CreateTrigger, which for the same
reason as above cannot be done from ProcessUtilitySlow. This can help to reduce
repeated lookup issue.

discussion: https://postgr.es/m/CACJufxHJAr2FjbeB6ghg_-N5dxX5JVnjKSLOUxOyt4TeaAWQkg@mail.gmail.com
discussion: https://postgr.es/m/CACJufxGkqYrmwMdvUOUPet0443oUTgF_dKCpw3TfJiutfuywAQ@mail.gmail.com
commitfest: https://commitfest.postgresql.org/patch/6087
commitfest: https://commitfest.postgresql.org/patch/6089
---
 src/backend/catalog/index.c      |  3 ++-
 src/backend/commands/tablecmds.c | 12 ++++++++----
 src/backend/commands/trigger.c   | 16 +++++++---------
 src/backend/parser/gram.y        |  2 ++
 src/backend/tcop/utility.c       |  2 +-
 src/include/commands/trigger.h   |  4 ++--
 src/include/nodes/parsenodes.h   | 11 +++++++++++
 7 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 8dea58ad96b..8e74ff1dd33 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -2028,6 +2028,7 @@ index_constraint_create(Relation heapRelation,
 			"PK_ConstraintTrigger" :
 			"Unique_ConstraintTrigger";
 		trigger->relation = NULL;
+		trigger->relOid = RelationGetRelid(heapRelation);
 		trigger->funcname = SystemFuncName("unique_key_recheck");
 		trigger->args = NIL;
 		trigger->row = true;
@@ -2040,7 +2041,7 @@ index_constraint_create(Relation heapRelation,
 		trigger->initdeferred = initdeferred;
 		trigger->constrrel = NULL;
 
-		(void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation),
+		(void) CreateTrigger(trigger, NULL,
 							 InvalidOid, conOid, indexRelationId, InvalidOid,
 							 InvalidOid, NULL, true, false);
 	}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1d9565b09fc..ee400c1cd58 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13840,6 +13840,7 @@ CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
 	fk_trigger->isconstraint = true;
 	fk_trigger->trigname = "RI_ConstraintTrigger_c";
 	fk_trigger->relation = NULL;
+	fk_trigger->relOid = myRelOid;
 
 	/* Either ON INSERT or ON UPDATE */
 	if (on_insert)
@@ -13863,7 +13864,7 @@ CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint,
 	fk_trigger->initdeferred = fkconstraint->initdeferred;
 	fk_trigger->constrrel = NULL;
 
-	trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid,
+	trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid,
 								constraintOid, indexOid, InvalidOid,
 								parentTrigOid, NULL, true, false);
 
@@ -13899,6 +13900,7 @@ createForeignKeyActionTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstr
 	fk_trigger->isconstraint = true;
 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
 	fk_trigger->relation = NULL;
+	fk_trigger->relOid = refRelOid;
 	fk_trigger->args = NIL;
 	fk_trigger->row = true;
 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
@@ -13941,7 +13943,7 @@ createForeignKeyActionTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstr
 			break;
 	}
 
-	trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid,
+	trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid,
 								constraintOid, indexOid, InvalidOid,
 								parentDelTrigger, NULL, true, false);
 	if (deleteTrigOid)
@@ -13959,6 +13961,7 @@ createForeignKeyActionTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstr
 	fk_trigger->isconstraint = true;
 	fk_trigger->trigname = "RI_ConstraintTrigger_a";
 	fk_trigger->relation = NULL;
+	fk_trigger->relOid = refRelOid;
 	fk_trigger->args = NIL;
 	fk_trigger->row = true;
 	fk_trigger->timing = TRIGGER_TYPE_AFTER;
@@ -14001,7 +14004,7 @@ createForeignKeyActionTriggers(Oid myRelOid, Oid refRelOid, Constraint *fkconstr
 			break;
 	}
 
-	trigAddress = CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid,
+	trigAddress = CreateTrigger(fk_trigger, NULL, myRelOid,
 								constraintOid, indexOid, InvalidOid,
 								parentUpdTrigger, NULL, true, false);
 	if (updateTrigOid)
@@ -20905,6 +20908,7 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
 		trigStmt->isconstraint = OidIsValid(trigForm->tgconstraint);
 		trigStmt->trigname = NameStr(trigForm->tgname);
 		trigStmt->relation = NULL;
+		trigStmt->relOid = RelationGetRelid(partition);
 		trigStmt->funcname = NULL;	/* passed separately */
 		trigStmt->args = trigargs;
 		trigStmt->row = true;
@@ -20917,7 +20921,7 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
 		trigStmt->initdeferred = trigForm->tginitdeferred;
 		trigStmt->constrrel = NULL; /* passed separately */
 
-		CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
+		CreateTriggerFiringOn(trigStmt, NULL,
 							  trigForm->tgconstrrelid, InvalidOid, InvalidOid,
 							  trigForm->tgfoid, trigForm->oid, qual,
 							  false, true, trigForm->tgenabled);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 12c97f2c023..6e079213863 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -111,9 +111,6 @@ static HeapTuple check_modified_virtual_generated(TupleDesc tupdesc, HeapTuple t
  * queryString is the source text of the CREATE TRIGGER command.
  * This must be supplied if a whenClause is specified, else it can be NULL.
  *
- * relOid, if nonzero, is the relation on which the trigger should be
- * created.  If zero, the name provided in the statement will be looked up.
- *
  * refRelOid, if nonzero, is the relation to which the constraint trigger
  * refers.  If zero, the constraint relation name provided in the statement
  * will be looked up as needed.
@@ -158,12 +155,12 @@ static HeapTuple check_modified_virtual_generated(TupleDesc tupdesc, HeapTuple t
  */
 ObjectAddress
 CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
-			  Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
+			  Oid refRelOid, Oid constraintOid, Oid indexOid,
 			  Oid funcoid, Oid parentTriggerOid, Node *whenClause,
 			  bool isInternal, bool in_partition)
 {
 	return
-		CreateTriggerFiringOn(stmt, queryString, relOid, refRelOid,
+		CreateTriggerFiringOn(stmt, queryString, refRelOid,
 							  constraintOid, indexOid, funcoid,
 							  parentTriggerOid, whenClause, isInternal,
 							  in_partition, TRIGGER_FIRES_ON_ORIGIN);
@@ -175,7 +172,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
  */
 ObjectAddress
 CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
-					  Oid relOid, Oid refRelOid, Oid constraintOid,
+					  Oid refRelOid, Oid constraintOid,
 					  Oid indexOid, Oid funcoid, Oid parentTriggerOid,
 					  Node *whenClause, bool isInternal, bool in_partition,
 					  char trigger_fires_when)
@@ -208,8 +205,8 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 	bool		existing_isInternal = false;
 	bool		existing_isClone = false;
 
-	if (OidIsValid(relOid))
-		rel = table_open(relOid, ShareRowExclusiveLock);
+	if (OidIsValid(stmt->relOid))
+		rel = table_open(stmt->relOid, ShareRowExclusiveLock);
 	else
 		rel = table_openrv(stmt->relation, ShareRowExclusiveLock);
 
@@ -1186,8 +1183,9 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 				map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
 										childTbl, rel);
 
+			childStmt->relOid = partdesc->oids[i];
 			CreateTriggerFiringOn(childStmt, queryString,
-								  partdesc->oids[i], refRelOid,
+								  refRelOid,
 								  InvalidOid, InvalidOid,
 								  funcoid, trigoid, qual,
 								  isInternal, true, trigger_fires_when);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 28f4e11e30f..01e66ba615e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6139,6 +6139,7 @@ CreateTrigStmt:
 					n->isconstraint = false;
 					n->trigname = $4;
 					n->relation = $8;
+					n->relOid = InvalidOid;
 					n->funcname = $14;
 					n->args = $16;
 					n->row = $10;
@@ -6188,6 +6189,7 @@ CreateTrigStmt:
 					n->isconstraint = true;
 					n->trigname = $5;
 					n->relation = $9;
+					n->relOid = InvalidOid;
 					n->funcname = $18;
 					n->args = $20;
 					n->row = true;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index d18a3a60a46..7d6387ad9b5 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1701,7 +1701,7 @@ ProcessUtilitySlow(ParseState *pstate,
 
 			case T_CreateTrigStmt:
 				address = CreateTrigger((CreateTrigStmt *) parsetree,
-										queryString, InvalidOid, InvalidOid,
+										queryString, InvalidOid,
 										InvalidOid, InvalidOid, InvalidOid,
 										InvalidOid, NULL, false, false);
 				break;
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index cfd7daa20ed..ae7abd456bf 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -152,11 +152,11 @@ extern PGDLLIMPORT int SessionReplicationRole;
 #define TRIGGER_DISABLED					'D'
 
 extern ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
-								   Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
+								   Oid refRelOid, Oid constraintOid, Oid indexOid,
 								   Oid funcoid, Oid parentTriggerOid, Node *whenClause,
 								   bool isInternal, bool in_partition);
 extern ObjectAddress CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
-										   Oid relOid, Oid refRelOid, Oid constraintOid,
+										   Oid refRelOid, Oid constraintOid,
 										   Oid indexOid, Oid funcoid, Oid parentTriggerOid,
 										   Node *whenClause, bool isInternal, bool in_partition,
 										   char trigger_fires_when);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index bc7adba4a0f..f876f00ab9f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3138,6 +3138,17 @@ typedef struct CreateTrigStmt
 	bool		isconstraint;	/* This is a constraint trigger */
 	char	   *trigname;		/* TRIGGER's name */
 	RangeVar   *relation;		/* relation trigger is on */
+
+	/*
+	 * The OID of the relation on which the trigger is to be created. If this
+	 * is InvalidOid, CreateTrigStmt.relation is used to perform the lookup;
+	 * otherwise, use this directly. This is useful when CreateTrigger is
+	 * invoked indirectly rather than directly from the parser.
+	 *
+	 * Using the OID also avoids repeated relation name lookups.
+	 */
+	Oid			relOid;
+
 	List	   *funcname;		/* qual. name of function to call */
 	List	   *args;			/* list of String or NIL */
 	bool		row;			/* ROW/STATEMENT */
-- 
2.34.1

