mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
Improve handling of dropped objects in pg_event_trigger_ddl_commands()
An object found as dropped when digging into the list of objects returned by pg_event_trigger_ddl_commands() could cause a cache lookup error, as the calls grabbing for the object address and the type name would fail if the object was missing. Those lookup errors could be seen with combinations of ALTER TABLE sub-commands involving identity columns. The lookup logic is changed in this code path to get a behavior similar to any other SQL-callable function by ignoring objects that are not found, taking advantage of 2a10fdc. The back-branches are not changed, as they require this commit that is too invasive for stable branches. While on it, add test cases to exercise event triggers with identity columns, and stress more cases with the event ddl_command_end for relations. Author: Sven Klemm, Aleksander Alekseev, Michael Paquier Discussion: https://postgr.es/m/CAMCrgp2R1cEXU53iYKtW6yVEp2_yKUz+z=3-CTrYpPP+xryRtg@mail.gmail.com
This commit is contained in:
parent
dbab0c07e5
commit
2d689babe3
@ -1936,8 +1936,19 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
|
|||||||
else if (cmd->type == SCT_AlterTSConfig)
|
else if (cmd->type == SCT_AlterTSConfig)
|
||||||
addr = cmd->d.atscfg.address;
|
addr = cmd->d.atscfg.address;
|
||||||
|
|
||||||
type = getObjectTypeDescription(&addr, false);
|
/*
|
||||||
identity = getObjectIdentity(&addr, false);
|
* If an object was dropped in the same command we may end
|
||||||
|
* up in a situation where we generated a message but can
|
||||||
|
* no longer look for the object information, so skip it
|
||||||
|
* rather than failing. This can happen for example with
|
||||||
|
* some subcommand combinations of ALTER TABLE.
|
||||||
|
*/
|
||||||
|
identity = getObjectIdentity(&addr, true);
|
||||||
|
if (identity == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* The type can never be NULL. */
|
||||||
|
type = getObjectTypeDescription(&addr, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain schema name, if any ("pg_temp" if a temp
|
* Obtain schema name, if any ("pg_temp" if a temp
|
||||||
|
@ -366,6 +366,7 @@ SELECT * FROM dropped_objects WHERE type = 'schema';
|
|||||||
DROP ROLE regress_evt_user;
|
DROP ROLE regress_evt_user;
|
||||||
DROP EVENT TRIGGER regress_event_trigger_drop_objects;
|
DROP EVENT TRIGGER regress_event_trigger_drop_objects;
|
||||||
DROP EVENT TRIGGER undroppable;
|
DROP EVENT TRIGGER undroppable;
|
||||||
|
-- Event triggers on relations.
|
||||||
CREATE OR REPLACE FUNCTION event_trigger_report_dropped()
|
CREATE OR REPLACE FUNCTION event_trigger_report_dropped()
|
||||||
RETURNS event_trigger
|
RETURNS event_trigger
|
||||||
LANGUAGE plpgsql
|
LANGUAGE plpgsql
|
||||||
@ -384,41 +385,90 @@ BEGIN
|
|||||||
END; $$;
|
END; $$;
|
||||||
CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop
|
CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop
|
||||||
EXECUTE PROCEDURE event_trigger_report_dropped();
|
EXECUTE PROCEDURE event_trigger_report_dropped();
|
||||||
|
CREATE OR REPLACE FUNCTION event_trigger_report_end()
|
||||||
|
RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE r RECORD;
|
||||||
|
BEGIN
|
||||||
|
FOR r IN SELECT * FROM pg_event_trigger_ddl_commands()
|
||||||
|
LOOP
|
||||||
|
RAISE NOTICE 'END: command_tag=% type=% identity=%',
|
||||||
|
r.command_tag, r.object_type, r.object_identity;
|
||||||
|
END LOOP;
|
||||||
|
END; $$;
|
||||||
|
CREATE EVENT TRIGGER regress_event_trigger_report_end ON ddl_command_end
|
||||||
|
EXECUTE PROCEDURE event_trigger_report_end();
|
||||||
CREATE SCHEMA evttrig
|
CREATE SCHEMA evttrig
|
||||||
CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two')
|
CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two', col_c SERIAL)
|
||||||
CREATE INDEX one_idx ON one (col_b)
|
CREATE INDEX one_idx ON one (col_b)
|
||||||
CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42);
|
CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42)
|
||||||
|
CREATE TABLE id (col_d int NOT NULL GENERATED ALWAYS AS IDENTITY);
|
||||||
|
NOTICE: END: command_tag=CREATE SCHEMA type=schema identity=evttrig
|
||||||
|
NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_a_seq
|
||||||
|
NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_c_seq
|
||||||
|
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.one
|
||||||
|
NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_pkey
|
||||||
|
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_a_seq
|
||||||
|
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_c_seq
|
||||||
|
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.two
|
||||||
|
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.two
|
||||||
|
NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.id_col_d_seq
|
||||||
|
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.id
|
||||||
|
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.id_col_d_seq
|
||||||
|
NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_idx
|
||||||
-- Partitioned tables with a partitioned index
|
-- Partitioned tables with a partitioned index
|
||||||
CREATE TABLE evttrig.parted (
|
CREATE TABLE evttrig.parted (
|
||||||
id int PRIMARY KEY)
|
id int PRIMARY KEY)
|
||||||
PARTITION BY RANGE (id);
|
PARTITION BY RANGE (id);
|
||||||
|
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.parted
|
||||||
|
NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.parted_pkey
|
||||||
CREATE TABLE evttrig.part_1_10 PARTITION OF evttrig.parted (id)
|
CREATE TABLE evttrig.part_1_10 PARTITION OF evttrig.parted (id)
|
||||||
FOR VALUES FROM (1) TO (10);
|
FOR VALUES FROM (1) TO (10);
|
||||||
|
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_1_10
|
||||||
CREATE TABLE evttrig.part_10_20 PARTITION OF evttrig.parted (id)
|
CREATE TABLE evttrig.part_10_20 PARTITION OF evttrig.parted (id)
|
||||||
FOR VALUES FROM (10) TO (20) PARTITION BY RANGE (id);
|
FOR VALUES FROM (10) TO (20) PARTITION BY RANGE (id);
|
||||||
|
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_10_20
|
||||||
CREATE TABLE evttrig.part_10_15 PARTITION OF evttrig.part_10_20 (id)
|
CREATE TABLE evttrig.part_10_15 PARTITION OF evttrig.part_10_20 (id)
|
||||||
FOR VALUES FROM (10) TO (15);
|
FOR VALUES FROM (10) TO (15);
|
||||||
|
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_10_15
|
||||||
CREATE TABLE evttrig.part_15_20 PARTITION OF evttrig.part_10_20 (id)
|
CREATE TABLE evttrig.part_15_20 PARTITION OF evttrig.part_10_20 (id)
|
||||||
FOR VALUES FROM (15) TO (20);
|
FOR VALUES FROM (15) TO (20);
|
||||||
|
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.part_15_20
|
||||||
ALTER TABLE evttrig.two DROP COLUMN col_c;
|
ALTER TABLE evttrig.two DROP COLUMN col_c;
|
||||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=table column identity=evttrig.two.col_c name={evttrig,two,col_c} args={}
|
NOTICE: NORMAL: orig=t normal=f istemp=f type=table column identity=evttrig.two.col_c name={evttrig,two,col_c} args={}
|
||||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table constraint identity=two_col_c_check on evttrig.two name={evttrig,two,two_col_c_check} args={}
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=table constraint identity=two_col_c_check on evttrig.two name={evttrig,two,two_col_c_check} args={}
|
||||||
|
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.two
|
||||||
ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT;
|
ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT;
|
||||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=default value identity=for evttrig.one.col_b name={evttrig,one,col_b} args={}
|
NOTICE: NORMAL: orig=t normal=f istemp=f type=default value identity=for evttrig.one.col_b name={evttrig,one,col_b} args={}
|
||||||
|
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one
|
||||||
ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey;
|
ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey;
|
||||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=table constraint identity=one_pkey on evttrig.one name={evttrig,one,one_pkey} args={}
|
NOTICE: NORMAL: orig=t normal=f istemp=f type=table constraint identity=one_pkey on evttrig.one name={evttrig,one,one_pkey} args={}
|
||||||
|
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one
|
||||||
|
ALTER TABLE evttrig.one DROP COLUMN col_c;
|
||||||
|
NOTICE: NORMAL: orig=t normal=f istemp=f type=table column identity=evttrig.one.col_c name={evttrig,one,col_c} args={}
|
||||||
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=default value identity=for evttrig.one.col_c name={evttrig,one,col_c} args={}
|
||||||
|
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one
|
||||||
|
ALTER TABLE evttrig.id ALTER COLUMN col_d SET DATA TYPE bigint;
|
||||||
|
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.id_col_d_seq
|
||||||
|
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.id
|
||||||
|
ALTER TABLE evttrig.id ALTER COLUMN col_d DROP IDENTITY,
|
||||||
|
ALTER COLUMN col_d SET DATA TYPE int;
|
||||||
|
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.id
|
||||||
DROP INDEX evttrig.one_idx;
|
DROP INDEX evttrig.one_idx;
|
||||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=index identity=evttrig.one_idx name={evttrig,one_idx} args={}
|
NOTICE: NORMAL: orig=t normal=f istemp=f type=index identity=evttrig.one_idx name={evttrig,one_idx} args={}
|
||||||
DROP SCHEMA evttrig CASCADE;
|
DROP SCHEMA evttrig CASCADE;
|
||||||
NOTICE: drop cascades to 3 other objects
|
NOTICE: drop cascades to 4 other objects
|
||||||
DETAIL: drop cascades to table evttrig.one
|
DETAIL: drop cascades to table evttrig.one
|
||||||
drop cascades to table evttrig.two
|
drop cascades to table evttrig.two
|
||||||
|
drop cascades to table evttrig.id
|
||||||
drop cascades to table evttrig.parted
|
drop cascades to table evttrig.parted
|
||||||
NOTICE: NORMAL: orig=t normal=f istemp=f type=schema identity=evttrig name={evttrig} args={}
|
NOTICE: NORMAL: orig=t normal=f istemp=f type=schema identity=evttrig name={evttrig} args={}
|
||||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.one name={evttrig,one} args={}
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.one name={evttrig,one} args={}
|
||||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=sequence identity=evttrig.one_col_a_seq name={evttrig,one_col_a_seq} args={}
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=sequence identity=evttrig.one_col_a_seq name={evttrig,one_col_a_seq} args={}
|
||||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=default value identity=for evttrig.one.col_a name={evttrig,one,col_a} args={}
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=default value identity=for evttrig.one.col_a name={evttrig,one,col_a} args={}
|
||||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.two name={evttrig,two} args={}
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.two name={evttrig,two} args={}
|
||||||
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.id name={evttrig,id} args={}
|
||||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.parted name={evttrig,parted} args={}
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.parted name={evttrig,parted} args={}
|
||||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_1_10 name={evttrig,part_1_10} args={}
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_1_10 name={evttrig,part_1_10} args={}
|
||||||
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_10_20 name={evttrig,part_10_20} args={}
|
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_10_20 name={evttrig,part_10_20} args={}
|
||||||
@ -427,6 +477,7 @@ NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_15_20
|
|||||||
DROP TABLE a_temp_tbl;
|
DROP TABLE a_temp_tbl;
|
||||||
NOTICE: NORMAL: orig=t normal=f istemp=t type=table identity=pg_temp.a_temp_tbl name={pg_temp,a_temp_tbl} args={}
|
NOTICE: NORMAL: orig=t normal=f istemp=t type=table identity=pg_temp.a_temp_tbl name={pg_temp,a_temp_tbl} args={}
|
||||||
DROP EVENT TRIGGER regress_event_trigger_report_dropped;
|
DROP EVENT TRIGGER regress_event_trigger_report_dropped;
|
||||||
|
DROP EVENT TRIGGER regress_event_trigger_report_end;
|
||||||
-- only allowed from within an event trigger function, should fail
|
-- only allowed from within an event trigger function, should fail
|
||||||
select pg_event_trigger_table_rewrite_oid();
|
select pg_event_trigger_table_rewrite_oid();
|
||||||
ERROR: pg_event_trigger_table_rewrite_oid() can only be called in a table_rewrite event trigger function
|
ERROR: pg_event_trigger_table_rewrite_oid() can only be called in a table_rewrite event trigger function
|
||||||
|
@ -273,6 +273,7 @@ DROP ROLE regress_evt_user;
|
|||||||
DROP EVENT TRIGGER regress_event_trigger_drop_objects;
|
DROP EVENT TRIGGER regress_event_trigger_drop_objects;
|
||||||
DROP EVENT TRIGGER undroppable;
|
DROP EVENT TRIGGER undroppable;
|
||||||
|
|
||||||
|
-- Event triggers on relations.
|
||||||
CREATE OR REPLACE FUNCTION event_trigger_report_dropped()
|
CREATE OR REPLACE FUNCTION event_trigger_report_dropped()
|
||||||
RETURNS event_trigger
|
RETURNS event_trigger
|
||||||
LANGUAGE plpgsql
|
LANGUAGE plpgsql
|
||||||
@ -291,10 +292,26 @@ BEGIN
|
|||||||
END; $$;
|
END; $$;
|
||||||
CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop
|
CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop
|
||||||
EXECUTE PROCEDURE event_trigger_report_dropped();
|
EXECUTE PROCEDURE event_trigger_report_dropped();
|
||||||
|
CREATE OR REPLACE FUNCTION event_trigger_report_end()
|
||||||
|
RETURNS event_trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE r RECORD;
|
||||||
|
BEGIN
|
||||||
|
FOR r IN SELECT * FROM pg_event_trigger_ddl_commands()
|
||||||
|
LOOP
|
||||||
|
RAISE NOTICE 'END: command_tag=% type=% identity=%',
|
||||||
|
r.command_tag, r.object_type, r.object_identity;
|
||||||
|
END LOOP;
|
||||||
|
END; $$;
|
||||||
|
CREATE EVENT TRIGGER regress_event_trigger_report_end ON ddl_command_end
|
||||||
|
EXECUTE PROCEDURE event_trigger_report_end();
|
||||||
|
|
||||||
CREATE SCHEMA evttrig
|
CREATE SCHEMA evttrig
|
||||||
CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two')
|
CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two', col_c SERIAL)
|
||||||
CREATE INDEX one_idx ON one (col_b)
|
CREATE INDEX one_idx ON one (col_b)
|
||||||
CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42);
|
CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42)
|
||||||
|
CREATE TABLE id (col_d int NOT NULL GENERATED ALWAYS AS IDENTITY);
|
||||||
|
|
||||||
-- Partitioned tables with a partitioned index
|
-- Partitioned tables with a partitioned index
|
||||||
CREATE TABLE evttrig.parted (
|
CREATE TABLE evttrig.parted (
|
||||||
@ -312,11 +329,16 @@ CREATE TABLE evttrig.part_15_20 PARTITION OF evttrig.part_10_20 (id)
|
|||||||
ALTER TABLE evttrig.two DROP COLUMN col_c;
|
ALTER TABLE evttrig.two DROP COLUMN col_c;
|
||||||
ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT;
|
ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT;
|
||||||
ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey;
|
ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey;
|
||||||
|
ALTER TABLE evttrig.one DROP COLUMN col_c;
|
||||||
|
ALTER TABLE evttrig.id ALTER COLUMN col_d SET DATA TYPE bigint;
|
||||||
|
ALTER TABLE evttrig.id ALTER COLUMN col_d DROP IDENTITY,
|
||||||
|
ALTER COLUMN col_d SET DATA TYPE int;
|
||||||
DROP INDEX evttrig.one_idx;
|
DROP INDEX evttrig.one_idx;
|
||||||
DROP SCHEMA evttrig CASCADE;
|
DROP SCHEMA evttrig CASCADE;
|
||||||
DROP TABLE a_temp_tbl;
|
DROP TABLE a_temp_tbl;
|
||||||
|
|
||||||
DROP EVENT TRIGGER regress_event_trigger_report_dropped;
|
DROP EVENT TRIGGER regress_event_trigger_report_dropped;
|
||||||
|
DROP EVENT TRIGGER regress_event_trigger_report_end;
|
||||||
|
|
||||||
-- only allowed from within an event trigger function, should fail
|
-- only allowed from within an event trigger function, should fail
|
||||||
select pg_event_trigger_table_rewrite_oid();
|
select pg_event_trigger_table_rewrite_oid();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user