Preserve firing-on state when cloning row triggers to partitions
When triggers are cloned from partitioned tables to their partitions, the 'tgenabled' flag (origin/replica/always/disable) was not propagated. Make it so that the flag on the trigger on partition is initially set to the same value as on the partitioned table. Add a test case to verify the behavior. Backpatch to 11, where this appeared in commit 86f575948c77. Author: Álvaro Herrera <alvherre@alvh.no-ip.org> Reported-by: Justin Pryzby <pryzby@telsasoft.com> Discussion: https://postgr.es/m/20200930223450.GA14848@telsasoft.com
This commit is contained in:
parent
e5bcbb1070
commit
eef92de11e
@ -17641,10 +17641,10 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
|
|||||||
trigStmt->initdeferred = trigForm->tginitdeferred;
|
trigStmt->initdeferred = trigForm->tginitdeferred;
|
||||||
trigStmt->constrrel = NULL; /* passed separately */
|
trigStmt->constrrel = NULL; /* passed separately */
|
||||||
|
|
||||||
CreateTrigger(trigStmt, NULL, RelationGetRelid(partition),
|
CreateTriggerFiringOn(trigStmt, NULL, RelationGetRelid(partition),
|
||||||
trigForm->tgconstrrelid, InvalidOid, InvalidOid,
|
trigForm->tgconstrrelid, InvalidOid, InvalidOid,
|
||||||
trigForm->tgfoid, trigForm->oid, qual,
|
trigForm->tgfoid, trigForm->oid, qual,
|
||||||
false, true);
|
false, true, trigForm->tgenabled);
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
MemoryContextReset(perTupCxt);
|
MemoryContextReset(perTupCxt);
|
||||||
|
@ -151,6 +151,24 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
|
|||||||
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
|
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
|
||||||
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
|
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
|
||||||
bool isInternal, bool in_partition)
|
bool isInternal, bool in_partition)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
CreateTriggerFiringOn(stmt, queryString, relOid, refRelOid,
|
||||||
|
constraintOid, indexOid, funcoid,
|
||||||
|
parentTriggerOid, whenClause, isInternal,
|
||||||
|
in_partition, TRIGGER_FIRES_ON_ORIGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like the above; additionally the firing condition
|
||||||
|
* (always/origin/replica/disabled) can be specified.
|
||||||
|
*/
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
int16 tgtype;
|
int16 tgtype;
|
||||||
int ncolumns;
|
int ncolumns;
|
||||||
@ -848,7 +866,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
|
|||||||
CStringGetDatum(trigname));
|
CStringGetDatum(trigname));
|
||||||
values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
|
values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
|
||||||
values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
|
values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
|
||||||
values[Anum_pg_trigger_tgenabled - 1] = CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
|
values[Anum_pg_trigger_tgenabled - 1] = trigger_fires_when;
|
||||||
values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal || in_partition);
|
values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal || in_partition);
|
||||||
values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
|
values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
|
||||||
values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
|
values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
|
||||||
@ -1195,11 +1213,11 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
|
|||||||
map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
|
map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
|
||||||
childTbl, rel);
|
childTbl, rel);
|
||||||
|
|
||||||
CreateTrigger(childStmt, queryString,
|
CreateTriggerFiringOn(childStmt, queryString,
|
||||||
partdesc->oids[i], refRelOid,
|
partdesc->oids[i], refRelOid,
|
||||||
InvalidOid, indexOnChild,
|
InvalidOid, indexOnChild,
|
||||||
funcoid, trigoid, qual,
|
funcoid, trigoid, qual,
|
||||||
isInternal, true);
|
isInternal, true, trigger_fires_when);
|
||||||
|
|
||||||
table_close(childTbl, NoLock);
|
table_close(childTbl, NoLock);
|
||||||
|
|
||||||
|
@ -154,6 +154,11 @@ extern ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString
|
|||||||
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
|
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
|
||||||
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
|
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
|
||||||
bool isInternal, bool in_partition);
|
bool isInternal, bool in_partition);
|
||||||
|
extern 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);
|
||||||
|
|
||||||
extern void RemoveTriggerById(Oid trigOid);
|
extern void RemoveTriggerById(Oid trigOid);
|
||||||
extern Oid get_trigger_oid(Oid relid, const char *name, bool missing_ok);
|
extern Oid get_trigger_oid(Oid relid, const char *name, bool missing_ok);
|
||||||
|
@ -2661,6 +2661,62 @@ select tgrelid::regclass, tgname, tgenabled from pg_trigger
|
|||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
drop table parent, child1;
|
drop table parent, child1;
|
||||||
|
-- Verify that firing state propagates correctly on creation, too
|
||||||
|
CREATE TABLE trgfire (i int) PARTITION BY RANGE (i);
|
||||||
|
CREATE TABLE trgfire1 PARTITION OF trgfire FOR VALUES FROM (1) TO (10);
|
||||||
|
CREATE OR REPLACE FUNCTION tgf() RETURNS trigger LANGUAGE plpgsql
|
||||||
|
AS $$ begin raise exception 'except'; end $$;
|
||||||
|
CREATE TRIGGER tg AFTER INSERT ON trgfire FOR EACH ROW EXECUTE FUNCTION tgf();
|
||||||
|
INSERT INTO trgfire VALUES (1);
|
||||||
|
ERROR: except
|
||||||
|
CONTEXT: PL/pgSQL function tgf() line 1 at RAISE
|
||||||
|
ALTER TABLE trgfire DISABLE TRIGGER tg;
|
||||||
|
INSERT INTO trgfire VALUES (1);
|
||||||
|
CREATE TABLE trgfire2 PARTITION OF trgfire FOR VALUES FROM (10) TO (20);
|
||||||
|
INSERT INTO trgfire VALUES (11);
|
||||||
|
CREATE TABLE trgfire3 (LIKE trgfire);
|
||||||
|
ALTER TABLE trgfire ATTACH PARTITION trgfire3 FOR VALUES FROM (20) TO (30);
|
||||||
|
INSERT INTO trgfire VALUES (21);
|
||||||
|
CREATE TABLE trgfire4 PARTITION OF trgfire FOR VALUES FROM (30) TO (40) PARTITION BY LIST (i);
|
||||||
|
CREATE TABLE trgfire4_30 PARTITION OF trgfire4 FOR VALUES IN (30);
|
||||||
|
INSERT INTO trgfire VALUES (30);
|
||||||
|
CREATE TABLE trgfire5 (LIKE trgfire) PARTITION BY LIST (i);
|
||||||
|
CREATE TABLE trgfire5_40 PARTITION OF trgfire5 FOR VALUES IN (40);
|
||||||
|
ALTER TABLE trgfire ATTACH PARTITION trgfire5 FOR VALUES FROM (40) TO (50);
|
||||||
|
INSERT INTO trgfire VALUES (40);
|
||||||
|
SELECT tgrelid::regclass, tgenabled FROM pg_trigger
|
||||||
|
WHERE tgrelid::regclass IN (SELECT oid from pg_class where relname LIKE 'trgfire%')
|
||||||
|
ORDER BY tgrelid::regclass::text;
|
||||||
|
tgrelid | tgenabled
|
||||||
|
-------------+-----------
|
||||||
|
trgfire | D
|
||||||
|
trgfire1 | D
|
||||||
|
trgfire2 | D
|
||||||
|
trgfire3 | D
|
||||||
|
trgfire4 | D
|
||||||
|
trgfire4_30 | D
|
||||||
|
trgfire5 | D
|
||||||
|
trgfire5_40 | D
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
|
ALTER TABLE trgfire ENABLE TRIGGER tg;
|
||||||
|
INSERT INTO trgfire VALUES (1);
|
||||||
|
ERROR: except
|
||||||
|
CONTEXT: PL/pgSQL function tgf() line 1 at RAISE
|
||||||
|
INSERT INTO trgfire VALUES (11);
|
||||||
|
ERROR: except
|
||||||
|
CONTEXT: PL/pgSQL function tgf() line 1 at RAISE
|
||||||
|
INSERT INTO trgfire VALUES (21);
|
||||||
|
ERROR: except
|
||||||
|
CONTEXT: PL/pgSQL function tgf() line 1 at RAISE
|
||||||
|
INSERT INTO trgfire VALUES (30);
|
||||||
|
ERROR: except
|
||||||
|
CONTEXT: PL/pgSQL function tgf() line 1 at RAISE
|
||||||
|
INSERT INTO trgfire VALUES (40);
|
||||||
|
ERROR: except
|
||||||
|
CONTEXT: PL/pgSQL function tgf() line 1 at RAISE
|
||||||
|
DROP TABLE trgfire;
|
||||||
|
DROP FUNCTION tgf();
|
||||||
--
|
--
|
||||||
-- Test the interaction between transition tables and both kinds of
|
-- Test the interaction between transition tables and both kinds of
|
||||||
-- inheritance. We'll dump the contents of the transition tables in a
|
-- inheritance. We'll dump the contents of the transition tables in a
|
||||||
|
@ -1836,6 +1836,38 @@ select tgrelid::regclass, tgname, tgenabled from pg_trigger
|
|||||||
order by tgrelid::regclass::text;
|
order by tgrelid::regclass::text;
|
||||||
drop table parent, child1;
|
drop table parent, child1;
|
||||||
|
|
||||||
|
-- Verify that firing state propagates correctly on creation, too
|
||||||
|
CREATE TABLE trgfire (i int) PARTITION BY RANGE (i);
|
||||||
|
CREATE TABLE trgfire1 PARTITION OF trgfire FOR VALUES FROM (1) TO (10);
|
||||||
|
CREATE OR REPLACE FUNCTION tgf() RETURNS trigger LANGUAGE plpgsql
|
||||||
|
AS $$ begin raise exception 'except'; end $$;
|
||||||
|
CREATE TRIGGER tg AFTER INSERT ON trgfire FOR EACH ROW EXECUTE FUNCTION tgf();
|
||||||
|
INSERT INTO trgfire VALUES (1);
|
||||||
|
ALTER TABLE trgfire DISABLE TRIGGER tg;
|
||||||
|
INSERT INTO trgfire VALUES (1);
|
||||||
|
CREATE TABLE trgfire2 PARTITION OF trgfire FOR VALUES FROM (10) TO (20);
|
||||||
|
INSERT INTO trgfire VALUES (11);
|
||||||
|
CREATE TABLE trgfire3 (LIKE trgfire);
|
||||||
|
ALTER TABLE trgfire ATTACH PARTITION trgfire3 FOR VALUES FROM (20) TO (30);
|
||||||
|
INSERT INTO trgfire VALUES (21);
|
||||||
|
CREATE TABLE trgfire4 PARTITION OF trgfire FOR VALUES FROM (30) TO (40) PARTITION BY LIST (i);
|
||||||
|
CREATE TABLE trgfire4_30 PARTITION OF trgfire4 FOR VALUES IN (30);
|
||||||
|
INSERT INTO trgfire VALUES (30);
|
||||||
|
CREATE TABLE trgfire5 (LIKE trgfire) PARTITION BY LIST (i);
|
||||||
|
CREATE TABLE trgfire5_40 PARTITION OF trgfire5 FOR VALUES IN (40);
|
||||||
|
ALTER TABLE trgfire ATTACH PARTITION trgfire5 FOR VALUES FROM (40) TO (50);
|
||||||
|
INSERT INTO trgfire VALUES (40);
|
||||||
|
SELECT tgrelid::regclass, tgenabled FROM pg_trigger
|
||||||
|
WHERE tgrelid::regclass IN (SELECT oid from pg_class where relname LIKE 'trgfire%')
|
||||||
|
ORDER BY tgrelid::regclass::text;
|
||||||
|
ALTER TABLE trgfire ENABLE TRIGGER tg;
|
||||||
|
INSERT INTO trgfire VALUES (1);
|
||||||
|
INSERT INTO trgfire VALUES (11);
|
||||||
|
INSERT INTO trgfire VALUES (21);
|
||||||
|
INSERT INTO trgfire VALUES (30);
|
||||||
|
INSERT INTO trgfire VALUES (40);
|
||||||
|
DROP TABLE trgfire;
|
||||||
|
DROP FUNCTION tgf();
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Test the interaction between transition tables and both kinds of
|
-- Test the interaction between transition tables and both kinds of
|
||||||
|
Loading…
x
Reference in New Issue
Block a user