diff --git a/src/backend/distributed/commands/citus_add_local_table_to_metadata.c b/src/backend/distributed/commands/citus_add_local_table_to_metadata.c index ebc69d19b..c713ce099 100644 --- a/src/backend/distributed/commands/citus_add_local_table_to_metadata.c +++ b/src/backend/distributed/commands/citus_add_local_table_to_metadata.c @@ -1478,11 +1478,20 @@ InsertMetadataForCitusLocalTable(Oid citusLocalTableId, uint64 shardId, static void FinalizeCitusLocalTableCreation(Oid relationId) { +#if PG_VERSION_NUM >= PG_VERSION_16 + + /* + * PG16+ supports truncate triggers on foreign tables + */ + if (RegularTable(relationId) || IsForeignTable(relationId)) +#else + /* * If it is a foreign table, then skip creating citus truncate trigger * as foreign tables do not support truncate triggers. */ if (RegularTable(relationId)) +#endif { CreateTruncateTrigger(relationId); } diff --git a/src/backend/distributed/commands/create_distributed_table.c b/src/backend/distributed/commands/create_distributed_table.c index ff02593f5..dc06692b3 100644 --- a/src/backend/distributed/commands/create_distributed_table.c +++ b/src/backend/distributed/commands/create_distributed_table.c @@ -1256,8 +1256,17 @@ CreateCitusTable(Oid relationId, CitusTableType tableType, colocationId, citusTableParams.replicationModel, autoConverted); +#if PG_VERSION_NUM >= PG_VERSION_16 + + /* + * PG16+ supports truncate triggers on foreign tables + */ + if (RegularTable(relationId) || IsForeignTable(relationId)) +#else + /* foreign tables do not support TRUNCATE trigger */ if (RegularTable(relationId)) +#endif { CreateTruncateTrigger(relationId); } diff --git a/src/test/regress/expected/pg16.out b/src/test/regress/expected/pg16.out index 8c0fdc859..27abfdf7a 100644 --- a/src/test/regress/expected/pg16.out +++ b/src/test/regress/expected/pg16.out @@ -314,6 +314,80 @@ SELECT result FROM run_command_on_workers (2 rows) SET search_path TO pg16; +SET citus.next_shard_id TO 951000; +-- Foreign table TRUNCATE trigger +-- Relevant PG commit: +-- https://github.com/postgres/postgres/commit/3b00a94 +SELECT 1 FROM citus_add_node('localhost', :master_port, groupid => 0); + ?column? +--------------------------------------------------------------------- + 1 +(1 row) + +SET citus.use_citus_managed_tables TO ON; +CREATE TABLE foreign_table_test (id integer NOT NULL, data text, a bigserial); +INSERT INTO foreign_table_test VALUES (1, 'text_test'); +CREATE EXTENSION postgres_fdw; +CREATE SERVER foreign_server + FOREIGN DATA WRAPPER postgres_fdw + OPTIONS (host 'localhost', port :'master_port', dbname 'regression'); +CREATE USER MAPPING FOR CURRENT_USER + SERVER foreign_server + OPTIONS (user 'postgres'); +CREATE FOREIGN TABLE foreign_table ( + id integer NOT NULL, + data text, + a bigserial +) + SERVER foreign_server + OPTIONS (schema_name 'pg16', table_name 'foreign_table_test'); +-- verify it's a Citus foreign table +SELECT partmethod, repmodel FROM pg_dist_partition +WHERE logicalrelid = 'foreign_table'::regclass ORDER BY logicalrelid; + partmethod | repmodel +--------------------------------------------------------------------- + n | s +(1 row) + +INSERT INTO foreign_table VALUES (2, 'test_2'); +INSERT INTO foreign_table_test VALUES (3, 'test_3'); +CREATE FUNCTION trigger_func() RETURNS trigger LANGUAGE plpgsql AS $$ +BEGIN + RAISE NOTICE 'trigger_func(%) called: action = %, when = %, level = %', + TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL; + RETURN NULL; +END;$$; +CREATE FUNCTION trigger_func_on_shard() RETURNS trigger LANGUAGE plpgsql AS $$ +BEGIN + RAISE NOTICE 'trigger_func_on_shard(%) called: action = %, when = %, level = %', + TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL; + RETURN NULL; +END;$$; +CREATE TRIGGER trig_stmt_before BEFORE TRUNCATE ON foreign_table + FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func(); +SET citus.override_table_visibility TO off; +CREATE TRIGGER trig_stmt_shard_before BEFORE TRUNCATE ON foreign_table_951001 + FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func_on_shard(); +RESET citus.override_table_visibility; +SELECT * FROM foreign_table ORDER BY 1; + id | data | a +--------------------------------------------------------------------- + 1 | text_test | 1 + 2 | test_2 | 1 + 3 | test_3 | 2 +(3 rows) + +TRUNCATE foreign_table; +NOTICE: trigger_func() called: action = TRUNCATE, when = BEFORE, level = STATEMENT +CONTEXT: PL/pgSQL function trigger_func() line XX at RAISE +NOTICE: trigger_func_on_shard() called: action = TRUNCATE, when = BEFORE, level = STATEMENT +CONTEXT: PL/pgSQL function trigger_func_on_shard() line XX at RAISE +SELECT * FROM foreign_table ORDER BY 1; + id | data | a +--------------------------------------------------------------------- +(0 rows) + +RESET citus.use_citus_managed_tables; -- -- COPY FROM ... DEFAULT -- Already supported in Citus, adding all PG tests with a distributed table @@ -678,4 +752,5 @@ SELECT result FROM run_command_on_workers \set VERBOSITY terse SET client_min_messages TO ERROR; +DROP EXTENSION postgres_fdw CASCADE; DROP SCHEMA pg16 CASCADE; diff --git a/src/test/regress/sql/pg16.sql b/src/test/regress/sql/pg16.sql index 1df96e6a7..f5185deab 100644 --- a/src/test/regress/sql/pg16.sql +++ b/src/test/regress/sql/pg16.sql @@ -146,6 +146,63 @@ DROP DATABASE test_db; SELECT result FROM run_command_on_workers ($$DROP DATABASE test_db$$); SET search_path TO pg16; +SET citus.next_shard_id TO 951000; + +-- Foreign table TRUNCATE trigger +-- Relevant PG commit: +-- https://github.com/postgres/postgres/commit/3b00a94 +SELECT 1 FROM citus_add_node('localhost', :master_port, groupid => 0); +SET citus.use_citus_managed_tables TO ON; +CREATE TABLE foreign_table_test (id integer NOT NULL, data text, a bigserial); +INSERT INTO foreign_table_test VALUES (1, 'text_test'); +CREATE EXTENSION postgres_fdw; +CREATE SERVER foreign_server + FOREIGN DATA WRAPPER postgres_fdw + OPTIONS (host 'localhost', port :'master_port', dbname 'regression'); +CREATE USER MAPPING FOR CURRENT_USER + SERVER foreign_server + OPTIONS (user 'postgres'); +CREATE FOREIGN TABLE foreign_table ( + id integer NOT NULL, + data text, + a bigserial +) + SERVER foreign_server + OPTIONS (schema_name 'pg16', table_name 'foreign_table_test'); + +-- verify it's a Citus foreign table +SELECT partmethod, repmodel FROM pg_dist_partition +WHERE logicalrelid = 'foreign_table'::regclass ORDER BY logicalrelid; + +INSERT INTO foreign_table VALUES (2, 'test_2'); +INSERT INTO foreign_table_test VALUES (3, 'test_3'); + +CREATE FUNCTION trigger_func() RETURNS trigger LANGUAGE plpgsql AS $$ +BEGIN + RAISE NOTICE 'trigger_func(%) called: action = %, when = %, level = %', + TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL; + RETURN NULL; +END;$$; + +CREATE FUNCTION trigger_func_on_shard() RETURNS trigger LANGUAGE plpgsql AS $$ +BEGIN + RAISE NOTICE 'trigger_func_on_shard(%) called: action = %, when = %, level = %', + TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL; + RETURN NULL; +END;$$; + +CREATE TRIGGER trig_stmt_before BEFORE TRUNCATE ON foreign_table + FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func(); +SET citus.override_table_visibility TO off; +CREATE TRIGGER trig_stmt_shard_before BEFORE TRUNCATE ON foreign_table_951001 + FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func_on_shard(); +RESET citus.override_table_visibility; + +SELECT * FROM foreign_table ORDER BY 1; +TRUNCATE foreign_table; +SELECT * FROM foreign_table ORDER BY 1; + +RESET citus.use_citus_managed_tables; -- -- COPY FROM ... DEFAULT @@ -390,4 +447,5 @@ SELECT result FROM run_command_on_workers \set VERBOSITY terse SET client_min_messages TO ERROR; +DROP EXTENSION postgres_fdw CASCADE; DROP SCHEMA pg16 CASCADE;