Record parents of triggers
This let us get rid of a recently introduced ugly hack (commit
1fa846f1c9
).
Author: Álvaro Herrera
Reviewed-by: Amit Langote, Tom Lane
Discussion: https://postgr.es/m/20200217215641.GA29784@alvherre.pgsql
This commit is contained in:
parent
c4b0edb07e
commit
b9b408c487
|
@ -6951,6 +6951,17 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
|
||||||
<entry>The table this trigger is on</entry>
|
<entry>The table this trigger is on</entry>
|
||||||
</row>
|
</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>
|
<row>
|
||||||
<entry><structfield>tgname</structfield></entry>
|
<entry><structfield>tgname</structfield></entry>
|
||||||
<entry><type>name</type></entry>
|
<entry><type>name</type></entry>
|
||||||
|
|
|
@ -16447,54 +16447,6 @@ out:
|
||||||
MemoryContextDelete(cxt);
|
MemoryContextDelete(cxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
* CloneRowTriggersToPartition
|
||||||
* subroutine for ATExecAttachPartition/DefineRelation to create row
|
* subroutine for ATExecAttachPartition/DefineRelation to create row
|
||||||
|
@ -16537,11 +16489,10 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal triggers require careful examination. Ideally, we don't
|
* Internal triggers require careful examination. Ideally, we don't
|
||||||
* clone them.
|
* clone them. However, if our parent is itself a partition, there
|
||||||
*
|
* might be internal triggers that must not be skipped; for example,
|
||||||
* However, if our parent is a partitioned relation, there might be
|
* triggers on our parent that are in turn clones from its parent (our
|
||||||
* internal triggers that need cloning. In that case, we must skip
|
* grandparent) are marked internal, yet they are to be cloned.
|
||||||
* clone it if the trigger on parent depends on another trigger.
|
|
||||||
*
|
*
|
||||||
* Note we dare not verify that the other trigger belongs to an
|
* Note we dare not verify that the other trigger belongs to an
|
||||||
* ancestor relation of our parent, because that creates deadlock
|
* ancestor relation of our parent, because that creates deadlock
|
||||||
|
@ -16549,7 +16500,7 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
|
||||||
*/
|
*/
|
||||||
if (trigForm->tgisinternal &&
|
if (trigForm->tgisinternal &&
|
||||||
(!parent->rd_rel->relispartition ||
|
(!parent->rd_rel->relispartition ||
|
||||||
!isPartitionTrigger(trigForm->oid)))
|
!OidIsValid(trigForm->tgparentid)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -847,6 +847,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
|
||||||
|
|
||||||
values[Anum_pg_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
|
values[Anum_pg_trigger_oid - 1] = ObjectIdGetDatum(trigoid);
|
||||||
values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
|
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,
|
values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
|
||||||
CStringGetDatum(trigname));
|
CStringGetDatum(trigname));
|
||||||
values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
|
values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
|
||||||
|
|
|
@ -35,6 +35,7 @@ CATALOG(pg_trigger,2620,TriggerRelationId)
|
||||||
{
|
{
|
||||||
Oid oid; /* oid */
|
Oid oid; /* oid */
|
||||||
Oid tgrelid; /* relation trigger is attached to */
|
Oid tgrelid; /* relation trigger is attached to */
|
||||||
|
Oid tgparentid; /* OID of parent trigger, if any */
|
||||||
NameData tgname; /* trigger's name */
|
NameData tgname; /* trigger's name */
|
||||||
Oid tgfoid; /* OID of function to be called */
|
Oid tgfoid; /* OID of function to be called */
|
||||||
int16 tgtype; /* BEFORE/AFTER/INSTEAD, UPDATE/DELETE/INSERT,
|
int16 tgtype; /* BEFORE/AFTER/INSTEAD, UPDATE/DELETE/INSERT,
|
||||||
|
|
|
@ -208,6 +208,9 @@ timestamp_tbl|f
|
||||||
timestamptz_tbl|f
|
timestamptz_tbl|f
|
||||||
timetz_tbl|f
|
timetz_tbl|f
|
||||||
tmp|f
|
tmp|f
|
||||||
|
trigger_parted|t
|
||||||
|
trigger_parted_p1|t
|
||||||
|
trigger_parted_p1_1|t
|
||||||
varchar_tbl|f
|
varchar_tbl|f
|
||||||
view_base_table|t
|
view_base_table|t
|
||||||
-- restore normal output mode
|
-- restore normal output mode
|
||||||
|
|
|
@ -2928,3 +2928,12 @@ drop table self_ref;
|
||||||
drop function dump_insert();
|
drop function dump_insert();
|
||||||
drop function dump_update();
|
drop function dump_update();
|
||||||
drop function dump_delete();
|
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);
|
||||||
|
|
|
@ -2213,3 +2213,13 @@ drop table self_ref;
|
||||||
drop function dump_insert();
|
drop function dump_insert();
|
||||||
drop function dump_update();
|
drop function dump_update();
|
||||||
drop function dump_delete();
|
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);
|
||||||
|
|
Loading…
Reference in New Issue