diff --git a/src/test/regress/after_pg_upgrade_schedule b/src/test/regress/after_pg_upgrade_schedule index 52b88d71d..6b8c3973f 100644 --- a/src/test/regress/after_pg_upgrade_schedule +++ b/src/test/regress/after_pg_upgrade_schedule @@ -1,4 +1,4 @@ -test: upgrade_basic_after upgrade_type_after upgrade_ref2ref_after upgrade_distributed_function_after upgrade_rebalance_strategy_after upgrade_list_citus_objects upgrade_autoconverted_after upgrade_citus_stat_activity upgrade_citus_locks +test: upgrade_basic_after upgrade_type_after upgrade_ref2ref_after upgrade_distributed_function_after upgrade_rebalance_strategy_after upgrade_list_citus_objects upgrade_autoconverted_after upgrade_citus_stat_activity upgrade_citus_locks upgrade_distributed_triggers_after # This attempts dropping citus extension (and rollbacks), so please do # not run in parallel with any other tests. diff --git a/src/test/regress/before_pg_upgrade_schedule b/src/test/regress/before_pg_upgrade_schedule index 93bcce368..671d6fa6f 100644 --- a/src/test/regress/before_pg_upgrade_schedule +++ b/src/test/regress/before_pg_upgrade_schedule @@ -8,6 +8,7 @@ test: upgrade_distributed_function_before upgrade_rebalance_strategy_before test: upgrade_autoconverted_before test: upgrade_citus_stat_activity test: upgrade_citus_locks +test: upgrade_distributed_triggers_before # upgrade_columnar_before renames public schema to citus_schema, so let's # run this test as the last one. diff --git a/src/test/regress/expected/upgrade_distributed_triggers_after.out b/src/test/regress/expected/upgrade_distributed_triggers_after.out new file mode 100644 index 000000000..591f33401 --- /dev/null +++ b/src/test/regress/expected/upgrade_distributed_triggers_after.out @@ -0,0 +1,226 @@ +-- +-- UPGRADE_DISTRIBUTED_TRIGGERS_AFTER +-- +-- In PG15, Renaming triggers on partitioned tables +-- recurses to renaming the triggers on the partitions as well. +-- Relevant PG commit: +-- 80ba4bb383538a2ee846fece6a7b8da9518b6866 +-- +-- this test is relevant only for pg14-15 upgrade +-- +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int = 15 AS server_version_eq_15 +\gset +\if :server_version_eq_15 +\else +\q +\endif +SET search_path TO upgrade_distributed_triggers, public; +SET citus.shard_count TO 4; +SET citus.enable_unsafe_triggers TO true; +SELECT run_command_on_workers('ALTER SYSTEM SET citus.enable_unsafe_triggers TO true;'); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,"ALTER SYSTEM") + (localhost,10202,t,"ALTER SYSTEM") +(2 rows) + +SELECT run_command_on_workers('SELECT pg_reload_conf();'); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,t) + (localhost,10202,t,t) +(2 rows) + +-- after PG15 upgrade, all child triggers have the same name with the parent triggers +-- check that the workers are also updated +SELECT * FROM sale_triggers ORDER BY 1, 2; + tgname | tgrelid | tgenabled +--------------------------------------------------------------------- + another_renamed_trigger | sale | O + another_renamed_trigger | sale_newyork | O + another_renamed_trigger | sale_california | O + not_renamed_trigger | sale | O + not_renamed_trigger | sale_newyork | O + not_renamed_trigger | sale_california | O + renamed_record_sale_trigger | sale | O + renamed_record_sale_trigger | sale_newyork | O + renamed_record_sale_trigger | sale_california | O + truncate_trigger_xxxxxxx | sale | O + truncate_trigger_xxxxxxx | sale_newyork | O + truncate_trigger_xxxxxxx | sale_california | O +(12 rows) + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'record_sale_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- +(0 rows) + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- + sale | renamed_record_sale_trigger + sale_california | renamed_record_sale_trigger + sale_newyork | renamed_record_sale_trigger +(3 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'record_sale_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,0) + (localhost,10202,t,0) +(2 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,9) + (localhost,10202,t,9) +(2 rows) + +-- create another partition to verify that all is safe and sound +CREATE TABLE sale_alabama PARTITION OF sale FOR VALUES IN ('AL'); +SELECT * FROM sale_triggers ORDER BY 1, 2; + tgname | tgrelid | tgenabled +--------------------------------------------------------------------- + another_renamed_trigger | sale | O + another_renamed_trigger | sale_newyork | O + another_renamed_trigger | sale_california | O + another_renamed_trigger | sale_alabama | O + not_renamed_trigger | sale | O + not_renamed_trigger | sale_newyork | O + not_renamed_trigger | sale_california | O + not_renamed_trigger | sale_alabama | O + renamed_record_sale_trigger | sale | O + renamed_record_sale_trigger | sale_newyork | O + renamed_record_sale_trigger | sale_california | O + renamed_record_sale_trigger | sale_alabama | O + truncate_trigger_xxxxxxx | sale | O + truncate_trigger_xxxxxxx | sale_newyork | O + truncate_trigger_xxxxxxx | sale_california | O + truncate_trigger_xxxxxxx | sale_alabama | O +(16 rows) + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'record_sale_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- +(0 rows) + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- + sale | renamed_record_sale_trigger + sale_alabama | renamed_record_sale_trigger + sale_california | renamed_record_sale_trigger + sale_newyork | renamed_record_sale_trigger +(4 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'record_sale_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,0) + (localhost,10202,t,0) +(2 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,12) + (localhost,10202,t,12) +(2 rows) + +-- drop a trigger to verify that all is safe and sound +DROP TRIGGER another_renamed_trigger ON sale; +SELECT * FROM sale_triggers ORDER BY 1, 2; + tgname | tgrelid | tgenabled +--------------------------------------------------------------------- + not_renamed_trigger | sale | O + not_renamed_trigger | sale_newyork | O + not_renamed_trigger | sale_california | O + not_renamed_trigger | sale_alabama | O + renamed_record_sale_trigger | sale | O + renamed_record_sale_trigger | sale_newyork | O + renamed_record_sale_trigger | sale_california | O + renamed_record_sale_trigger | sale_alabama | O + truncate_trigger_xxxxxxx | sale | O + truncate_trigger_xxxxxxx | sale_newyork | O + truncate_trigger_xxxxxxx | sale_california | O + truncate_trigger_xxxxxxx | sale_alabama | O +(12 rows) + +-- rename a trigger - note that it also renames the triggers on the partitions +ALTER TRIGGER "renamed_record_sale_trigger" ON "sale" RENAME TO "final_renamed_record_sale_trigger"; +SELECT * FROM sale_triggers ORDER BY 1, 2; + tgname | tgrelid | tgenabled +--------------------------------------------------------------------- + final_renamed_record_sale_trigger | sale | O + final_renamed_record_sale_trigger | sale_newyork | O + final_renamed_record_sale_trigger | sale_california | O + final_renamed_record_sale_trigger | sale_alabama | O + not_renamed_trigger | sale | O + not_renamed_trigger | sale_newyork | O + not_renamed_trigger | sale_california | O + not_renamed_trigger | sale_alabama | O + truncate_trigger_xxxxxxx | sale | O + truncate_trigger_xxxxxxx | sale_newyork | O + truncate_trigger_xxxxxxx | sale_california | O + truncate_trigger_xxxxxxx | sale_alabama | O +(12 rows) + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- +(0 rows) + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'final_renamed_record_sale_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- + sale | final_renamed_record_sale_trigger + sale_alabama | final_renamed_record_sale_trigger + sale_california | final_renamed_record_sale_trigger + sale_newyork | final_renamed_record_sale_trigger +(4 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,0) + (localhost,10202,t,0) +(2 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'final_renamed_record_sale_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,12) + (localhost,10202,t,12) +(2 rows) + +DROP TRIGGER final_renamed_record_sale_trigger ON sale; +-- create another trigger and rename it +CREATE TRIGGER yet_another_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); +ALTER TRIGGER "yet_another_trigger" ON "sale" RENAME TO "renamed_yet_another_trigger"; +SELECT * FROM sale_triggers ORDER BY 1, 2; + tgname | tgrelid | tgenabled +--------------------------------------------------------------------- + not_renamed_trigger | sale | O + not_renamed_trigger | sale_newyork | O + not_renamed_trigger | sale_california | O + not_renamed_trigger | sale_alabama | O + renamed_yet_another_trigger | sale | O + renamed_yet_another_trigger | sale_newyork | O + renamed_yet_another_trigger | sale_california | O + renamed_yet_another_trigger | sale_alabama | O + truncate_trigger_xxxxxxx | sale | O + truncate_trigger_xxxxxxx | sale_newyork | O + truncate_trigger_xxxxxxx | sale_california | O + truncate_trigger_xxxxxxx | sale_alabama | O +(12 rows) + +DROP SCHEMA upgrade_distributed_triggers CASCADE; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to function record_sale() +drop cascades to table sale +drop cascades to table record_sale +drop cascades to view sale_triggers diff --git a/src/test/regress/expected/upgrade_distributed_triggers_after_0.out b/src/test/regress/expected/upgrade_distributed_triggers_after_0.out new file mode 100644 index 000000000..2b1f5cac1 --- /dev/null +++ b/src/test/regress/expected/upgrade_distributed_triggers_after_0.out @@ -0,0 +1,16 @@ +-- +-- UPGRADE_DISTRIBUTED_TRIGGERS_AFTER +-- +-- In PG15, Renaming triggers on partitioned tables +-- recurses to renaming the triggers on the partitions as well. +-- Relevant PG commit: +-- 80ba4bb383538a2ee846fece6a7b8da9518b6866 +-- +-- this test is relevant only for pg14-15 upgrade +-- +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int = 15 AS server_version_eq_15 +\gset +\if :server_version_eq_15 +\else +\q diff --git a/src/test/regress/expected/upgrade_distributed_triggers_before.out b/src/test/regress/expected/upgrade_distributed_triggers_before.out new file mode 100644 index 000000000..5e369c84c --- /dev/null +++ b/src/test/regress/expected/upgrade_distributed_triggers_before.out @@ -0,0 +1,243 @@ +-- +-- UPGRADE_DISTRIBUTED_TRIGGERS_BEFORE +-- +-- PRE PG15, Renaming the parent triggers on partitioned tables doesn't +-- recurse to renaming the child triggers on the partitions as well. +-- +-- this test is relevant only for pg14-15 upgrade +-- +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int = 14 AS server_version_eq_14 +\gset +\if :server_version_eq_14 +\else +\q +\endif +CREATE SCHEMA upgrade_distributed_triggers; +SET search_path TO upgrade_distributed_triggers, public; +SET citus.shard_count TO 4; +SET citus.enable_unsafe_triggers TO true; +SELECT run_command_on_workers('ALTER SYSTEM SET citus.enable_unsafe_triggers TO true;'); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,"ALTER SYSTEM") + (localhost,10202,t,"ALTER SYSTEM") +(2 rows) + +SELECT run_command_on_workers('SELECT pg_reload_conf();'); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,t) + (localhost,10202,t,t) +(2 rows) + +CREATE TABLE sale( + sale_date date not null, + state_code text, + product_sku text, + units integer) + PARTITION BY list (state_code); +ALTER TABLE sale ADD CONSTRAINT sale_pk PRIMARY KEY (state_code, sale_date); +CREATE TABLE sale_newyork PARTITION OF sale FOR VALUES IN ('NY'); +CREATE TABLE record_sale( + operation_type text not null, + product_sku text, + state_code text, + units integer, + PRIMARY KEY(state_code, product_sku, operation_type, units)); +SELECT create_distributed_table('sale', 'state_code'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE sale_california PARTITION OF sale FOR VALUES IN ('CA'); +SELECT create_distributed_table('record_sale', 'state_code', colocate_with := 'sale'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE OR REPLACE FUNCTION record_sale() +RETURNS trigger +AS $$ +BEGIN + INSERT INTO upgrade_distributed_triggers.record_sale(operation_type, product_sku, state_code, units) + VALUES (TG_OP, NEW.product_sku, NEW.state_code, NEW.units); + RETURN NULL; +END; +$$ LANGUAGE plpgsql; +-- will rename this trigger +CREATE TRIGGER record_sale_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); +-- will rename this trigger +CREATE TRIGGER another_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); +-- won't rename this trigger +CREATE TRIGGER not_renamed_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); +-- Trigger function should appear on workers +SELECT proname from pg_proc WHERE oid='upgrade_distributed_triggers.record_sale'::regproc; + proname +--------------------------------------------------------------------- + record_sale +(1 row) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_proc WHERE oid='upgrade_distributed_triggers.record_sale'::regproc$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,1) + (localhost,10202,t,1) +(2 rows) + +-- Trigger should appear on workers +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'record_sale_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- + sale | record_sale_trigger + sale_california | record_sale_trigger + sale_newyork | record_sale_trigger +(3 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'record_sale_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,9) + (localhost,10202,t,9) +(2 rows) + +CREATE VIEW sale_triggers AS + SELECT tgname, tgrelid::regclass, tgenabled + FROM pg_trigger + WHERE tgrelid::regclass::text like 'sale%' + ORDER BY 1, 2; +SELECT * FROM sale_triggers ORDER BY 1, 2; + tgname | tgrelid | tgenabled +--------------------------------------------------------------------- + another_trigger | sale | O + another_trigger | sale_newyork | O + another_trigger | sale_california | O + not_renamed_trigger | sale | O + not_renamed_trigger | sale_newyork | O + not_renamed_trigger | sale_california | O + record_sale_trigger | sale | O + record_sale_trigger | sale_newyork | O + record_sale_trigger | sale_california | O + truncate_trigger_xxxxxxx | sale | O + truncate_trigger_xxxxxxx | sale_newyork | O + truncate_trigger_xxxxxxx | sale_california | O +(12 rows) + +-- rename the triggers - note that it doesn't rename the +-- triggers on the partitions +ALTER TRIGGER record_sale_trigger ON sale RENAME TO renamed_record_sale_trigger; +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'record_sale_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- + sale_california | record_sale_trigger + sale_newyork | record_sale_trigger +(2 rows) + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- + sale | renamed_record_sale_trigger +(1 row) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'record_sale_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,6) + (localhost,10202,t,6) +(2 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,3) + (localhost,10202,t,3) +(2 rows) + +ALTER TRIGGER another_trigger ON sale RENAME TO another_renamed_trigger; +SELECT * FROM sale_triggers ORDER BY 1, 2; + tgname | tgrelid | tgenabled +--------------------------------------------------------------------- + another_renamed_trigger | sale | O + another_trigger | sale_newyork | O + another_trigger | sale_california | O + not_renamed_trigger | sale | O + not_renamed_trigger | sale_newyork | O + not_renamed_trigger | sale_california | O + record_sale_trigger | sale_newyork | O + record_sale_trigger | sale_california | O + renamed_record_sale_trigger | sale | O + truncate_trigger_xxxxxxx | sale | O + truncate_trigger_xxxxxxx | sale_newyork | O + truncate_trigger_xxxxxxx | sale_california | O +(12 rows) + +-- although the child triggers haven't been renamed to +-- another_renamed_trigger, they are dropped when the parent is dropped +DROP TRIGGER another_renamed_trigger ON sale; +SELECT * FROM sale_triggers ORDER BY 1, 2; + tgname | tgrelid | tgenabled +--------------------------------------------------------------------- + not_renamed_trigger | sale | O + not_renamed_trigger | sale_newyork | O + not_renamed_trigger | sale_california | O + record_sale_trigger | sale_newyork | O + record_sale_trigger | sale_california | O + renamed_record_sale_trigger | sale | O + truncate_trigger_xxxxxxx | sale | O + truncate_trigger_xxxxxxx | sale_newyork | O + truncate_trigger_xxxxxxx | sale_california | O +(9 rows) + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'another_renamed_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- +(0 rows) + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'another_trigger%' ORDER BY 1,2; + tgrelid | tgname +--------------------------------------------------------------------- +(0 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'another_renamed_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,0) + (localhost,10202,t,0) +(2 rows) + +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'another_trigger%';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,10201,t,0) + (localhost,10202,t,0) +(2 rows) + +CREATE TRIGGER another_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); +ALTER TRIGGER another_trigger ON sale RENAME TO another_renamed_trigger; +SELECT * FROM sale_triggers ORDER BY 1, 2; + tgname | tgrelid | tgenabled +--------------------------------------------------------------------- + another_renamed_trigger | sale | O + another_trigger | sale_newyork | O + another_trigger | sale_california | O + not_renamed_trigger | sale | O + not_renamed_trigger | sale_newyork | O + not_renamed_trigger | sale_california | O + record_sale_trigger | sale_newyork | O + record_sale_trigger | sale_california | O + renamed_record_sale_trigger | sale | O + truncate_trigger_xxxxxxx | sale | O + truncate_trigger_xxxxxxx | sale_newyork | O + truncate_trigger_xxxxxxx | sale_california | O +(12 rows) + diff --git a/src/test/regress/expected/upgrade_distributed_triggers_before_0.out b/src/test/regress/expected/upgrade_distributed_triggers_before_0.out new file mode 100644 index 000000000..34a7cedf2 --- /dev/null +++ b/src/test/regress/expected/upgrade_distributed_triggers_before_0.out @@ -0,0 +1,14 @@ +-- +-- UPGRADE_DISTRIBUTED_TRIGGERS_BEFORE +-- +-- PRE PG15, Renaming the parent triggers on partitioned tables doesn't +-- recurse to renaming the child triggers on the partitions as well. +-- +-- this test is relevant only for pg14-15 upgrade +-- +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int = 14 AS server_version_eq_14 +\gset +\if :server_version_eq_14 +\else +\q diff --git a/src/test/regress/sql/upgrade_distributed_triggers_after.sql b/src/test/regress/sql/upgrade_distributed_triggers_after.sql new file mode 100644 index 000000000..bcbd7432e --- /dev/null +++ b/src/test/regress/sql/upgrade_distributed_triggers_after.sql @@ -0,0 +1,72 @@ +-- +-- UPGRADE_DISTRIBUTED_TRIGGERS_AFTER +-- +-- In PG15, Renaming triggers on partitioned tables +-- recurses to renaming the triggers on the partitions as well. +-- Relevant PG commit: +-- 80ba4bb383538a2ee846fece6a7b8da9518b6866 +-- +-- this test is relevant only for pg14-15 upgrade +-- + +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int = 15 AS server_version_eq_15 +\gset +\if :server_version_eq_15 +\else +\q +\endif + +SET search_path TO upgrade_distributed_triggers, public; +SET citus.shard_count TO 4; + +SET citus.enable_unsafe_triggers TO true; +SELECT run_command_on_workers('ALTER SYSTEM SET citus.enable_unsafe_triggers TO true;'); +SELECT run_command_on_workers('SELECT pg_reload_conf();'); + +-- after PG15 upgrade, all child triggers have the same name with the parent triggers +-- check that the workers are also updated +SELECT * FROM sale_triggers ORDER BY 1, 2; + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'record_sale_trigger%' ORDER BY 1,2; +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%' ORDER BY 1,2; +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'record_sale_trigger%';$$); +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%';$$); + +-- create another partition to verify that all is safe and sound +CREATE TABLE sale_alabama PARTITION OF sale FOR VALUES IN ('AL'); + +SELECT * FROM sale_triggers ORDER BY 1, 2; + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'record_sale_trigger%' ORDER BY 1,2; +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%' ORDER BY 1,2; +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'record_sale_trigger%';$$); +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%';$$); + +-- drop a trigger to verify that all is safe and sound +DROP TRIGGER another_renamed_trigger ON sale; + +SELECT * FROM sale_triggers ORDER BY 1, 2; + +-- rename a trigger - note that it also renames the triggers on the partitions +ALTER TRIGGER "renamed_record_sale_trigger" ON "sale" RENAME TO "final_renamed_record_sale_trigger"; + +SELECT * FROM sale_triggers ORDER BY 1, 2; + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%' ORDER BY 1,2; +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'final_renamed_record_sale_trigger%' ORDER BY 1,2; +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%';$$); +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'final_renamed_record_sale_trigger%';$$); + +DROP TRIGGER final_renamed_record_sale_trigger ON sale; + +-- create another trigger and rename it +CREATE TRIGGER yet_another_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); + +ALTER TRIGGER "yet_another_trigger" ON "sale" RENAME TO "renamed_yet_another_trigger"; + +SELECT * FROM sale_triggers ORDER BY 1, 2; + +DROP SCHEMA upgrade_distributed_triggers CASCADE; diff --git a/src/test/regress/sql/upgrade_distributed_triggers_before.sql b/src/test/regress/sql/upgrade_distributed_triggers_before.sql new file mode 100644 index 000000000..a1d4c9db3 --- /dev/null +++ b/src/test/regress/sql/upgrade_distributed_triggers_before.sql @@ -0,0 +1,116 @@ +-- +-- UPGRADE_DISTRIBUTED_TRIGGERS_BEFORE +-- +-- PRE PG15, Renaming the parent triggers on partitioned tables doesn't +-- recurse to renaming the child triggers on the partitions as well. +-- +-- this test is relevant only for pg14-15 upgrade +-- + +SHOW server_version \gset +SELECT substring(:'server_version', '\d+')::int = 14 AS server_version_eq_14 +\gset +\if :server_version_eq_14 +\else +\q +\endif + +CREATE SCHEMA upgrade_distributed_triggers; +SET search_path TO upgrade_distributed_triggers, public; +SET citus.shard_count TO 4; + +SET citus.enable_unsafe_triggers TO true; +SELECT run_command_on_workers('ALTER SYSTEM SET citus.enable_unsafe_triggers TO true;'); +SELECT run_command_on_workers('SELECT pg_reload_conf();'); + +CREATE TABLE sale( + sale_date date not null, + state_code text, + product_sku text, + units integer) + PARTITION BY list (state_code); + +ALTER TABLE sale ADD CONSTRAINT sale_pk PRIMARY KEY (state_code, sale_date); + +CREATE TABLE sale_newyork PARTITION OF sale FOR VALUES IN ('NY'); + +CREATE TABLE record_sale( + operation_type text not null, + product_sku text, + state_code text, + units integer, + PRIMARY KEY(state_code, product_sku, operation_type, units)); + +SELECT create_distributed_table('sale', 'state_code'); +CREATE TABLE sale_california PARTITION OF sale FOR VALUES IN ('CA'); +SELECT create_distributed_table('record_sale', 'state_code', colocate_with := 'sale'); + +CREATE OR REPLACE FUNCTION record_sale() +RETURNS trigger +AS $$ +BEGIN + INSERT INTO upgrade_distributed_triggers.record_sale(operation_type, product_sku, state_code, units) + VALUES (TG_OP, NEW.product_sku, NEW.state_code, NEW.units); + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +-- will rename this trigger +CREATE TRIGGER record_sale_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); + +-- will rename this trigger +CREATE TRIGGER another_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); + +-- won't rename this trigger +CREATE TRIGGER not_renamed_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); + +-- Trigger function should appear on workers +SELECT proname from pg_proc WHERE oid='upgrade_distributed_triggers.record_sale'::regproc; +SELECT run_command_on_workers($$SELECT count(*) FROM pg_proc WHERE oid='upgrade_distributed_triggers.record_sale'::regproc$$); + +-- Trigger should appear on workers +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'record_sale_trigger%' ORDER BY 1,2; +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'record_sale_trigger%';$$); + +CREATE VIEW sale_triggers AS + SELECT tgname, tgrelid::regclass, tgenabled + FROM pg_trigger + WHERE tgrelid::regclass::text like 'sale%' + ORDER BY 1, 2; + +SELECT * FROM sale_triggers ORDER BY 1, 2; + +-- rename the triggers - note that it doesn't rename the +-- triggers on the partitions +ALTER TRIGGER record_sale_trigger ON sale RENAME TO renamed_record_sale_trigger; + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'record_sale_trigger%' ORDER BY 1,2; +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%' ORDER BY 1,2; +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'record_sale_trigger%';$$); +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'renamed_record_sale_trigger%';$$); + +ALTER TRIGGER another_trigger ON sale RENAME TO another_renamed_trigger; +SELECT * FROM sale_triggers ORDER BY 1, 2; + +-- although the child triggers haven't been renamed to +-- another_renamed_trigger, they are dropped when the parent is dropped +DROP TRIGGER another_renamed_trigger ON sale; +SELECT * FROM sale_triggers ORDER BY 1, 2; + +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'another_renamed_trigger%' ORDER BY 1,2; +SELECT tgrelid::regclass::text, tgname FROM pg_trigger WHERE tgname like 'another_trigger%' ORDER BY 1,2; +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'another_renamed_trigger%';$$); +SELECT run_command_on_workers($$SELECT count(*) FROM pg_trigger WHERE tgname like 'another_trigger%';$$); + +CREATE TRIGGER another_trigger +AFTER INSERT OR UPDATE OR DELETE ON sale +FOR EACH ROW EXECUTE FUNCTION upgrade_distributed_triggers.record_sale(); + +ALTER TRIGGER another_trigger ON sale RENAME TO another_renamed_trigger; +SELECT * FROM sale_triggers ORDER BY 1, 2;