aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/catalogs.sgml11
-rw-r--r--src/backend/commands/tablecmds.c59
-rw-r--r--src/backend/commands/trigger.c1
-rw-r--r--src/include/catalog/pg_trigger.h1
-rw-r--r--src/test/regress/expected/sanity_check.out3
-rw-r--r--src/test/regress/expected/triggers.out9
-rw-r--r--src/test/regress/sql/triggers.sql10
7 files changed, 40 insertions, 54 deletions
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index a10b66569b9..34bc0d05266 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -6952,6 +6952,17 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
</row>
<row>
+ <entry><structfield>tgparentid</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-trigger"><structname>pg_trigger</structname></link>.oid</literal></entry>
+ <entry>
+ Parent trigger that this trigger is cloned from, zero if not a clone;
+ this happens when partitions are created or attached to a partitioned
+ table.
+ </entry>
+ </row>
+
+ <row>
<entry><structfield>tgname</structfield></entry>
<entry><type>name</type></entry>
<entry></entry>
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b7c8d663fc4..02a7c04fdb7 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -16448,54 +16448,6 @@ out:
}
/*
- * isPartitionTrigger
- * Subroutine for CloneRowTriggersToPartition: determine whether
- * the given trigger has been cloned from another one.
- *
- * We use pg_depend as a proxy for this, since we don't have any direct
- * evidence. This is an ugly hack to cope with a catalog deficiency.
- * Keep away from children. Do not stare with naked eyes. Do not propagate.
- */
-static bool
-isPartitionTrigger(Oid trigger_oid)
-{
- Relation pg_depend;
- ScanKeyData key[2];
- SysScanDesc scan;
- HeapTuple tup;
- bool found = false;
-
- pg_depend = table_open(DependRelationId, AccessShareLock);
-
- ScanKeyInit(&key[0], Anum_pg_depend_classid,
- BTEqualStrategyNumber,
- F_OIDEQ,
- ObjectIdGetDatum(TriggerRelationId));
- ScanKeyInit(&key[1], Anum_pg_depend_objid,
- BTEqualStrategyNumber,
- F_OIDEQ,
- ObjectIdGetDatum(trigger_oid));
-
- scan = systable_beginscan(pg_depend, DependDependerIndexId,
- true, NULL, 2, key);
- while ((tup = systable_getnext(scan)) != NULL)
- {
- Form_pg_depend dep = (Form_pg_depend) GETSTRUCT(tup);
-
- if (dep->refclassid == TriggerRelationId)
- {
- found = true;
- break;
- }
- }
-
- systable_endscan(scan);
- table_close(pg_depend, AccessShareLock);
-
- return found;
-}
-
-/*
* CloneRowTriggersToPartition
* subroutine for ATExecAttachPartition/DefineRelation to create row
* triggers on partitions
@@ -16537,11 +16489,10 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
/*
* Internal triggers require careful examination. Ideally, we don't
- * clone them.
- *
- * However, if our parent is a partitioned relation, there might be
- * internal triggers that need cloning. In that case, we must skip
- * clone it if the trigger on parent depends on another trigger.
+ * clone them. However, if our parent is itself a partition, there
+ * might be internal triggers that must not be skipped; for example,
+ * triggers on our parent that are in turn clones from its parent (our
+ * grandparent) are marked internal, yet they are to be cloned.
*
* Note we dare not verify that the other trigger belongs to an
* ancestor relation of our parent, because that creates deadlock
@@ -16549,7 +16500,7 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
*/
if (trigForm->tgisinternal &&
(!parent->rd_rel->relispartition ||
- !isPartitionTrigger(trigForm->oid)))
+ !OidIsValid(trigForm->tgparentid)))
continue;
/*
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index b9b1262e300..6e8b7223fe5 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -847,6 +847,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
values[Anum_pg_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
+ values[Anum_pg_trigger_tgparentid - 1] = ObjectIdGetDatum(parentTriggerOid);
values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
CStringGetDatum(trigname));
values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h
index 2f30c7c2f94..9612b9bdd65 100644
--- a/src/include/catalog/pg_trigger.h
+++ b/src/include/catalog/pg_trigger.h
@@ -35,6 +35,7 @@ CATALOG(pg_trigger,2620,TriggerRelationId)
{
Oid oid; /* oid */
Oid tgrelid; /* relation trigger is attached to */
+ Oid tgparentid; /* OID of parent trigger, if any */
NameData tgname; /* trigger's name */
Oid tgfoid; /* OID of function to be called */
int16 tgtype; /* BEFORE/AFTER/INSTEAD, UPDATE/DELETE/INSERT,
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 45b421b747a..192445878d2 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -208,6 +208,9 @@ timestamp_tbl|f
timestamptz_tbl|f
timetz_tbl|f
tmp|f
+trigger_parted|t
+trigger_parted_p1|t
+trigger_parted_p1_1|t
varchar_tbl|f
view_base_table|t
-- restore normal output mode
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index b91fbd06481..22e65cc1ece 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -2928,3 +2928,12 @@ drop table self_ref;
drop function dump_insert();
drop function dump_update();
drop function dump_delete();
+-- Leave around some objects for other tests
+create table trigger_parted (a int primary key) partition by list (a);
+create function trigger_parted_trigfunc() returns trigger language plpgsql as
+ $$ begin end; $$;
+create trigger aft_row after insert or update on trigger_parted
+ for each row execute function trigger_parted_trigfunc();
+create table trigger_parted_p1 partition of trigger_parted for values in (1)
+ partition by list (a);
+create table trigger_parted_p1_1 partition of trigger_parted_p1 for values in (1);
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 7cd835449c5..0f61fdf0ea2 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -2213,3 +2213,13 @@ drop table self_ref;
drop function dump_insert();
drop function dump_update();
drop function dump_delete();
+
+-- Leave around some objects for other tests
+create table trigger_parted (a int primary key) partition by list (a);
+create function trigger_parted_trigfunc() returns trigger language plpgsql as
+ $$ begin end; $$;
+create trigger aft_row after insert or update on trigger_parted
+ for each row execute function trigger_parted_trigfunc();
+create table trigger_parted_p1 partition of trigger_parted for values in (1)
+ partition by list (a);
+create table trigger_parted_p1_1 partition of trigger_parted_p1 for values in (1);