From 8b08d415b3c8837fa7104ce43fda8af58fa25eaf Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 27 Mar 2020 15:01:58 +0100 Subject: [PATCH 1/9] Revert "Fixing a typo in the SQL query" This reverts commit 43b32783f38ea857b235c5b536fe2a080f3a63fa. --- pglogical_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pglogical_rpc.c b/pglogical_rpc.c index f308a03..a770e51 100644 --- a/pglogical_rpc.c +++ b/pglogical_rpc.c @@ -74,7 +74,7 @@ pg_logical_get_remote_repset_tables(PGconn *conn, List *replication_sets) /* PGLogical 2.0+ */ appendStringInfo(&query, "SELECT i.relid, i.nspname, i.relname, i.att_list," - " i.has_row_filter, i.nspname as nsptarget, i.relname as reltarget" + " i.has_row_filter, i.nspname as i.nsptarget, i.relname as i.reltarget" " FROM (SELECT DISTINCT relid FROM pglogical.tables WHERE set_name = ANY(ARRAY[%s])) t," " LATERAL pglogical.show_repset_table_info(t.relid, ARRAY[%s]) i", repsetarr.data, repsetarr.data); From dd8858b6195fb3ca823ae302b9d33e8f9099939b Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 27 Mar 2020 15:03:45 +0100 Subject: [PATCH 2/9] Revert "Use strict-names in pg_dump only starting with 9.6" This reverts commit cb9a7c5dd8022c4a71d5c6a2b6877c660b3eba6d. --- pglogical_sync.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pglogical_sync.c b/pglogical_sync.c index f7fb8d0..149f61b 100644 --- a/pglogical_sync.c +++ b/pglogical_sync.c @@ -144,11 +144,7 @@ dump_structure(PGLogicalSubscription *sub, const char *destfile, } initStringInfo(&command); -#if PG_VERSION_NUM >= 90600 appendStringInfo(&command, "\"%s\" --strict-names --snapshot=\"%s\" %s %s -s -F c -f \"%s\" \"%s\"", -#else - appendStringInfo(&command, "\"%s\" --snapshot=\"%s\" %s %s -s -F c -f \"%s\" \"%s\"", -#endif pg_dump, snapshot, schema_filter.data, table_filter.data, destfile, sub->origin_if->dsn); From 7209e860e350c4e1a5bd21c9c0d861c9016a8f8c Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 27 Mar 2020 16:08:48 +0100 Subject: [PATCH 3/9] Revert "Update protocol of write_rel()" This reverts commit 9538484a944d41c387fdd05974ec017be8d38650. --- Makefile | 2 +- docs/README.md | 24 +- expected/map.out | 659 ------------------------------------ internals-doc/OUTPUT.md | 6 - pglogical--2.2.2--2.3.0.sql | 41 --- pglogical--2.3.0.sql | 16 +- pglogical_executor.c | 54 +-- pglogical_functions.c | 192 ++--------- pglogical_output_plugin.c | 27 +- pglogical_output_proto.h | 3 +- pglogical_proto_native.c | 29 +- pglogical_proto_native.h | 2 +- pglogical_relcache.c | 4 +- pglogical_relcache.h | 5 - pglogical_repset.c | 377 +-------------------- pglogical_repset.h | 33 +- pglogical_rpc.c | 70 ++-- pglogical_rpc.h | 2 +- pglogical_sequences.c | 119 +++---- pglogical_sync.c | 45 ++- sql/map.sql | 264 --------------- 21 files changed, 180 insertions(+), 1794 deletions(-) delete mode 100644 expected/map.out delete mode 100644 sql/map.sql diff --git a/Makefile b/Makefile index 3a82dd2..5fb1549 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ REGRESS = preseed infofuncs init_fail init preseed_check basic extended conflict toasted replication_set add_table relations_only matview bidirectional \ primary_key interfaces foreign_key functions copy triggers parallel row_filter \ row_filter_sampling att_list column_filter apply_delay multiple_upstreams \ - map node_origin_cascade drop + node_origin_cascade drop EXTRA_CLEAN += compat94/pglogical_compat.o compat95/pglogical_compat.o \ compat96/pglogical_compat.o compat10/pglogical_compat.o \ diff --git a/docs/README.md b/docs/README.md index 0698b16..5b83f5f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,7 +22,6 @@ Use cases supported are: * Selective replication of table rows at either publisher or subscriber side (row_filter) * Selective replication of table columns at publisher side * Data gather/merge from multiple upstream servers -* Data gather/merge from multiple upstream tables (distinct names) Architectural details: * pglogical works on a per-database level, not whole server level like @@ -502,7 +501,7 @@ The following functions are provided for managing the replication sets: Parameters: - `set_name` - name of the existing replication set -- `pglogical.replication_set_add_table(set_name name, relation regclass, synchronize_data boolean, columns text[], row_filter text, nsptarget text, reltarget text)` +- `pglogical.replication_set_add_table(set_name name, relation regclass, synchronize_data boolean, columns text[], row_filter text)` Adds a table to replication set. Parameters: @@ -516,8 +515,6 @@ The following functions are provided for managing the replication sets: - `row_filter` - row filtering expression, default NULL (no filtering), see [Row Filtering](#row-filtering) for more info. **WARNING: Use caution when synchronizing data with a valid row filter.** - - `nsptarget` - name of the schema visible to the receiver - - `reltarget` - name of the relation visible to the receiver Using `synchronize_data=true` with a valid `row_filter` is like a one-time operation for a table. Executing it again with modified `row_filter` won't synchronize data to subscriber. Subscribers may need to call `pglogical.alter_subscription_resynchronize_table()` to fix it. @@ -542,15 +539,13 @@ may need to call `pglogical.alter_subscription_resynchronize_table()` to fix it. - `set_name` - name of the existing replication set - `relation` - name or OID of the table to be removed from the set -- `pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean, nsptarget text, reltarget text)` +- `pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean)` Adds a sequence to a replication set. Parameters: - `set_name` - name of the existing replication set - `relation` - name or OID of the sequence to be added to the set - `synchronize_data` - if true, the sequence value will be synchronized immediately, default false - - `nsptarget` - name of the schema visible to the receiver - - `reltarget` - name of the relation visible to the receiver - `pglogical.replication_set_add_all_sequences(set_name name, schema_names text[], synchronize_data boolean)` Adds all sequences from the given schemas. Only existing sequences are added, any sequences that @@ -660,14 +655,6 @@ It is required to mark any such triggers as either `ENABLE REPLICA` or `ENABLE ALWAYS` otherwise they will not be executed by the replication process. -### Table and Sequence renaming - -It is possible to set distinct names for schema and/or relations while adding -them to the replication set on the provider side. This way, the receiver does -not know the original name and it's possible to merge 2 and more tables from the -provider to a single table on the receiver, it also allows to "rename" tables -(and sequence) from one side to the other. - ## Synchronous Replication Synchronous replication is supported using same standard mechanism provided @@ -678,13 +665,6 @@ when `COMMIT` command reports success to client if pglogical subscription name is used in `synchronous_standby_names`. Refer to PostgreSQL documentation for more info about how to configure these two variables. -# Table and Sequence names - -By default, relation and schema name are the same on the receiver and the -provider. However 2 columns are used to track the target names to offer the -user to change them, the receiver does not know about the original names, -only those (mandatory) set for "target". - ## Conflicts In case the node is subscribed to multiple providers, or when local writes diff --git a/expected/map.out b/expected/map.out deleted file mode 100644 index d39525a..0000000 --- a/expected/map.out +++ /dev/null @@ -1,659 +0,0 @@ -SELECT * FROM pglogical_regress_variables() -\gset -/* -Covered cases: - - - 1 table replicated with a distinct name in a distinct schema. Init + DML + resync + TRUNCATE - - 1 table replicated with a distinct name in the same schema. Init + DML + resync + TRUNCATE - - 1 table replicated with the same name in a distinct schema. Init + DML + resync + TRUNCATE - - 1 table replicated with distinct target in 2 distinct sets (a.b -> c.d and a.b -> e.f) - - 2 tables merged from distinct sets - - test resynchronize when multiple origin for the same table (origin indistincts sets - - - Not supported: 2 tables merged in the same set - - Trying to add twice the same table in the same set (with distinct targets): FORBIDEN (XXX should/can we allow ?) -*/ -\c :provider_dsn -CREATE SCHEMA "provider.ping"; -CREATE SCHEMA "provider2.ping2"; -CREATE SCHEMA provsub; -CREATE TABLE "provider.ping".test_origin(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".test_origin(data) VALUES ('a'); -INSERT INTO "provider.ping".test_origin(data) VALUES ('b'); -SELECT * FROM "provider.ping".test_origin ORDER by 1; - id | data -----+------ - 1 | a - 2 | b -(2 rows) - -CREATE TABLE "provider.ping".test_origin2(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".test_origin2(data) VALUES ('y'); -INSERT INTO "provider.ping".test_origin2(data) VALUES ('z'); -SELECT * FROM "provider.ping".test_origin2 ORDER by 1; - id | data -----+------ - 1 | y - 2 | z -(2 rows) - -CREATE TABLE provsub.test_origin3(id serial primary key, data text DEFAULT ''); -INSERT INTO provsub.test_origin3(data) VALUES ('a'); -INSERT INTO provsub.test_origin3(data) VALUES ('b'); -SELECT * FROM provsub.test_origin3 ORDER by 1; - id | data -----+------ - 1 | a - 2 | b -(2 rows) - -CREATE TABLE "provider.ping".provsub(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".provsub(data) VALUES ('a'); -INSERT INTO "provider.ping".provsub(data) VALUES ('b'); -SELECT * FROM "provider.ping".provsub ORDER by 1; - id | data -----+------ - 1 | a - 2 | b -(2 rows) - -CREATE TABLE "provider.ping".bad(id serial primary key, data text DEFAULT ''); -\c :subscriber_dsn -CREATE SCHEMA "subscriber.pong"; -CREATE SCHEMA "subscriber2.pong2"; -CREATE SCHEMA provsub; -CREATE TABLE "subscriber.pong".test_target(id serial primary key, data text DEFAULT ''); -CREATE TABLE "subscriber2.pong2".test_target2(id serial primary key, data text DEFAULT ''); -CREATE TABLE provsub.test_target3(id serial primary key, data text DEFAULT ''); -CREATE TABLE "subscriber.pong".provsub(id serial primary key, data text DEFAULT ''); --- test replication with initial copy --- add table and sequence to the subscribed replication set -\c :provider_dsn -SELECT * FROM pglogical.create_replication_set('map1', - replicate_insert:=true, - replicate_update:=true, - replicate_delete:=true, - replicate_truncate:=true); - create_replication_set ------------------------- - 2047405990 -(1 row) - --- distinct name and schema -SELECT * FROM pglogical.replication_set_add_table('map1', '"provider.ping".test_origin', true, nsptarget:='subscriber.pong', reltarget:='test_target'); - replication_set_add_table ---------------------------- - t -(1 row) - -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('"provider.ping".test_origin', 'id'), nsptarget:='subscriber.pong', reltarget:='test_target_id_seq'); -- XXX not a dynamic name ... - replication_set_add_sequence ------------------------------- - t -(1 row) - --- distinct name, same schema -SELECT * FROM pglogical.replication_set_add_table('map1', 'provsub.test_origin3', true, reltarget:='test_target3'); - replication_set_add_table ---------------------------- - t -(1 row) - -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('provsub.test_origin3', 'id'), reltarget:='test_target3_id_seq'); -- XXX not a dynamic name ... - replication_set_add_sequence ------------------------------- - t -(1 row) - --- same name, distinct schema -SELECT * FROM pglogical.replication_set_add_table('map1', '"provider.ping".provsub', true, nsptarget:='subscriber.pong'); - replication_set_add_table ---------------------------- - t -(1 row) - -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('"provider.ping".provsub', 'id'), nsptarget:='subscriber.pong'); - replication_set_add_sequence ------------------------------- - t -(1 row) - -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); - wait_slot_confirm_lsn ------------------------ - -(1 row) - -SELECT * FROM pglogical.replication_set_seq order by 1,2; - set_id | set_seqoid | set_nsptarget | set_seqtarget -------------+------------------------------------+-----------------+--------------------- - 2047405990 | "provider.ping".test_origin_id_seq | subscriber.pong | test_target_id_seq - 2047405990 | provsub.test_origin3_id_seq | provsub | test_target3_id_seq - 2047405990 | "provider.ping".provsub_id_seq | subscriber.pong | provsub_id_seq -(3 rows) - -SELECT * FROM pglogical.replication_set_table order by 1,2; - set_id | set_reloid | set_att_list | set_row_filter | set_nsptarget | set_reltarget -------------+-----------------------------+--------------+----------------+-----------------+--------------- - 2047405990 | "provider.ping".test_origin | | | subscriber.pong | test_target - 2047405990 | provsub.test_origin3 | | | provsub | test_target3 - 2047405990 | "provider.ping".provsub | | | subscriber.pong | provsub -(3 rows) - -\c :subscriber_dsn --- init -SELECT * FROM pglogical.create_subscription( - subscription_name := 'sub_map1', - provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', - forward_origins := '{}', - replication_sets := '{map1}'); - create_subscription ---------------------- - 2754255463 -(1 row) - -SELECT pglogical.wait_for_subscription_sync_complete('sub_map1'); - wait_for_subscription_sync_complete -------------------------------------- - -(1 row) - -SELECT * FROM "subscriber.pong".test_target; - id | data -----+------ - 1 | a - 2 | b -(2 rows) - -SELECT * FROM provsub.test_target3; - id | data -----+------ - 1 | a - 2 | b -(2 rows) - -SELECT * FROM "subscriber.pong".provsub; - id | data -----+------ - 1 | a - 2 | b -(2 rows) - --- test resynchronize -\c :subscriber_dsn -DELETE FROM "subscriber.pong".test_target WHERE id > 1; -DELETE FROM provsub.test_target3 WHERE id > 1; -DELETE FROM "subscriber.pong".provsub WHERE id > 1; -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map1', '"subscriber.pong".test_target', true); - alter_subscription_resynchronize_table ----------------------------------------- - t -(1 row) - -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map1', 'provsub.test_target3', true); - alter_subscription_resynchronize_table ----------------------------------------- - t -(1 row) - -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map1', '"subscriber.pong".provsub', true); - alter_subscription_resynchronize_table ----------------------------------------- - t -(1 row) - -SELECT pglogical.wait_for_table_sync_complete('sub_map1', '"subscriber.pong".test_target'); - wait_for_table_sync_complete ------------------------------- - -(1 row) - -SELECT pglogical.wait_for_table_sync_complete('sub_map1', 'provsub.test_target3'); - wait_for_table_sync_complete ------------------------------- - -(1 row) - -SELECT pglogical.wait_for_table_sync_complete('sub_map1', '"subscriber.pong".provsub'); - wait_for_table_sync_complete ------------------------------- - -(1 row) - -SELECT * FROM "subscriber.pong".test_target; - id | data -----+------ - 1 | a - 2 | b -(2 rows) - -SELECT * FROM provsub.test_target3; - id | data -----+------ - 1 | a - 2 | b -(2 rows) - -SELECT * FROM "subscriber.pong".provsub; - id | data -----+------ - 1 | a - 2 | b -(2 rows) - --- test synchronize -\c :subscriber_dsn -CREATE TABLE "subscriber.pong".test_synchronize(id serial primary key, data text DEFAULT ''); -\c :provider_dsn -CREATE TABLE "provider.ping".test_synchronize(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".test_synchronize(data) VALUES ('a'); -SELECT * FROM pglogical.replication_set_add_table('map1', '"provider.ping".test_synchronize', true, nsptarget:='subscriber.pong'); - replication_set_add_table ---------------------------- - t -(1 row) - -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('"provider.ping".test_synchronize', 'id'), nsptarget:='subscriber.pong'); -- XXX not a dynamic name ... - replication_set_add_sequence ------------------------------- - t -(1 row) - -\c :subscriber_dsn -SELECT * FROM pglogical.alter_subscription_synchronize('sub_map1'); - alter_subscription_synchronize --------------------------------- - t -(1 row) - -SELECT pglogical.wait_for_table_sync_complete('sub_map1', '"subscriber.pong".test_synchronize'); - wait_for_table_sync_complete ------------------------------- - -(1 row) - -SELECT * FROM "subscriber.pong".test_synchronize; - id | data -----+------ - 1 | a -(1 row) - --- test DML replication after init -\c :provider_dsn -INSERT INTO "provider.ping".test_origin(data) VALUES ('c'); -INSERT INTO "provider.ping".test_origin(data) VALUES ('d'); -UPDATE "provider.ping".test_origin SET data = 'data'; -DELETE FROM "provider.ping".test_origin WHERE id < 3; -INSERT INTO provsub.test_origin3(data) VALUES ('c'); -INSERT INTO provsub.test_origin3(data) VALUES ('d'); -UPDATE provsub.test_origin3 SET data = 'data'; -DELETE FROM provsub.test_origin3 WHERE id < 3; -INSERT INTO "provider.ping".provsub(data) VALUES ('c'); -INSERT INTO "provider.ping".provsub(data) VALUES ('d'); -UPDATE "provider.ping".provsub SET data = 'data'; -DELETE FROM "provider.ping".provsub WHERE id < 3; -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); - wait_slot_confirm_lsn ------------------------ - -(1 row) - -\c :subscriber_dsn -SELECT * FROM "subscriber.pong".test_target; - id | data -----+------ - 3 | data - 4 | data -(2 rows) - -SELECT * FROM provsub.test_target3; - id | data -----+------ - 3 | data - 4 | data -(2 rows) - -SELECT * FROM "subscriber.pong".provsub; - id | data -----+------ - 3 | data - 4 | data -(2 rows) - --- truncate -\c :provider_dsn -TRUNCATE "provider.ping".test_origin; -TRUNCATE provsub.test_origin3; -TRUNCATE "provider.ping".provsub; -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); - wait_slot_confirm_lsn ------------------------ - -(1 row) - -\c :subscriber_dsn -SELECT * FROM "subscriber.pong".test_target; - id | data -----+------ -(0 rows) - -SELECT * FROM provsub.test_target3; - id | data -----+------ -(0 rows) - -SELECT * FROM "subscriber.pong".provsub; - id | data -----+------ -(0 rows) - --- Merging tables --- test merge data from 2 tables into 1 in distinct sets -\c :subscriber_dsn -CREATE TABLE "subscriber.pong".test_merge(id serial primary key, data text DEFAULT ''); -\c :provider_dsn -CREATE TABLE "provider.ping".test_merge(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".test_merge(id,data) VALUES (9, 'm'); -INSERT INTO "provider.ping".test_origin(data) VALUES ('n'); -SELECT * FROM "provider.ping".test_merge ORDER by 1; - id | data -----+------ - 9 | m -(1 row) - -SELECT * FROM "provider.ping".test_origin ORDER by 1; - id | data -----+------ - 5 | n -(1 row) - -SELECT * FROM pglogical.create_replication_set('map2', - replicate_insert:=true, - replicate_update:=true, - replicate_delete:=true, - replicate_truncate:=true); - create_replication_set ------------------------- - 1072520286 -(1 row) - -SELECT * FROM pglogical.replication_set_add_table('map2', '"provider.ping".test_merge', true, nsptarget:='subscriber.pong', reltarget:='test_target'); - replication_set_add_table ---------------------------- - t -(1 row) - -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); - wait_slot_confirm_lsn ------------------------ - -(1 row) - -\c :subscriber_dsn -SELECT * FROM "subscriber.pong".test_target; - id | data -----+------ - 5 | n -(1 row) - -SELECT * FROM pglogical.create_subscription( - subscription_name := 'sub_map2', - provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', - forward_origins := '{}', - replication_sets := '{map2}'); - create_subscription ---------------------- - 4241919301 -(1 row) - -SELECT pglogical.wait_for_subscription_sync_complete('sub_map2'); - wait_for_subscription_sync_complete -------------------------------------- - -(1 row) - -SELECT * FROM "subscriber.pong".test_target; - id | data -----+------ - 5 | n - 9 | m -(2 rows) - -TRUNCATE "subscriber.pong".test_target; --- test resynchronize when multiple origin for the same table (origin indistincts sets -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map1', '"subscriber.pong".test_target', true); - alter_subscription_resynchronize_table ----------------------------------------- - t -(1 row) - -SELECT pglogical.wait_for_table_sync_complete('sub_map1', '"subscriber.pong".test_target'); - wait_for_table_sync_complete ------------------------------- - -(1 row) - -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map2', '"subscriber.pong".test_target', false); - alter_subscription_resynchronize_table ----------------------------------------- - t -(1 row) - -SELECT pglogical.wait_for_table_sync_complete('sub_map2', '"subscriber.pong".test_target'); - wait_for_table_sync_complete ------------------------------- - -(1 row) - -SELECT * FROM "subscriber.pong".test_target; - id | data -----+------ - 5 | n - 9 | m -(2 rows) - --- Splitting --- 1 table replicated with distinct target in 2 distinct sets (a.b -> c.d and a.b -> e.f) -\c :provider_dsn -SELECT * FROM pglogical.replication_set_add_table('map2', '"provider.ping".test_origin', true, nsptarget:='subscriber2.pong2', reltarget:='test_target2'); - replication_set_add_table ---------------------------- - t -(1 row) - -SELECT * FROM pglogical.replication_set_add_sequence('map2', pg_get_serial_sequence('"provider.ping".test_origin', 'id'), nsptarget:='subscriber2.pong2', reltarget:='test_target2_id_seq'); -- XXX not a dynamic name ... - replication_set_add_sequence ------------------------------- - t -(1 row) - -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); - wait_slot_confirm_lsn ------------------------ - -(1 row) - -\c :subscriber_dsn -SELECT pglogical.wait_for_subscription_sync_complete('sub_map2'); - wait_for_subscription_sync_complete -------------------------------------- - -(1 row) - -SELECT * FROM "subscriber2.pong2".test_target2; - id | data -----+------ - 5 | n -(1 row) - --- Not supported cases: --- test merging 2 sequences to the same target: not allowed ! -\c :provider_dsn --- same set -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('"provider.ping".bad', 'id'), nsptarget:='subscriber.pong', reltarget:='test_target_id_seq'); -- XXX not a dynamic name ... -ERROR: Sequence subscriber.pong.test_target_id_seq already replicated from provider.ping.bad_id_seq, cannot add another source --- distinct set -SELECT * FROM pglogical.replication_set_add_sequence('map2', pg_get_serial_sequence('"provider.ping".bad', 'id'), nsptarget:='subscriber.pong', reltarget:='test_target_id_seq'); -- XXX not a dynamic name ... -ERROR: Sequence subscriber.pong.test_target_id_seq already replicated from provider.ping.bad_id_seq, cannot add another source -DROP TABLE "provider.ping".bad; --- Merging tables --- test merge data from 2 tables into 1 in the same set: not allowed -\c :provider_dsn -SELECT * FROM pglogical.replication_set_add_table('map1', '"provider.ping".test_origin2', true, nsptarget:='subscriber.pong', reltarget:='test_target'); -ERROR: Table subscriber.pong.test_target already replicated from provider.ping.test_origin2 in the same set, cannot add another source --- XXX copy test required ? --- synchronize sequences -\c :provider_dsn -SELECT pglogical.synchronize_sequence('"provider.ping".test_origin_id_seq'); - synchronize_sequence ----------------------- - t -(1 row) - -SELECT pglogical.synchronize_sequence('provsub.test_origin3_id_seq'); - synchronize_sequence ----------------------- - t -(1 row) - -SELECT pglogical.synchronize_sequence('"provider.ping".provsub_id_seq'); - synchronize_sequence ----------------------- - t -(1 row) - -SELECT pglogical.synchronize_sequence('"provider.ping".test_synchronize_id_seq'); - synchronize_sequence ----------------------- - t -(1 row) - -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); - wait_slot_confirm_lsn ------------------------ - -(1 row) - -\c :subscriber_dsn -SELECT N.nspname AS schemaname, C.relname AS tablename, (nextval(C.oid) > 1000) as synced - FROM pg_class C JOIN pg_namespace N ON (N.oid = C.relnamespace) - WHERE C.relkind = 'S' AND C.relname IN ('test_target_id_seq', 'test_target2_id_seq', 'test_target3_id_seq' - ,'provsub_id_seq', 'test_synchronize_id_seq') - ORDER BY 1, 2; - schemaname | tablename | synced --------------------+-------------------------+-------- - provsub | test_target3_id_seq | t - subscriber.pong | provsub_id_seq | t - subscriber.pong | test_synchronize_id_seq | t - subscriber.pong | test_target_id_seq | t - subscriber2.pong2 | test_target2_id_seq | t -(5 rows) - --- show and cleaning -\c :subscriber_dsn -SELECT * FROM pglogical.show_subscription_status('sub_map1'); - subscription_name | status | provider_node | provider_dsn | slot_name | replication_sets | forward_origins --------------------+-------------+---------------+------------------------------+-------------------------------------+------------------+----------------- - sub_map1 | replicating | test_provider | dbname=regression user=super | pgl_postgres_test_provider_sub_map1 | {map1} | -(1 row) - -SELECT * FROM pglogical.show_subscription_table('sub_map1','"subscriber.pong".test_target'); - nspname | relname | status ------------------+-------------+------------- - subscriber.pong | test_target | replicating -(1 row) - ---- XXX add more here -SELECT * FROM pglogical.show_subscription_status('sub_map2'); - subscription_name | status | provider_node | provider_dsn | slot_name | replication_sets | forward_origins --------------------+-------------+---------------+------------------------------+-------------------------------------+------------------+----------------- - sub_map2 | replicating | test_provider | dbname=regression user=super | pgl_postgres_test_provider_sub_map2 | {map2} | -(1 row) - -SELECT * FROM pglogical.drop_subscription('sub_map1'); - drop_subscription -------------------- - 1 -(1 row) - -SELECT * FROM pglogical.drop_subscription('sub_map2'); - drop_subscription -------------------- - 1 -(1 row) - -\c :provider_dsn -SELECT nspname, relname, att_list, has_row_filter, nsptarget, reltarget -FROM pglogical.show_repset_table_info_by_target('subscriber.pong','test_target', ARRAY['map1','map2']) order by 1,2; - nspname | relname | att_list | has_row_filter | nsptarget | reltarget ----------------+-------------+-----------+----------------+-----------------+------------- - provider.ping | test_merge | {id,data} | f | subscriber.pong | test_target - provider.ping | test_origin | {id,data} | f | subscriber.pong | test_target -(2 rows) - --- XXX fonction pglogical.table_data_filtered(anyelement,regclass,text[]) ? -SELECT * FROM pglogical.replication_set_seq order by 1,2; - set_id | set_seqoid | set_nsptarget | set_seqtarget -------------+-----------------------------------------+-------------------+------------------------- - 1072520286 | "provider.ping".test_origin_id_seq | subscriber2.pong2 | test_target2_id_seq - 2047405990 | "provider.ping".test_origin_id_seq | subscriber.pong | test_target_id_seq - 2047405990 | provsub.test_origin3_id_seq | provsub | test_target3_id_seq - 2047405990 | "provider.ping".provsub_id_seq | subscriber.pong | provsub_id_seq - 2047405990 | "provider.ping".test_synchronize_id_seq | subscriber.pong | test_synchronize_id_seq -(5 rows) - -SELECT * FROM pglogical.replication_set_table order by 1,2; - set_id | set_reloid | set_att_list | set_row_filter | set_nsptarget | set_reltarget -------------+----------------------------------+--------------+----------------+-------------------+------------------ - 1072520286 | "provider.ping".test_origin | | | subscriber2.pong2 | test_target2 - 1072520286 | "provider.ping".test_merge | | | subscriber.pong | test_target - 2047405990 | "provider.ping".test_origin | | | subscriber.pong | test_target - 2047405990 | provsub.test_origin3 | | | provsub | test_target3 - 2047405990 | "provider.ping".provsub | | | subscriber.pong | provsub - 2047405990 | "provider.ping".test_synchronize | | | subscriber.pong | test_synchronize -(6 rows) - -SELECT cache_size,last_value FROM pglogical.sequence_state; - cache_size | last_value -------------+------------ - 1000 | 1005 - 1000 | 1004 - 1000 | 1004 - 1000 | 1001 -(4 rows) - -SELECT * FROM pglogical.drop_replication_set('map1'); - drop_replication_set ----------------------- - t -(1 row) - -SELECT * FROM pglogical.drop_replication_set('map2'); - drop_replication_set ----------------------- - t -(1 row) - -DROP SCHEMA "provider.ping" CASCADE; -NOTICE: drop cascades to 5 other objects -DETAIL: drop cascades to table "provider.ping".test_origin -drop cascades to table "provider.ping".test_origin2 -drop cascades to table "provider.ping".provsub -drop cascades to table "provider.ping".test_synchronize -drop cascades to table "provider.ping".test_merge -DROP SCHEMA "provider2.ping2" CASCADE; -DROP SCHEMA provsub CASCADE; -NOTICE: drop cascades to table provsub.test_origin3 -\c :subscriber_dsn -DROP SCHEMA "subscriber.pong" CASCADE; -NOTICE: drop cascades to 4 other objects -DETAIL: drop cascades to table "subscriber.pong".test_target -drop cascades to table "subscriber.pong".provsub -drop cascades to table "subscriber.pong".test_synchronize -drop cascades to table "subscriber.pong".test_merge -DROP SCHEMA "subscriber2.pong2" CASCADE; -NOTICE: drop cascades to table "subscriber2.pong2".test_target2 -DROP SCHEMA provsub CASCADE; -NOTICE: drop cascades to table provsub.test_target3 diff --git a/internals-doc/OUTPUT.md b/internals-doc/OUTPUT.md index 5ddb92d..4000921 100644 --- a/internals-doc/OUTPUT.md +++ b/internals-doc/OUTPUT.md @@ -271,12 +271,6 @@ case is bi-directional (mutual) replication. By specifying a row filter hook it's possible to filter the replication stream server-side so that only a subset of changes is replicated. -# Table and Sequence names - -By default, relation and schema name are the same on the receiver and the -provider. However 2 columns are used to track the target names to offer the -user to change them, the receiver does not know about the original names, -only those (mandatory) set for "target". # Hooks diff --git a/pglogical--2.2.2--2.3.0.sql b/pglogical--2.2.2--2.3.0.sql index e65808f..b6f02fd 100644 --- a/pglogical--2.2.2--2.3.0.sql +++ b/pglogical--2.2.2--2.3.0.sql @@ -9,44 +9,3 @@ RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_create_s DROP FUNCTION pglogical.create_subscription(subscription_name name, provider_dsn text, replication_sets text[], synchronize_structure boolean, synchronize_data boolean, forward_origins text[], apply_delay interval); - -ALTER TABLE pglogical.replication_set_table - ADD COLUMN set_nsptarget name NOT NULL - , ADD COLUMN set_reltarget name NOT NULL; -ALTER TABLE pglogical.replication_set_seq - ADD COLUMN set_nsptarget name NOT NULL - , ADD COLUMN set_seqtarget name NOT NULL; -DROP FUNCTION pglogical.show_repset_table_info(regclass, text[]); -CREATE FUNCTION pglogical.show_repset_table_info(relation regclass, repsets text[], OUT relid oid, OUT nspname text, - OUT relname text, OUT att_list text[], OUT has_row_filter boolean, OUT nsptarget text, OUT reltarget text) -RETURNS record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info'; - -CREATE FUNCTION pglogical.show_repset_table_info_by_target(nsptarget name, reltarget name, repsets text[], OUT relid oid, OUT nspname text, - OUT relname text, OUT att_list text[], OUT has_row_filter boolean, OUT nsptarget text, OUT reltarget text) -RETURNS SETOF record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info_by_target'; - -UPDATE pglogical.replication_set_table - SET set_nsptarget = n.nspname - , set_reltarget = c.relname -FROM pg_class c - JOIN pg_namespace n ON n.oid = c.relnamespace -WHERE c.oid = set_reloid; - -UPDATE pglogical.replication_set_seq - SET set_nsptarget = n.nspname - , set_seqtarget = c.relname -FROM pg_class c - JOIN pg_namespace n ON n.oid = c.relnamespace -WHERE c.oid = set_seqoid; - --- a VACUUM FULL of the table above would be nice here. - -DROP FUNCTION pglogical.replication_set_add_table(name, regclass, boolean, - text[], text); -CREATE FUNCTION pglogical.replication_set_add_table(set_name name, relation regclass, synchronize_data boolean DEFAULT false, - columns text[] DEFAULT NULL, row_filter text DEFAULT NULL, nsptarget name DEFAULT NULL, reltarget name DEFAULT NULL) -RETURNS boolean CALLED ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_table'; - -DROP FUNCTION pglogical.replication_set_add_sequence(name, regclass, boolean); -CREATE FUNCTION pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean DEFAULT false, nsptarget name DEFAULT NULL, reltarget name DEFAULT NULL) -RETURNS boolean VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_sequence'; diff --git a/pglogical--2.3.0.sql b/pglogical--2.3.0.sql index 5ef62fa..52c1dbe 100644 --- a/pglogical--2.3.0.sql +++ b/pglogical--2.3.0.sql @@ -97,16 +97,12 @@ CREATE TABLE pglogical.replication_set_table ( set_reloid regclass NOT NULL, set_att_list text[], set_row_filter pg_node_tree, - set_nsptarget name NOT NULL, - set_reltarget name NOT NULL, PRIMARY KEY(set_id, set_reloid) ) WITH (user_catalog_table=true); CREATE TABLE pglogical.replication_set_seq ( set_id oid NOT NULL, set_seqoid regclass NOT NULL, - set_nsptarget name NOT NULL, - set_seqtarget name NOT NULL, PRIMARY KEY(set_id, set_seqoid) ) WITH (user_catalog_table=true); @@ -172,15 +168,15 @@ CREATE FUNCTION pglogical.drop_replication_set(set_name name, ifexists boolean D RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_drop_replication_set'; CREATE FUNCTION pglogical.replication_set_add_table(set_name name, relation regclass, synchronize_data boolean DEFAULT false, - columns text[] DEFAULT NULL, row_filter text DEFAULT NULL, nsptarget name DEFAULT NULL, reltarget name DEFAULT NULL) + columns text[] DEFAULT NULL, row_filter text DEFAULT NULL) RETURNS boolean CALLED ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_table'; CREATE FUNCTION pglogical.replication_set_add_all_tables(set_name name, schema_names text[], synchronize_data boolean DEFAULT false) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_all_tables'; CREATE FUNCTION pglogical.replication_set_remove_table(set_name name, relation regclass) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_remove_table'; -CREATE FUNCTION pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean DEFAULT false, nsptarget name DEFAULT NULL, reltarget name DEFAULT NULL) -RETURNS boolean VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_sequence'; +CREATE FUNCTION pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean DEFAULT false) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_sequence'; CREATE FUNCTION pglogical.replication_set_add_all_sequences(set_name name, schema_names text[], synchronize_data boolean DEFAULT false) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_all_sequences'; CREATE FUNCTION pglogical.replication_set_remove_sequence(set_name name, relation regclass) @@ -200,13 +196,9 @@ CREATE FUNCTION pglogical.table_data_filtered(reltyp anyelement, relation regcla RETURNS SETOF anyelement CALLED ON NULL INPUT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_table_data_filtered'; CREATE FUNCTION pglogical.show_repset_table_info(relation regclass, repsets text[], OUT relid oid, OUT nspname text, - OUT relname text, OUT att_list text[], OUT has_row_filter boolean, OUT nsptarget text, OUT reltarget text) + OUT relname text, OUT att_list text[], OUT has_row_filter boolean) RETURNS record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info'; -CREATE FUNCTION pglogical.show_repset_table_info_by_target(nsptarget name, reltarget name, repsets text[], OUT relid oid, OUT nspname text, - OUT relname text, OUT att_list text[], OUT has_row_filter boolean, OUT nsptarget text, OUT reltarget text) -RETURNS SETOF record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info_by_target'; - CREATE FUNCTION pglogical.show_subscription_table(subscription_name name, relation regclass, OUT nspname text, OUT relname text, OUT status text) RETURNS record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_subscription_table'; diff --git a/pglogical_executor.c b/pglogical_executor.c index 6d10943..0205905 100644 --- a/pglogical_executor.c +++ b/pglogical_executor.c @@ -197,33 +197,35 @@ pglogical_finish_truncate(void) foreach (tlc, pglogical_truncated_tables) { Oid reloid = lfirst_oid(tlc); - List *reltargets; - ListCell *lc; - - /* And now prepare the messages for the queue */ - reltargets = get_table_replication_sets_targets(local_node->node->id, reloid); - - /* - * Compute a message for each unique (reloid,nsptarget,reltarget) triplet - */ - foreach (lc, reltargets) + char *nspname; + char *relname; + List *repsets; + StringInfoData json; + + /* Format the query. */ + nspname = get_namespace_name(get_rel_namespace(reloid)); + relname = get_rel_name(reloid); + + /* It's easier to construct json manually than via Jsonb API... */ + initStringInfo(&json); + appendStringInfo(&json, "{\"schema_name\": "); + escape_json(&json, nspname); + appendStringInfo(&json, ",\"table_name\": "); + escape_json(&json, relname); + appendStringInfo(&json, "}"); + + repsets = get_table_replication_sets(local_node->node->id, reloid); + + if (list_length(repsets)) { - StringInfoData json; - List *repset_names = NIL; - char *nspname; - char *relname; - PGLogicalRepSetRel *t = (PGLogicalRepSetRel *) lfirst(lc); - - nspname = pstrdup(t->nsptarget); - relname = pstrdup(t->reltarget); - repset_names = lappend(repset_names, t->repset_name); - - initStringInfo(&json); - appendStringInfoString(&json, "{\"schema_name\": "); - escape_json(&json, nspname); - appendStringInfoString(&json, ",\"table_name\": "); - escape_json(&json, relname); - appendStringInfo(&json, "}"); + List *repset_names = NIL; + ListCell *rlc; + + foreach (rlc, repsets) + { + PGLogicalRepSet *repset = (PGLogicalRepSet *) lfirst(rlc); + repset_names = lappend(repset_names, pstrdup(repset->name)); + } /* Queue the truncate for replication. */ queue_message(repset_names, GetUserId(), diff --git a/pglogical_functions.c b/pglogical_functions.c index 0534f32..dce3485 100644 --- a/pglogical_functions.c +++ b/pglogical_functions.c @@ -133,7 +133,6 @@ PG_FUNCTION_INFO_V1(pglogical_dependency_check_trigger); PG_FUNCTION_INFO_V1(pglogical_gen_slot_name); PG_FUNCTION_INFO_V1(pglogical_node_info); PG_FUNCTION_INFO_V1(pglogical_show_repset_table_info); -PG_FUNCTION_INFO_V1(pglogical_show_repset_table_info_by_target); PG_FUNCTION_INFO_V1(pglogical_table_data_filtered); /* Information */ @@ -834,8 +833,8 @@ pglogical_alter_subscription_synchronize(PG_FUNCTION_ARGS) /* We might delete the cell so advance it now. */ next = lnext(llc); - if (namestrcmp(&tablesync->nspname, remoterel->nsptarget) == 0 && - namestrcmp(&tablesync->relname, remoterel->reltarget) == 0) + if (namestrcmp(&tablesync->nspname, remoterel->nspname) == 0 && + namestrcmp(&tablesync->relname, remoterel->relname) == 0) { oldsync = tablesync; local_tables = list_delete_cell(local_tables, llc, prev); @@ -852,13 +851,13 @@ pglogical_alter_subscription_synchronize(PG_FUNCTION_ARGS) memset(&newsync, 0, sizeof(PGLogicalSyncStatus)); newsync.kind = SYNC_KIND_DATA; newsync.subid = sub->id; - namestrcpy(&newsync.nspname, remoterel->nsptarget); - namestrcpy(&newsync.relname, remoterel->reltarget); + namestrcpy(&newsync.nspname, remoterel->nspname); + namestrcpy(&newsync.relname, remoterel->relname); newsync.status = SYNC_STATUS_INIT; create_local_sync_status(&newsync); if (truncate) - truncate_table(remoterel->nsptarget, remoterel->reltarget); + truncate_table(remoterel->nspname, remoterel->relname); } } @@ -1384,8 +1383,6 @@ pglogical_replication_set_add_table(PG_FUNCTION_ARGS) PGLogicalLocalNode *node; char *nspname; char *relname; - char *nsptarget; - char *reltarget; StringInfoData json; /* Proccess for required parameters. */ @@ -1463,26 +1460,16 @@ pglogical_replication_set_add_table(PG_FUNCTION_ARGS) text_to_cstring(PG_GETARG_TEXT_PP(4))); } - if (!PG_ARGISNULL(5)) - nsptarget = NameStr(*PG_GETARG_NAME(5)); - else - nsptarget = pstrdup(nspname); - if (!PG_ARGISNULL(6)) - reltarget = NameStr(*PG_GETARG_NAME(6)); - else - reltarget = pstrdup(relname); - - replication_set_add_table(repset->id, reloid, att_list, row_filter, - nsptarget, reltarget); + replication_set_add_table(repset->id, reloid, att_list, row_filter); if (synchronize) { /* It's easier to construct json manually than via Jsonb API... */ initStringInfo(&json); appendStringInfo(&json, "{\"schema_name\": "); - escape_json(&json, nsptarget); + escape_json(&json, nspname); appendStringInfo(&json, ",\"table_name\": "); - escape_json(&json, reltarget); + escape_json(&json, relname); appendStringInfo(&json, "}"); /* Queue the synchronize request for replication. */ queue_message(list_make1(repset->name), GetUserId(), @@ -1490,7 +1477,7 @@ pglogical_replication_set_add_table(PG_FUNCTION_ARGS) } /* Cleanup. */ - table_close(rel, ShareRowExclusiveLock); + table_close(rel, NoLock); PG_RETURN_BOOL(true); } @@ -1509,8 +1496,6 @@ pglogical_replication_set_add_sequence(PG_FUNCTION_ARGS) PGLogicalLocalNode *node; char *nspname; char *relname; - char *nsptarget; - char *reltarget; StringInfoData json; node = check_local_node(true); @@ -1525,27 +1510,19 @@ pglogical_replication_set_add_sequence(PG_FUNCTION_ARGS) */ rel = table_open(reloid, ShareRowExclusiveLock); - nspname = get_namespace_name(RelationGetNamespace(rel)); - relname = RelationGetRelationName(rel); - if (!PG_ARGISNULL(3)) - nsptarget = NameStr(*PG_GETARG_NAME(3)); - else - nsptarget = pstrdup(nspname); - if (!PG_ARGISNULL(4)) - reltarget = NameStr(*PG_GETARG_NAME(4)); - else - reltarget = pstrdup(relname); - - replication_set_add_seq(repset->id, reloid, nsptarget, reltarget); + replication_set_add_seq(repset->id, reloid); if (synchronize) { + nspname = get_namespace_name(RelationGetNamespace(rel)); + relname = RelationGetRelationName(rel); + /* It's easier to construct json manually than via Jsonb API... */ initStringInfo(&json); appendStringInfo(&json, "{\"schema_name\": "); - escape_json(&json, nsptarget); + escape_json(&json, nspname); appendStringInfo(&json, ",\"sequence_name\": "); - escape_json(&json, reltarget); + escape_json(&json, relname); appendStringInfo(&json, ",\"last_value\": \""INT64_FORMAT"\"", sequence_get_last_value(reloid)); appendStringInfo(&json, "}"); @@ -1620,11 +1597,9 @@ pglogical_replication_set_add_all_relations(Name repset_name, if (!list_member_oid(existing_relations, reloid)) { if (relkind == RELKIND_RELATION) - replication_set_add_table(repset->id, reloid, NIL, NULL, - NULL, NULL); + replication_set_add_table(repset->id, reloid, NIL, NULL); else - replication_set_add_seq(repset->id, reloid, - NULL, NULL); + replication_set_add_seq(repset->id, reloid); if (synchronize) { @@ -1933,26 +1908,20 @@ pglogical_node_info(PG_FUNCTION_ARGS) * This is called by downstream sync worker on the upstream to obtain * info needed to do initial synchronization correctly. Be careful * about changing it, as it must be upward- and downward-compatible. - * - * it's not used starting with pglogical 2.3 (and can be remove if we drop - * support to pre-2.3 in the future. - * - * It will return only tables with same name and schema on subscriber and - * provider */ Datum pglogical_show_repset_table_info(PG_FUNCTION_ARGS) { Oid reloid = PG_GETARG_OID(0); - ArrayType *rep_set_names = PG_GETARG_ARRAYTYPE_P(1); + ArrayType *rep_set_names = PG_GETARG_ARRAYTYPE_P(1); Relation rel; List *replication_sets; TupleDesc reldesc; TupleDesc rettupdesc; int i; List *att_list = NIL; - Datum values[7]; - bool nulls[7]; + Datum values[5]; + bool nulls[5]; char *nspname; char *relname; HeapTuple htup; @@ -1978,7 +1947,7 @@ pglogical_show_repset_table_info(PG_FUNCTION_ARGS) /* Build the replication info for the table. */ tableinfo = get_table_replication_info(node->node->id, rel, - replication_sets); + replication_sets); /* Build the column list. */ for (i = 0; i < reldesc->natts; i++) @@ -2005,8 +1974,6 @@ pglogical_show_repset_table_info(PG_FUNCTION_ARGS) values[2] = CStringGetTextDatum(relname); values[3] = PointerGetDatum(strlist_to_textarray(att_list)); values[4] = BoolGetDatum(list_length(tableinfo->row_filter) > 0); - values[5] = CStringGetTextDatum(tableinfo->nsptarget); - values[6] = CStringGetTextDatum(tableinfo->reltarget); htup = heap_form_tuple(rettupdesc, values, nulls); @@ -2015,123 +1982,6 @@ pglogical_show_repset_table_info(PG_FUNCTION_ARGS) PG_RETURN_DATUM(HeapTupleGetDatum(htup)); } -/* - * Get replication info about table, by target name - * - * This is called by downstream sync worker on the upstream to obtain - * info needed to do initial synchronization correctly. Be careful - * about changing it, as it must be upward- and downward-compatible. - */ -Datum -pglogical_show_repset_table_info_by_target(PG_FUNCTION_ARGS) -{ - ArrayType *rep_set_names = PG_GETARG_ARRAYTYPE_P(2); - RangeVar *target; - char *nsptarget; - char *reltarget; - Relation rel; - List *replication_sets; - TupleDesc reldesc; - int i; - Datum values[7]; - bool nulls[7]; - char *nspname; - char *relname; - PGLogicalLocalNode *node; - List *tablesinfo = NIL; - ListCell *lc; - ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - - if (PG_ARGISNULL(0)) - elog(ERROR,"Schema target name required"); - nsptarget = NameStr(*PG_GETARG_NAME(0)); - if (PG_ARGISNULL(1)) - elog(ERROR,"Table target name required"); - reltarget = NameStr(*PG_GETARG_NAME(1)); - - node = get_local_node(false, false); - - target = makeRangeVar(nsptarget, reltarget, -1); - - replication_sets = textarray_to_list(rep_set_names); - replication_sets = get_replication_sets(node->node->id, - replication_sets, - false); - - /* Build the replication info for the table. */ - tablesinfo = get_table_replication_info_by_target(node->node->id, - target->schemaname, - target->relname, - replication_sets); - - /* Switch into long-lived context to construct returned data structures */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - /* Build a tuple descriptor for our result type */ - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - elog(ERROR, "return type must be a row type"); - tupdesc = BlessTupleDesc(tupdesc); - - tupstore = tuplestore_begin_heap(true, false, work_mem); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); - - foreach (lc, tablesinfo) - { - List *att_list = NIL; - PGLogicalTableRepInfo *tableinfo = (PGLogicalTableRepInfo *) lfirst(lc); - - rel = table_open(tableinfo->reloid, AccessShareLock); - reldesc = RelationGetDescr(rel); - - nspname = get_namespace_name(RelationGetNamespace(rel)); - relname = RelationGetRelationName(rel); - - /* Build the column list. */ - for (i = 0; i < reldesc->natts; i++) - { - Form_pg_attribute att = TupleDescAttr(reldesc,i); - - /* Skip dropped columns. */ - if (att->attisdropped) - continue; - - /* Skip filtered columns if any. */ - if (tableinfo->att_list && - !bms_is_member(att->attnum - FirstLowInvalidHeapAttributeNumber, - tableinfo->att_list)) - continue; - - att_list = lappend(att_list, NameStr(att->attname)); - } - - /* And now build the result. */ - memset(nulls, false, sizeof(nulls)); - values[0] = ObjectIdGetDatum(RelationGetRelid(rel)); - values[1] = CStringGetTextDatum(nspname); - values[2] = CStringGetTextDatum(relname); - values[3] = PointerGetDatum(strlist_to_textarray(att_list)); - values[4] = BoolGetDatum(list_length(tableinfo->row_filter) > 0); - values[5] = CStringGetTextDatum(tableinfo->nsptarget); - values[6] = CStringGetTextDatum(tableinfo->reltarget); - - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - table_close(rel, NoLock); - } - - // XXX not required - tuplestore_donestoring(tupstore); - - PG_RETURN_VOID(); -} /* * Decide if to return tuple or not. diff --git a/pglogical_output_plugin.c b/pglogical_output_plugin.c index 2da772a..11fa818 100644 --- a/pglogical_output_plugin.c +++ b/pglogical_output_plugin.c @@ -26,7 +26,6 @@ #include "storage/fd.h" #include "storage/lmgr.h" #include "utils/inval.h" -#include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/rel.h" #include "replication/origin.h" @@ -681,34 +680,10 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, if (!cached_relmeta->is_cached) { - PGLogicalTableRepInfo *tblinfo; - char *nsptarget; - char *reltarget; - - if (RelationGetRelid(relation) == get_queue_table_oid() - || RelationGetRelid(relation) == get_replication_set_rel_oid()) - { - nsptarget = get_namespace_name(RelationGetNamespace(relation)); - reltarget = pstrdup(RelationGetRelationName(relation)); - if (nsptarget == NULL) - elog(ERROR, "cache lookup failed for namespace %u", - relation->rd_rel->relnamespace); - } - else - { - tblinfo = get_table_replication_info(data->local_node_id, relation, - data->replication_sets); - nsptarget = pstrdup(tblinfo->nsptarget); - reltarget = pstrdup(tblinfo->reltarget); - } - OutputPluginPrepareWrite(ctx, false); - data->api->write_rel(ctx->out, data, relation, att_list, - nsptarget, reltarget); + data->api->write_rel(ctx->out, data, relation, att_list); OutputPluginWrite(ctx, false); cached_relmeta->is_cached = true; - pfree(nsptarget); - pfree(reltarget); } } diff --git a/pglogical_output_proto.h b/pglogical_output_proto.h index 0a3ce54..173d662 100644 --- a/pglogical_output_proto.h +++ b/pglogical_output_proto.h @@ -57,8 +57,7 @@ typedef enum PGLogicalProtoType } PGLogicalProtoType; typedef void (*pglogical_write_rel_fn) (StringInfo out, PGLogicalOutputData * data, - Relation rel, Bitmapset *att_list, - const char *nsptarget, const char *reltarget); + Relation rel, Bitmapset *att_list); typedef void (*pglogical_write_begin_fn) (StringInfo out, PGLogicalOutputData * data, ReorderBufferTXN *txn); diff --git a/pglogical_proto_native.c b/pglogical_proto_native.c index 8e6c578..2b4c5a9 100644 --- a/pglogical_proto_native.c +++ b/pglogical_proto_native.c @@ -52,10 +52,12 @@ static void pglogical_read_tuple(StringInfo in, PGLogicalRelation *rel, */ void pglogical_write_rel(StringInfo out, PGLogicalOutputData *data, Relation rel, - Bitmapset *att_list, const char *nsptarget, const char *reltarget) + Bitmapset *att_list) { - uint8 nsptargetlen; - uint8 reltargetlen; + char *nspname; + uint8 nspnamelen; + const char *relname; + uint8 relnamelen; uint8 flags = 0; pq_sendbyte(out, 'R'); /* sending RELATION */ @@ -66,16 +68,25 @@ pglogical_write_rel(StringInfo out, PGLogicalOutputData *data, Relation rel, /* use Oid as relation identifier */ pq_sendint(out, RelationGetRelid(rel), 4); - nsptargetlen = strlen(nsptarget) + 1; - pq_sendbyte(out, nsptargetlen); /* schema name length */ - pq_sendbytes(out, nsptarget, nsptargetlen); + nspname = get_namespace_name(rel->rd_rel->relnamespace); + if (nspname == NULL) + elog(ERROR, "cache lookup failed for namespace %u", + rel->rd_rel->relnamespace); + nspnamelen = strlen(nspname) + 1; - reltargetlen = strlen(reltarget) + 1; - pq_sendbyte(out, reltargetlen); /* table name length */ - pq_sendbytes(out, reltarget, reltargetlen); + relname = NameStr(rel->rd_rel->relname); + relnamelen = strlen(relname) + 1; + + pq_sendbyte(out, nspnamelen); /* schema name length */ + pq_sendbytes(out, nspname, nspnamelen); + + pq_sendbyte(out, relnamelen); /* table name length */ + pq_sendbytes(out, relname, relnamelen); /* send the attribute info */ pglogical_write_attrs(out, rel, att_list); + + pfree(nspname); } /* diff --git a/pglogical_proto_native.h b/pglogical_proto_native.h index d6d327b..cb517fa 100644 --- a/pglogical_proto_native.h +++ b/pglogical_proto_native.h @@ -29,7 +29,7 @@ typedef struct PGLogicalTupleData } PGLogicalTupleData; extern void pglogical_write_rel(StringInfo out, PGLogicalOutputData *data, - Relation rel, Bitmapset *att_list, const char *nsptarget, const char *reltarget); + Relation rel, Bitmapset *att_list); extern void pglogical_write_begin(StringInfo out, PGLogicalOutputData *data, ReorderBufferTXN *txn); extern void pglogical_write_commit(StringInfo out, PGLogicalOutputData *data, diff --git a/pglogical_relcache.c b/pglogical_relcache.c index bafa39a..648abbe 100644 --- a/pglogical_relcache.c +++ b/pglogical_relcache.c @@ -181,8 +181,8 @@ pglogical_relation_cache_updater(PGLogicalRemoteRel *remoterel) /* Make cached copy of the data */ oldcontext = MemoryContextSwitchTo(CacheMemoryContext); - entry->nspname = pstrdup(remoterel->nsptarget); - entry->relname = pstrdup(remoterel->reltarget); + entry->nspname = pstrdup(remoterel->nspname); + entry->relname = pstrdup(remoterel->relname); entry->natts = remoterel->natts; entry->attnames = palloc(remoterel->natts * sizeof(char *)); for (i = 0; i < remoterel->natts; i++) diff --git a/pglogical_relcache.h b/pglogical_relcache.h index c2f6305..b76cf19 100644 --- a/pglogical_relcache.h +++ b/pglogical_relcache.h @@ -18,7 +18,6 @@ typedef struct PGLogicalRemoteRel { uint32 relid; - /* the nspname and relname are always the origin names */ char *nspname; char *relname; int natts; @@ -26,16 +25,12 @@ typedef struct PGLogicalRemoteRel /* Only returned by info function, not protocol. */ bool hasRowFilter; - char *nsptarget; - char *reltarget; } PGLogicalRemoteRel; typedef struct PGLogicalRelation { /* Info coming from the remote side. */ uint32 remoteid; - /* the nspanme and relname are always the target names, we don't know origin - * (remote) names */ char *nspname; char *relname; int natts; diff --git a/pglogical_repset.c b/pglogical_repset.c index d693133..b7b68ed 100644 --- a/pglogical_repset.c +++ b/pglogical_repset.c @@ -78,15 +78,11 @@ typedef struct RepSetSeqTuple { Oid id; Oid seqoid; - NameData nsptarget; - NameData seqtarget; } RepSetSeqTuple; -#define Natts_repset_seq 4 +#define Natts_repset_seq 2 #define Anum_repset_seq_setid 1 #define Anum_repset_seq_seqoid 2 -#define Anum_repset_seq_nsptarget 3 -#define Anum_repset_seq_seqtarget 4 typedef struct RepSetTableTuple { @@ -95,18 +91,14 @@ typedef struct RepSetTableTuple #if 0 /* Only for info here. */ text att_list[1]; text row_filter; - NameData nsptarget; - NameData reltarget; #endif } RepSetTableTuple; -#define Natts_repset_table 6 +#define Natts_repset_table 4 #define Anum_repset_table_setid 1 #define Anum_repset_table_reloid 2 #define Anum_repset_table_att_list 3 #define Anum_repset_table_row_filter 4 -#define Anum_repset_table_nsptarget 5 -#define Anum_repset_table_reltarget 6 #define REPSETTABLEHASH_INITIAL_SIZE 128 @@ -224,8 +216,6 @@ repset_relcache_invalidate_callback(Datum arg, Oid reloid) if (list_length(entry->row_filter)) list_free_deep(entry->row_filter); entry->row_filter = NIL; - entry->nsptarget = NULL; - entry->reltarget = NULL; } } else if ((entry = hash_search(RepSetTableHash, &reloid, @@ -238,8 +228,6 @@ repset_relcache_invalidate_callback(Datum arg, Oid reloid) if (list_length(entry->row_filter)) list_free_deep(entry->row_filter); entry->row_filter = NIL; - entry->nsptarget = NULL; - entry->reltarget = NULL; } } @@ -424,8 +412,6 @@ get_table_replication_info(Oid nodeid, Relation table, entry->replicate_delete = false; entry->att_list = NULL; entry->row_filter = NIL; - entry->nsptarget = get_namespace_name(RelationGetNamespace(table)); - entry->reltarget = RelationGetRelationName(table); /* * Check for match between table's replication sets and the subscription @@ -517,16 +503,6 @@ get_table_replication_info(Oid nodeid, Relation table, entry->row_filter = lappend(entry->row_filter, row_filter); MemoryContextSwitchTo(olctx); } - - /* Add namespace target. NOT NULL */ - d = heap_getattr(tuple, Anum_repset_table_nsptarget, - repset_rel_desc, &isnull); - entry->nsptarget = pstrdup(NameStr(*DatumGetName(d))); - - /* Add relation target. NOT NULL */ - d = heap_getattr(tuple, Anum_repset_table_reltarget, - repset_rel_desc, &isnull); - entry->reltarget = pstrdup(NameStr(*DatumGetName(d))); } } } @@ -538,147 +514,6 @@ get_table_replication_info(Oid nodeid, Relation table, return entry; } -List * -get_table_replication_info_by_target(Oid nodeid, char *nsptarget, char *reltarget, - List *subs_replication_sets) -{ - RangeVar *rv; - Oid repset_reloid; - Relation repset_rel; - ScanKeyData key[2]; - SysScanDesc scan; - HeapTuple tuple; - List *tablesinfo = NIL; - TupleDesc table_desc, - repset_rel_desc; - - // XXX use cache like in the previous function ? - - /* - * Check for match between table's replication sets and the subscription - * list of replication sets that was given as parameter. - * - * Note that tables can have no replication sets. This will be commonly - * true for example for internal tables which are created during table - * rewrites, so if we'll want to support replicating those, we'll have - * to have special handling for them. - */ - rv = makeRangeVar(EXTENSION_NAME, CATALOG_REPSET_TABLE, -1); - repset_reloid = RangeVarGetRelid(rv, RowExclusiveLock, true); - /* Backwards compat with 1.1/1.2 where the relation name was different. */ - if (!OidIsValid(repset_reloid)) - { - rv = makeRangeVar(EXTENSION_NAME, CATALOG_REPSET_RELATION, -1); - repset_reloid = RangeVarGetRelid(rv, RowExclusiveLock, true); - if (!OidIsValid(repset_reloid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_TABLE), - errmsg("relation \"%s.%s\" does not exist", - rv->schemaname, rv->relname))); - } - repset_rel = table_open(repset_reloid, NoLock); - repset_rel_desc = RelationGetDescr(repset_rel); - - ScanKeyInit(&key[0], - Anum_repset_table_nsptarget, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(nsptarget)); - ScanKeyInit(&key[1], - Anum_repset_table_reltarget, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(reltarget)); - - /* TODO: use index */ - scan = systable_beginscan(repset_rel, 0, true, NULL, 2, key); - - while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - PGLogicalTableRepInfo *entry = palloc0(sizeof(PGLogicalTableRepInfo)); - RepSetTableTuple *t = (RepSetTableTuple *) GETSTRUCT(tuple); - ListCell *lc; - - /* Fill the entry */ - entry->reloid = InvalidOid; - entry->replicate_insert = false; - entry->replicate_update = false; - entry->replicate_delete = false; - entry->att_list = NULL; - entry->row_filter = NIL; - entry->nsptarget = nsptarget; - entry->reltarget = reltarget; - entry->isvalid = false; - - foreach (lc, subs_replication_sets) - { - PGLogicalRepSet *repset = lfirst(lc); - bool isnull; - Datum d; - - if (t->setid == repset->id) - { - /* Update the OID */ - entry->reloid = t->reloid; - - /* Update the action filter. */ - if (repset->replicate_insert) - entry->replicate_insert = true; - if (repset->replicate_update) - entry->replicate_update = true; - if (repset->replicate_delete) - entry->replicate_delete = true; - - /* Update replicated column map. */ - d = heap_getattr(tuple, Anum_repset_table_att_list, - repset_rel_desc, &isnull); - if (!isnull) - { - Datum *elems; - int nelems, i; - Relation rel; - - deconstruct_array(DatumGetArrayTypePCopy(d), - TEXTOID, -1, false, 'i', - &elems, NULL, &nelems); - - rel = table_open(entry->reloid, AccessShareLock); - table_desc = RelationGetDescr(rel); - for (i = 0; i < nelems; i++) - { - const char *attname = TextDatumGetCString(elems[i]); - int attnum = get_att_num_by_name(table_desc, - attname); - - MemoryContext olctx = MemoryContextSwitchTo(CacheMemoryContext); - entry->att_list = bms_add_member(entry->att_list, - attnum - FirstLowInvalidHeapAttributeNumber); - MemoryContextSwitchTo(olctx); - } - table_close(rel, AccessShareLock); - } - - /* Add row filter if any. */ - d = heap_getattr(tuple, Anum_repset_table_row_filter, - repset_rel_desc, &isnull); - if (!isnull) - { - MemoryContext olctx = MemoryContextSwitchTo(CacheMemoryContext); - Node *row_filter = stringToNode(TextDatumGetCString(d)); - entry->row_filter = lappend(entry->row_filter, row_filter); - MemoryContextSwitchTo(olctx); - } - } - } - if (entry->reloid == InvalidOid) - continue; - entry->isvalid = true; - tablesinfo = lappend(tablesinfo, entry); - } - - systable_endscan(scan); - table_close(repset_rel, RowExclusiveLock); - return tablesinfo; -} - List * get_table_replication_sets(Oid nodeid, Oid reloid) { @@ -804,113 +639,6 @@ get_seq_replication_sets(Oid nodeid, Oid seqoid) return replication_sets; } -List * -get_seq_replication_sets_targets(Oid nodeid, Oid seqoid) -{ - RangeVar *rv; - Relation rel; - ScanKeyData key[1]; - SysScanDesc scan; - HeapTuple tuple; - List *seq_targets = NIL; - - Assert(IsTransactionState()); - - rv = makeRangeVar(EXTENSION_NAME, CATALOG_REPSET_SEQ, -1); - rel = table_openrv(rv, RowExclusiveLock); - - ScanKeyInit(&key[0], - Anum_repset_seq_seqoid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(seqoid)); - - /* TODO: use index */ - scan = systable_beginscan(rel, 0, true, NULL, 1, key); - - while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - RepSetSeqTuple *t = (RepSetSeqTuple *) GETSTRUCT(tuple); - PGLogicalRepSet *repset = get_replication_set(t->id); - PGLogicalRepSetSeq *seqtarget; - - if (repset->nodeid != nodeid) - continue; - - seqtarget = (PGLogicalRepSetSeq *) palloc(sizeof(PGLogicalRepSetSeq)); - seqtarget->seqoid = t->seqoid; - seqtarget->nsptarget = pstrdup(NameStr(t->nsptarget)); - seqtarget->seqtarget = pstrdup(NameStr(t->seqtarget)); - seqtarget->repset_name = pstrdup(repset->name); - seq_targets = lappend(seq_targets, seqtarget); - } - - systable_endscan(scan); - table_close(rel, RowExclusiveLock); - - return seq_targets; -} - -List * -get_table_replication_sets_targets(Oid nodeid, Oid reloid) -{ - RangeVar *rv; - Relation rel; - ScanKeyData key[1]; - SysScanDesc scan; - HeapTuple tuple; - List *rel_targets = NIL; - TupleDesc rel_desc; - - Assert(IsTransactionState()); - - rv = makeRangeVar(EXTENSION_NAME, CATALOG_REPSET_TABLE, -1); - rel = table_openrv(rv, RowExclusiveLock); - rel_desc = RelationGetDescr(rel); - - ScanKeyInit(&key[0], - Anum_repset_table_reloid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(reloid)); - - /* TODO: use index */ - scan = systable_beginscan(rel, 0, true, NULL, 1, key); - - while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - RepSetTableTuple *t = (RepSetTableTuple *) GETSTRUCT(tuple); - PGLogicalRepSet *repset = get_replication_set(t->setid); - PGLogicalRepSetRel *reltarget = (PGLogicalRepSetRel *) palloc(sizeof(PGLogicalRepSetRel)); - bool isnull; - Datum d; - - if (repset->nodeid != nodeid) - continue; - reltarget->reloid = t->reloid; - - /* Add namespace target. */ - d = heap_getattr(tuple, Anum_repset_table_nsptarget, - rel_desc, &isnull); - if (isnull) - elog(ERROR, "nsptarget is NULL!"); - reltarget->nsptarget = pstrdup(NameStr(*DatumGetName(d))); - - /* Add relation target. */ - d = heap_getattr(tuple, Anum_repset_table_reltarget, - rel_desc, &isnull); - if (isnull) - elog(ERROR, "reltarget is NULL!"); - reltarget->reltarget = pstrdup(NameStr(*DatumGetName(d))); - - reltarget->repset_name = pstrdup(repset->name); - rel_targets = lappend(rel_targets, reltarget); - } - - systable_endscan(scan); - table_close(rel, RowExclusiveLock); - - return rel_targets; -} - /* * Add new tuple to the replication_sets catalog. */ @@ -1286,16 +1014,13 @@ drop_node_replication_sets(Oid nodeid) */ void replication_set_add_table(Oid setid, Oid reloid, List *att_list, - Node *row_filter, char *nsptarget, char *reltarget) + Node *row_filter) { RangeVar *rv; Relation rel; Relation targetrel; TupleDesc tupDesc; HeapTuple tup; - SysScanDesc scan; - ScanKeyData key[3]; - HeapTuple tuple; Datum values[Natts_repset_table]; bool nulls[Natts_repset_table]; PGLogicalRepSet *repset = get_replication_set(setid); @@ -1328,44 +1053,11 @@ replication_set_add_table(Oid setid, Oid reloid, List *att_list, table_close(targetrel, NoLock); - if (!nsptarget) - nsptarget = get_namespace_name(RelationGetNamespace(targetrel)); - if (!reltarget) - reltarget = RelationGetRelationName(targetrel); - /* Open the catalog. */ rv = makeRangeVar(EXTENSION_NAME, CATALOG_REPSET_TABLE, -1); rel = table_openrv(rv, RowExclusiveLock); tupDesc = RelationGetDescr(rel); - /* Check that another reloid does not exists with the same targets. */ - ScanKeyInit(&key[0], - Anum_repset_table_setid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(setid)); - ScanKeyInit(&key[1], - Anum_repset_table_nsptarget, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(nsptarget)); - ScanKeyInit(&key[2], - Anum_repset_table_reltarget, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(reltarget)); - scan = systable_beginscan(rel, 0, false, NULL, 3, key); - - /* And if it does ERROR out. */ - while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - RepSetTableTuple *r = (RepSetTableTuple *) GETSTRUCT(tuple); - if (r->reloid == reloid) - continue; - elog(ERROR,"Table %s.%s already replicated from %s.%s in the same set, cannot add another source", - nsptarget, reltarget, - get_namespace_name(RelationGetNamespace(targetrel)), - RelationGetRelationName(targetrel)); - } - systable_endscan(scan); - /* Form a tuple. */ memset(nulls, false, sizeof(nulls)); @@ -1384,20 +1076,6 @@ replication_set_add_table(Oid setid, Oid reloid, List *att_list, else nulls[Anum_repset_table_row_filter - 1] = true; - if (nsptarget) - values[Anum_repset_table_nsptarget - 1] = - CStringGetDatum(nsptarget); - else - values[Anum_repset_table_nsptarget - 1] = - CStringGetDatum(get_namespace_name(RelationGetNamespace(targetrel))); - - if (reltarget) - values[Anum_repset_table_reltarget - 1] = - CStringGetDatum(reltarget); - else - values[Anum_repset_table_reltarget - 1] = - CStringGetDatum(RelationGetRelationName(targetrel)); - tup = heap_form_tuple(tupDesc, values, nulls); /* Insert the tuple to the catalog. */ @@ -1434,16 +1112,13 @@ replication_set_add_table(Oid setid, Oid reloid, List *att_list, * Insert new replication set / sequence mapping. */ void -replication_set_add_seq(Oid setid, Oid seqoid, char *nsptarget, char *reltarget) +replication_set_add_seq(Oid setid, Oid seqoid) { RangeVar *rv; Relation rel; Relation targetrel; TupleDesc tupDesc; HeapTuple tup; - SysScanDesc scan; - ScanKeyData key[3]; - HeapTuple tuple; Datum values[Natts_repset_table]; bool nulls[Natts_repset_table]; PGLogicalRepSet *repset = get_replication_set(setid); @@ -1464,59 +1139,17 @@ replication_set_add_seq(Oid setid, Oid seqoid, char *nsptarget, char *reltarget) table_close(targetrel, NoLock); - if (!nsptarget) - nsptarget = get_namespace_name(RelationGetNamespace(targetrel)); - if (!reltarget) - reltarget = RelationGetRelationName(targetrel); - /* Open the catalog. */ rv = makeRangeVar(EXTENSION_NAME, CATALOG_REPSET_SEQ, -1); rel = table_openrv(rv, RowExclusiveLock); tupDesc = RelationGetDescr(rel); - /* Check that another seqoid does not exists with the same targets. */ - ScanKeyInit(&key[0], - Anum_repset_seq_nsptarget, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(nsptarget)); - ScanKeyInit(&key[1], - Anum_repset_seq_seqtarget, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(reltarget)); - scan = systable_beginscan(rel, 0, false, NULL, 2, key); - - /* And if it does ERROR out. */ - while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - RepSetSeqTuple *s = (RepSetSeqTuple *) GETSTRUCT(tuple); - if (s->seqoid == seqoid) - continue; - elog(ERROR,"Sequence %s.%s already replicated from %s.%s, cannot add another source", - nsptarget, reltarget, - get_namespace_name(RelationGetNamespace(targetrel)), - RelationGetRelationName(targetrel)); - } - /* Form a tuple. */ memset(nulls, false, sizeof(nulls)); values[Anum_repset_seq_setid - 1] = ObjectIdGetDatum(repset->id); values[Anum_repset_seq_seqoid - 1] = ObjectIdGetDatum(seqoid); - if (nsptarget) - values[Anum_repset_seq_nsptarget - 1] = - CStringGetDatum(nsptarget); - else - values[Anum_repset_seq_nsptarget - 1] = - CStringGetDatum(get_namespace_name(RelationGetNamespace(targetrel))); - - if (reltarget) - values[Anum_repset_seq_seqtarget - 1] = - CStringGetDatum(reltarget); - else - values[Anum_repset_seq_seqtarget - 1] = - CStringGetDatum(RelationGetRelationName(targetrel)); - tup = heap_form_tuple(tupDesc, values, nulls); /* Insert the tuple to the catalog. */ @@ -1536,8 +1169,6 @@ replication_set_add_seq(Oid setid, Oid seqoid, char *nsptarget, char *reltarget) pglogical_recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); - /* Cleanup. */ - systable_endscan(scan); table_close(rel, RowExclusiveLock); CommandCounterIncrement(); diff --git a/pglogical_repset.h b/pglogical_repset.h index 2b0b0e8..2c70569 100644 --- a/pglogical_repset.h +++ b/pglogical_repset.h @@ -26,14 +26,6 @@ typedef struct PGLogicalRepSet bool replicate_truncate; } PGLogicalRepSet; -typedef struct PGLogicalRepSetSeq -{ - Oid seqoid; - char *nsptarget; - char *seqtarget; - char *repset_name; -} PGLogicalRepSetSeq; - #define DEFAULT_REPSET_NAME "default" #define DEFAULT_INSONLY_REPSET_NAME "default_insert_only" #define DDL_SQL_REPSET_NAME "ddl_sql" @@ -54,45 +46,28 @@ typedef struct PGLogicalTableRepInfo otherwise each replicated column is a member */ List *row_filter; /* compiled row_filter nodes */ - - char *nsptarget; /* namespace name to expose */ - char *reltarget; /* relation name to expose */ } PGLogicalTableRepInfo; -typedef struct PGLogicalRepSetRel -{ - Oid reloid; - char *nsptarget; - char *reltarget; - char *repset_name; -} PGLogicalRepSetRel; - - extern PGLogicalRepSet *get_replication_set(Oid setid); extern PGLogicalRepSet *get_replication_set_by_name(Oid nodeid, const char *setname, bool missing_ok); -extern List *get_table_replication_sets_targets(Oid nodeid, Oid reloid); extern List *get_node_replication_sets(Oid nodeid); extern List *get_replication_sets(Oid nodeid, List *replication_set_names, bool missing_ok); + extern PGLogicalTableRepInfo *get_table_replication_info(Oid nodeid, Relation table, List *subs_replication_sets); -extern List *get_table_replication_info_by_target(Oid nodeid, - char *nsptarget, char *reltarget, List *subs_replication_sets); - extern void create_replication_set(PGLogicalRepSet *repset); extern void alter_replication_set(PGLogicalRepSet *repset); extern void drop_replication_set(Oid setid); extern void drop_node_replication_sets(Oid nodeid); extern void replication_set_add_table(Oid setid, Oid reloid, - List *att_list, Node *row_filter, - char *nsptarget, char *reltarget); -extern void replication_set_add_seq(Oid setid, Oid seqoid, - char *nsptarget, char *seqtarget); + List *att_list, Node *row_filter); +extern void replication_set_add_seq(Oid setid, Oid seqoid); extern List *replication_set_get_tables(Oid setid); extern List *replication_set_get_seqs(Oid setid); extern PGDLLEXPORT void replication_set_remove_table(Oid setid, Oid reloid, @@ -102,8 +77,6 @@ extern PGDLLEXPORT void replication_set_remove_seq(Oid setid, Oid reloid, extern List *get_table_replication_sets(Oid nodeid, Oid reloid); extern List *get_seq_replication_sets(Oid nodeid, Oid seqoid); -extern List *get_table_replication_sets_targets(Oid nodeid, Oid reloid); -extern List *get_seq_replication_sets_targets(Oid nodeid, Oid seqoid); extern PGLogicalRepSet *replication_set_from_tuple(HeapTuple tuple); diff --git a/pglogical_rpc.c b/pglogical_rpc.c index a770e51..b7fd467 100644 --- a/pglogical_rpc.c +++ b/pglogical_rpc.c @@ -59,22 +59,12 @@ pg_logical_get_remote_repset_tables(PGconn *conn, List *replication_sets) } initStringInfo(&query); - if (pglogical_remote_function_exists(conn, "pglogical", "show_repset_table_info_by_target", 3, NULL)) - { - /* PGLogical 2.3+ */ - appendStringInfo(&query, - "SELECT i.relid, i.nspname, i.relname, i.att_list," - " i.has_row_filter, i.nsptarget, i.reltarget" - " FROM (SELECT DISTINCT relid FROM pglogical.tables WHERE set_name = ANY(ARRAY[%s])) t," - " LATERAL pglogical.show_repset_table_info(t.relid, ARRAY[%s]) i", - repsetarr.data, repsetarr.data); - } - else if (pglogical_remote_function_exists(conn, "pglogical", "show_repset_table_info", 2, NULL)) + if (pglogical_remote_function_exists(conn, "pglogical", "show_repset_table_info", 2, NULL)) { /* PGLogical 2.0+ */ appendStringInfo(&query, "SELECT i.relid, i.nspname, i.relname, i.att_list," - " i.has_row_filter, i.nspname as i.nsptarget, i.relname as i.reltarget" + " i.has_row_filter" " FROM (SELECT DISTINCT relid FROM pglogical.tables WHERE set_name = ANY(ARRAY[%s])) t," " LATERAL pglogical.show_repset_table_info(t.relid, ARRAY[%s]) i", repsetarr.data, repsetarr.data); @@ -84,7 +74,7 @@ pg_logical_get_remote_repset_tables(PGconn *conn, List *replication_sets) /* PGLogical 1.x */ appendStringInfo(&query, "SELECT r.oid AS relid, t.nspname, t.relname, ARRAY(SELECT attname FROM pg_attribute WHERE attrelid = r.oid AND NOT attisdropped AND attnum > 0) AS att_list," - " false AS has_row_filter, t.nspname as nsptarget, t.relname as reltarget" + " false AS has_row_filter" " FROM pglogical.tables t, pg_catalog.pg_class r, pg_catalog.pg_namespace n" " WHERE t.set_name = ANY(ARRAY[%s]) AND r.relname = t.relname AND n.oid = r.relnamespace AND n.nspname = t.nspname", repsetarr.data); @@ -106,8 +96,6 @@ pg_logical_get_remote_repset_tables(PGconn *conn, List *replication_sets) &remoterel->natts)) elog(ERROR, "could not parse column list for table"); remoterel->hasRowFilter = (strcmp(PQgetvalue(res, i, 4), "t") == 0); - remoterel->nsptarget = pstrdup(PQgetvalue(res, i, 5)); - remoterel->reltarget = pstrdup(PQgetvalue(res, i, 6)); tables = lappend(tables, remoterel); } @@ -120,23 +108,22 @@ pg_logical_get_remote_repset_tables(PGconn *conn, List *replication_sets) /* * Like above but for one table. */ -List * +PGLogicalRemoteRel * pg_logical_get_remote_repset_table(PGconn *conn, RangeVar *rv, List *replication_sets) { + PGLogicalRemoteRel *remoterel = palloc0(sizeof(PGLogicalRemoteRel)); PGresult *res; - int i; - List *tables = NIL; ListCell *lc; bool first = true; StringInfoData query; StringInfoData repsetarr; - StringInfoData relname; + StringInfoData relname; initStringInfo(&relname); appendStringInfo(&relname, "%s.%s", - PQescapeLiteral(conn, rv->schemaname, strlen(rv->schemaname)), - PQescapeLiteral(conn, rv->relname, strlen(rv->relname))); + PQescapeIdentifier(conn, rv->schemaname, strlen(rv->schemaname)), + PQescapeIdentifier(conn, rv->relname, strlen(rv->relname))); initStringInfo(&repsetarr); foreach (lc, replication_sets) @@ -153,23 +140,12 @@ pg_logical_get_remote_repset_table(PGconn *conn, RangeVar *rv, } initStringInfo(&query); - if (pglogical_remote_function_exists(conn, "pglogical", "show_repset_table_info_by_target", 3, NULL)) - { - /* PGLogical 2.3+ */ - appendStringInfo(&query, - "SELECT i.relid, i.nspname, i.relname, i.att_list," - " i.has_row_filter, i.nsptarget, i.reltarget" - " FROM pglogical.show_repset_table_info_by_target(%s, %s, ARRAY[%s]) i", - PQescapeLiteral(conn, rv->schemaname, strlen(rv->schemaname)), - PQescapeLiteral(conn, rv->relname, strlen(rv->relname)), - repsetarr.data); - } - else if (pglogical_remote_function_exists(conn, "pglogical", "show_repset_table_info", 2, NULL)) + if (pglogical_remote_function_exists(conn, "pglogical", "show_repset_table_info", 2, NULL)) { /* PGLogical 2.0+ */ appendStringInfo(&query, "SELECT i.relid, i.nspname, i.relname, i.att_list," - " i.has_row_filter, i.nspname as nsptarget, i.relname as reltarget" + " i.has_row_filter" " FROM pglogical.show_repset_table_info(%s::regclass, ARRAY[%s]) i", PQescapeLiteral(conn, relname.data, relname.len), repsetarr.data); @@ -179,7 +155,7 @@ pg_logical_get_remote_repset_table(PGconn *conn, RangeVar *rv, /* PGLogical 1.x */ appendStringInfo(&query, "SELECT r.oid AS relid, t.nspname, t.relname, ARRAY(SELECT attname FROM pg_attribute WHERE attrelid = r.oid AND NOT attisdropped AND attnum > 0) AS att_list," - " false AS has_row_filter, t.nspname as nsptarget, t.relname as reltarget" + " false AS has_row_filter" " FROM pglogical.tables t, pg_catalog.pg_class r, pg_catalog.pg_namespace n" " WHERE r.oid = %s::regclass AND t.set_name = ANY(ARRAY[%s]) AND r.relname = t.relname AND n.oid = r.relnamespace AND n.nspname = t.nspname", PQescapeLiteral(conn, relname.data, relname.len), @@ -191,26 +167,18 @@ pg_logical_get_remote_repset_table(PGconn *conn, RangeVar *rv, if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) elog(ERROR, "could not get table list: %s", PQresultErrorMessage(res)); - for (i = 0; i < PQntuples(res); i++) - { - PGLogicalRemoteRel *remoterel = palloc0(sizeof(PGLogicalRemoteRel)); - - remoterel->relid = atooid(PQgetvalue(res, i, 0)); - remoterel->nspname = pstrdup(PQgetvalue(res, i, 1)); - remoterel->relname = pstrdup(PQgetvalue(res, i, 2)); - if (!parsePGArray(PQgetvalue(res, i, 3), &remoterel->attnames, - &remoterel->natts)) - elog(ERROR, "could not parse column list for table"); - remoterel->hasRowFilter = (strcmp(PQgetvalue(res, i, 4), "t") == 0); - remoterel->nsptarget = pstrdup(PQgetvalue(res, i, 5)); - remoterel->reltarget = pstrdup(PQgetvalue(res, i, 6)); + remoterel->relid = atooid(PQgetvalue(res, 0, 0)); + remoterel->nspname = pstrdup(PQgetvalue(res, 0, 1)); + remoterel->relname = pstrdup(PQgetvalue(res, 0, 2)); + if (!parsePGArray(PQgetvalue(res, 0, 3), &remoterel->attnames, + &remoterel->natts)) + elog(ERROR, "could not parse column list for table"); + remoterel->hasRowFilter = (strcmp(PQgetvalue(res, 0, 4), "t") == 0); - tables = lappend(tables, remoterel); - } PQclear(res); - return tables; + return remoterel; } /* diff --git a/pglogical_rpc.h b/pglogical_rpc.h index cae9e39..fbd80af 100644 --- a/pglogical_rpc.h +++ b/pglogical_rpc.h @@ -17,7 +17,7 @@ extern List *pg_logical_get_remote_repset_tables(PGconn *conn, List *replication_sets); -extern List *pg_logical_get_remote_repset_table(PGconn *conn, +extern PGLogicalRemoteRel *pg_logical_get_remote_repset_table(PGconn *conn, RangeVar *rv, List *replication_sets); extern List *pg_logical_get_remote_repset_sequences(PGconn *conn, List *replication_sets); diff --git a/pglogical_sequences.c b/pglogical_sequences.c index 3e1a05f..1d52f76 100644 --- a/pglogical_sequences.c +++ b/pglogical_sequences.c @@ -47,11 +47,6 @@ typedef struct SeqStateTuple { int64 last_value; } SeqStateTuple; -typedef struct SeqTargets { - Relation seqtarget; - List *repsets; -} SeqTargets; - #define Natts_sequence_state 3 #define Anum_sequence_state_seqoid 1 #define Anum_sequence_state_cache_size 2 @@ -115,8 +110,12 @@ synchronize_sequences(void) SeqStateTuple *newseq; int64 last_value; HeapTuple newtup; - List *seqtargets; + List *repsets; + List *repset_names; ListCell *lc; + char *nspname; + char *relname; + StringInfoData json; CHECK_FOR_INTERRUPTS(); @@ -141,42 +140,29 @@ synchronize_sequences(void) newseq->last_value = last_value + newseq->cache_size; simple_heap_update(rel, &tuple->t_self, newtup); - /* - * We need each target relation and namespace names, with their - * respective replication set names. - */ - seqtargets = get_seq_replication_sets_targets(local_node->node->id, - oldseq->seqoid); - /* - * For the moment, a sequence cannot have more than one target - * per node/replication set. And here we sync one oid at once. - * Still a sequence can have distinct targets on distinct repset - * so we need to figure that here. See - * pglogical.replication_set_seq CONSTRAINTS - */ - foreach (lc, seqtargets) + repsets = get_seq_replication_sets(local_node->node->id, + oldseq->seqoid); + repset_names = NIL; + foreach (lc, repsets) { - StringInfoData json; - List *repset_names = NIL; - char *nspname; - char *relname; - PGLogicalRepSetSeq *t = (PGLogicalRepSetSeq *) lfirst(lc); - nspname = pstrdup(t->nsptarget); - relname = pstrdup(t->seqtarget); - repset_names = lappend(repset_names, pstrdup(t->repset_name)); - - initStringInfo(&json); - appendStringInfoString(&json, "{\"schema_name\": "); - escape_json(&json, nspname); - appendStringInfoString(&json, ",\"sequence_name\": "); - escape_json(&json, relname); - appendStringInfo(&json, ",\"last_value\": \""INT64_FORMAT"\"", - newseq->last_value); - appendStringInfo(&json, "}"); - - queue_message(repset_names, GetUserId(), - QUEUE_COMMAND_TYPE_SEQUENCE, json.data); + PGLogicalRepSet *repset = (PGLogicalRepSet *) lfirst(lc); + repset_names = lappend(repset_names, pstrdup(repset->name)); } + + nspname = get_namespace_name(get_rel_namespace(oldseq->seqoid)); + relname = get_rel_name(oldseq->seqoid); + + initStringInfo(&json); + appendStringInfoString(&json, "{\"schema_name\": "); + escape_json(&json, nspname); + appendStringInfoString(&json, ",\"sequence_name\": "); + escape_json(&json, relname); + appendStringInfo(&json, ",\"last_value\": \""INT64_FORMAT"\"", + newseq->last_value); + appendStringInfo(&json, "}"); + + queue_message(repset_names, GetUserId(), + QUEUE_COMMAND_TYPE_SEQUENCE, json.data); } /* Cleanup */ @@ -203,8 +189,12 @@ synchronize_sequence(Oid seqoid) SeqStateTuple *newseq; int64 last_value; HeapTuple newtup; - List *seqtargets; + List *repsets; + List *repset_names; ListCell *lc; + char *nspname; + char *relname; + StringInfoData json; PGLogicalLocalNode *local_node = get_local_node(true, false); /* Check if the oid points to actual sequence. */ @@ -240,39 +230,32 @@ synchronize_sequence(Oid seqoid) last_value = sequence_get_last_value(seqoid); - /* Update the tracking table with new last_value */ newseq->last_value = last_value + newseq->cache_size; simple_heap_update(rel, &tuple->t_self, newtup); - /* And now prepare the messages for the queue */ - seqtargets = get_seq_replication_sets_targets(local_node->node->id, seqoid); - /* - * Compute a message for each unique (seqoid,nsptarget,seqtarget) triplet. - */ - foreach (lc, seqtargets) + repsets = get_seq_replication_sets(local_node->node->id, seqoid); + repset_names = NIL; + foreach (lc, repsets) { - StringInfoData json; - List *repset_names = NIL; - char *nspname; - char *relname; - PGLogicalRepSetSeq *t = (PGLogicalRepSetSeq *) lfirst(lc); - nspname = pstrdup(t->nsptarget); - relname = pstrdup(t->seqtarget); - repset_names = lappend(repset_names, pstrdup(t->repset_name)); - - initStringInfo(&json); - appendStringInfoString(&json, "{\"schema_name\": "); - escape_json(&json, nspname); - appendStringInfoString(&json, ",\"sequence_name\": "); - escape_json(&json, relname); - appendStringInfo(&json, ",\"last_value\": \""INT64_FORMAT"\"", - newseq->last_value); - appendStringInfo(&json, "}"); - - queue_message(repset_names, GetUserId(), - QUEUE_COMMAND_TYPE_SEQUENCE, json.data); + PGLogicalRepSet *repset = (PGLogicalRepSet *) lfirst(lc); + repset_names = lappend(repset_names, pstrdup(repset->name)); } + nspname = get_namespace_name(RelationGetNamespace(seqrel)); + relname = RelationGetRelationName(seqrel); + + initStringInfo(&json); + appendStringInfoString(&json, "{\"schema_name\": "); + escape_json(&json, nspname); + appendStringInfoString(&json, ",\"sequence_name\": "); + escape_json(&json, relname); + appendStringInfo(&json, ",\"last_value\": \""INT64_FORMAT"\"", + newseq->last_value); + appendStringInfo(&json, "}"); + + queue_message(repset_names, GetUserId(), + QUEUE_COMMAND_TYPE_SEQUENCE, json.data); + /* Cleanup */ systable_endscan(scan); table_close(rel, NoLock); diff --git a/pglogical_sync.c b/pglogical_sync.c index 149f61b..6935dd2 100644 --- a/pglogical_sync.c +++ b/pglogical_sync.c @@ -536,10 +536,10 @@ copy_table_data(PGconn *origin_conn, PGconn *target_conn, /* Build COPY FROM query. */ resetStringInfo(&query); appendStringInfo(&query, "COPY %s.%s ", - PQescapeIdentifier(target_conn, remoterel->nsptarget, - strlen(remoterel->nsptarget)), - PQescapeIdentifier(target_conn, remoterel->reltarget, - strlen(remoterel->reltarget))); + PQescapeIdentifier(origin_conn, remoterel->nspname, + strlen(remoterel->nspname)), + PQescapeIdentifier(origin_conn, remoterel->relname, + strlen(remoterel->relname))); if (list_length(attnamelist)) appendStringInfo(&query, "(%s) ", attlist.data); appendStringInfoString(&query, "FROM stdin"); @@ -588,7 +588,7 @@ copy_table_data(PGconn *origin_conn, PGconn *target_conn, PQclear(res); elog(INFO, "finished synchronization of data for table %s.%s", - remoterel->nsptarget, remoterel->reltarget); + remoterel->nspname, remoterel->relname); } /* @@ -621,10 +621,10 @@ list_replication_sets_objects(const char *dsn, const char *name, const char *sna initStringInfo(&object); appendStringInfo(&object, "%s.%s", - PQescapeLiteral(origin_conn, remoterel->nsptarget, - strlen(remoterel->nsptarget)), - PQescapeLiteral(origin_conn, remoterel->reltarget, - strlen(remoterel->reltarget))); + PQescapeLiteral(origin_conn, remoterel->nspname, + strlen(remoterel->nspname)), + PQescapeLiteral(origin_conn, remoterel->relname, + strlen(remoterel->relname))); res = lappend(res, object.data); /* XXX probably not required here */ @@ -672,7 +672,7 @@ copy_tables_data(char *sub_name, const char *origin_dsn, { PGconn *origin_conn; PGconn *target_conn; - ListCell *lc, *lcr; + ListCell *lc; /* Connect to origin node. */ origin_conn = pglogical_connect(origin_dsn, sub_name, "copy"); @@ -686,14 +686,12 @@ copy_tables_data(char *sub_name, const char *origin_dsn, foreach (lc, tables) { RangeVar *rv = lfirst(lc); - List *remoterels = NIL; - remoterels = pg_logical_get_remote_repset_table(origin_conn, rv, + PGLogicalRemoteRel *remoterel; + + remoterel = pg_logical_get_remote_repset_table(origin_conn, rv, replication_sets); - foreach(lcr, remoterels) - { - PGLogicalRemoteRel *remoterel = lfirst(lcr); - copy_table_data(origin_conn, target_conn, remoterel, replication_sets); - } + + copy_table_data(origin_conn, target_conn, remoterel, replication_sets); CHECK_FOR_INTERRUPTS(); } @@ -953,13 +951,12 @@ pglogical_sync_subscription(PGLogicalSubscription *sub) PGLogicalSyncStatus *oldsync; oldsync = get_table_sync_status(sub->id, - remoterel->nsptarget, - remoterel->reltarget, - true); + remoterel->nspname, + remoterel->relname, true); if (oldsync) { - set_table_sync_status(sub->id, remoterel->nsptarget, - remoterel->reltarget, + set_table_sync_status(sub->id, remoterel->nspname, + remoterel->relname, SYNC_STATUS_READY, lsn); } @@ -969,8 +966,8 @@ pglogical_sync_subscription(PGLogicalSubscription *sub) newsync.kind = SYNC_KIND_FULL; newsync.subid = sub->id; - namestrcpy(&newsync.nspname, remoterel->nsptarget); - namestrcpy(&newsync.relname, remoterel->reltarget); + namestrcpy(&newsync.nspname, remoterel->nspname); + namestrcpy(&newsync.relname, remoterel->relname); newsync.status = SYNC_STATUS_READY; newsync.statuslsn = lsn; create_local_sync_status(&newsync); diff --git a/sql/map.sql b/sql/map.sql deleted file mode 100644 index 5130b36..0000000 --- a/sql/map.sql +++ /dev/null @@ -1,264 +0,0 @@ -SELECT * FROM pglogical_regress_variables() -\gset - -/* -Covered cases: - - - 1 table replicated with a distinct name in a distinct schema. Init + DML + resync + TRUNCATE - - 1 table replicated with a distinct name in the same schema. Init + DML + resync + TRUNCATE - - 1 table replicated with the same name in a distinct schema. Init + DML + resync + TRUNCATE - - 1 table replicated with distinct target in 2 distinct sets (a.b -> c.d and a.b -> e.f) - - 2 tables merged from distinct sets - - test resynchronize when multiple origin for the same table (origin indistincts sets - - - Not supported: 2 tables merged in the same set - - Trying to add twice the same table in the same set (with distinct targets): FORBIDEN (XXX should/can we allow ?) -*/ - -\c :provider_dsn -CREATE SCHEMA "provider.ping"; -CREATE SCHEMA "provider2.ping2"; -CREATE SCHEMA provsub; - -CREATE TABLE "provider.ping".test_origin(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".test_origin(data) VALUES ('a'); -INSERT INTO "provider.ping".test_origin(data) VALUES ('b'); -SELECT * FROM "provider.ping".test_origin ORDER by 1; - -CREATE TABLE "provider.ping".test_origin2(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".test_origin2(data) VALUES ('y'); -INSERT INTO "provider.ping".test_origin2(data) VALUES ('z'); -SELECT * FROM "provider.ping".test_origin2 ORDER by 1; - -CREATE TABLE provsub.test_origin3(id serial primary key, data text DEFAULT ''); -INSERT INTO provsub.test_origin3(data) VALUES ('a'); -INSERT INTO provsub.test_origin3(data) VALUES ('b'); -SELECT * FROM provsub.test_origin3 ORDER by 1; - -CREATE TABLE "provider.ping".provsub(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".provsub(data) VALUES ('a'); -INSERT INTO "provider.ping".provsub(data) VALUES ('b'); -SELECT * FROM "provider.ping".provsub ORDER by 1; - -CREATE TABLE "provider.ping".bad(id serial primary key, data text DEFAULT ''); - -\c :subscriber_dsn -CREATE SCHEMA "subscriber.pong"; -CREATE SCHEMA "subscriber2.pong2"; -CREATE SCHEMA provsub; - -CREATE TABLE "subscriber.pong".test_target(id serial primary key, data text DEFAULT ''); -CREATE TABLE "subscriber2.pong2".test_target2(id serial primary key, data text DEFAULT ''); -CREATE TABLE provsub.test_target3(id serial primary key, data text DEFAULT ''); -CREATE TABLE "subscriber.pong".provsub(id serial primary key, data text DEFAULT ''); - --- test replication with initial copy --- add table and sequence to the subscribed replication set -\c :provider_dsn -SELECT * FROM pglogical.create_replication_set('map1', - replicate_insert:=true, - replicate_update:=true, - replicate_delete:=true, - replicate_truncate:=true); - --- distinct name and schema -SELECT * FROM pglogical.replication_set_add_table('map1', '"provider.ping".test_origin', true, nsptarget:='subscriber.pong', reltarget:='test_target'); -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('"provider.ping".test_origin', 'id'), nsptarget:='subscriber.pong', reltarget:='test_target_id_seq'); -- XXX not a dynamic name ... - --- distinct name, same schema -SELECT * FROM pglogical.replication_set_add_table('map1', 'provsub.test_origin3', true, reltarget:='test_target3'); -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('provsub.test_origin3', 'id'), reltarget:='test_target3_id_seq'); -- XXX not a dynamic name ... - --- same name, distinct schema -SELECT * FROM pglogical.replication_set_add_table('map1', '"provider.ping".provsub', true, nsptarget:='subscriber.pong'); -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('"provider.ping".provsub', 'id'), nsptarget:='subscriber.pong'); -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); -SELECT * FROM pglogical.replication_set_seq order by 1,2; -SELECT * FROM pglogical.replication_set_table order by 1,2; - -\c :subscriber_dsn --- init -SELECT * FROM pglogical.create_subscription( - subscription_name := 'sub_map1', - provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', - forward_origins := '{}', - replication_sets := '{map1}'); -SELECT pglogical.wait_for_subscription_sync_complete('sub_map1'); - -SELECT * FROM "subscriber.pong".test_target; -SELECT * FROM provsub.test_target3; -SELECT * FROM "subscriber.pong".provsub; - - --- test resynchronize -\c :subscriber_dsn -DELETE FROM "subscriber.pong".test_target WHERE id > 1; -DELETE FROM provsub.test_target3 WHERE id > 1; -DELETE FROM "subscriber.pong".provsub WHERE id > 1; -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map1', '"subscriber.pong".test_target', true); - -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map1', 'provsub.test_target3', true); -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map1', '"subscriber.pong".provsub', true); -SELECT pglogical.wait_for_table_sync_complete('sub_map1', '"subscriber.pong".test_target'); -SELECT pglogical.wait_for_table_sync_complete('sub_map1', 'provsub.test_target3'); -SELECT pglogical.wait_for_table_sync_complete('sub_map1', '"subscriber.pong".provsub'); -SELECT * FROM "subscriber.pong".test_target; -SELECT * FROM provsub.test_target3; -SELECT * FROM "subscriber.pong".provsub; - - --- test synchronize -\c :subscriber_dsn -CREATE TABLE "subscriber.pong".test_synchronize(id serial primary key, data text DEFAULT ''); -\c :provider_dsn -CREATE TABLE "provider.ping".test_synchronize(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".test_synchronize(data) VALUES ('a'); -SELECT * FROM pglogical.replication_set_add_table('map1', '"provider.ping".test_synchronize', true, nsptarget:='subscriber.pong'); -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('"provider.ping".test_synchronize', 'id'), nsptarget:='subscriber.pong'); -- XXX not a dynamic name ... - -\c :subscriber_dsn -SELECT * FROM pglogical.alter_subscription_synchronize('sub_map1'); -SELECT pglogical.wait_for_table_sync_complete('sub_map1', '"subscriber.pong".test_synchronize'); -SELECT * FROM "subscriber.pong".test_synchronize; - --- test DML replication after init -\c :provider_dsn -INSERT INTO "provider.ping".test_origin(data) VALUES ('c'); -INSERT INTO "provider.ping".test_origin(data) VALUES ('d'); -UPDATE "provider.ping".test_origin SET data = 'data'; -DELETE FROM "provider.ping".test_origin WHERE id < 3; - -INSERT INTO provsub.test_origin3(data) VALUES ('c'); -INSERT INTO provsub.test_origin3(data) VALUES ('d'); -UPDATE provsub.test_origin3 SET data = 'data'; -DELETE FROM provsub.test_origin3 WHERE id < 3; - -INSERT INTO "provider.ping".provsub(data) VALUES ('c'); -INSERT INTO "provider.ping".provsub(data) VALUES ('d'); -UPDATE "provider.ping".provsub SET data = 'data'; -DELETE FROM "provider.ping".provsub WHERE id < 3; -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); -\c :subscriber_dsn -SELECT * FROM "subscriber.pong".test_target; -SELECT * FROM provsub.test_target3; -SELECT * FROM "subscriber.pong".provsub; - --- truncate -\c :provider_dsn -TRUNCATE "provider.ping".test_origin; -TRUNCATE provsub.test_origin3; -TRUNCATE "provider.ping".provsub; -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); -\c :subscriber_dsn -SELECT * FROM "subscriber.pong".test_target; -SELECT * FROM provsub.test_target3; -SELECT * FROM "subscriber.pong".provsub; - --- Merging tables --- test merge data from 2 tables into 1 in distinct sets -\c :subscriber_dsn -CREATE TABLE "subscriber.pong".test_merge(id serial primary key, data text DEFAULT ''); -\c :provider_dsn -CREATE TABLE "provider.ping".test_merge(id serial primary key, data text DEFAULT ''); -INSERT INTO "provider.ping".test_merge(id,data) VALUES (9, 'm'); -INSERT INTO "provider.ping".test_origin(data) VALUES ('n'); -SELECT * FROM "provider.ping".test_merge ORDER by 1; -SELECT * FROM "provider.ping".test_origin ORDER by 1; - -SELECT * FROM pglogical.create_replication_set('map2', - replicate_insert:=true, - replicate_update:=true, - replicate_delete:=true, - replicate_truncate:=true); - -SELECT * FROM pglogical.replication_set_add_table('map2', '"provider.ping".test_merge', true, nsptarget:='subscriber.pong', reltarget:='test_target'); -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); - -\c :subscriber_dsn -SELECT * FROM "subscriber.pong".test_target; -SELECT * FROM pglogical.create_subscription( - subscription_name := 'sub_map2', - provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', - forward_origins := '{}', - replication_sets := '{map2}'); -SELECT pglogical.wait_for_subscription_sync_complete('sub_map2'); -SELECT * FROM "subscriber.pong".test_target; - -TRUNCATE "subscriber.pong".test_target; - --- test resynchronize when multiple origin for the same table (origin indistincts sets -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map1', '"subscriber.pong".test_target', true); -SELECT pglogical.wait_for_table_sync_complete('sub_map1', '"subscriber.pong".test_target'); -SELECT * FROM pglogical.alter_subscription_resynchronize_table('sub_map2', '"subscriber.pong".test_target', false); -SELECT pglogical.wait_for_table_sync_complete('sub_map2', '"subscriber.pong".test_target'); -SELECT * FROM "subscriber.pong".test_target; - --- Splitting --- 1 table replicated with distinct target in 2 distinct sets (a.b -> c.d and a.b -> e.f) -\c :provider_dsn -SELECT * FROM pglogical.replication_set_add_table('map2', '"provider.ping".test_origin', true, nsptarget:='subscriber2.pong2', reltarget:='test_target2'); -SELECT * FROM pglogical.replication_set_add_sequence('map2', pg_get_serial_sequence('"provider.ping".test_origin', 'id'), nsptarget:='subscriber2.pong2', reltarget:='test_target2_id_seq'); -- XXX not a dynamic name ... -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); -\c :subscriber_dsn -SELECT pglogical.wait_for_subscription_sync_complete('sub_map2'); -SELECT * FROM "subscriber2.pong2".test_target2; - --- Not supported cases: --- test merging 2 sequences to the same target: not allowed ! -\c :provider_dsn --- same set -SELECT * FROM pglogical.replication_set_add_sequence('map1', pg_get_serial_sequence('"provider.ping".bad', 'id'), nsptarget:='subscriber.pong', reltarget:='test_target_id_seq'); -- XXX not a dynamic name ... --- distinct set -SELECT * FROM pglogical.replication_set_add_sequence('map2', pg_get_serial_sequence('"provider.ping".bad', 'id'), nsptarget:='subscriber.pong', reltarget:='test_target_id_seq'); -- XXX not a dynamic name ... -DROP TABLE "provider.ping".bad; - --- Merging tables --- test merge data from 2 tables into 1 in the same set: not allowed -\c :provider_dsn -SELECT * FROM pglogical.replication_set_add_table('map1', '"provider.ping".test_origin2', true, nsptarget:='subscriber.pong', reltarget:='test_target'); - --- XXX copy test required ? - --- synchronize sequences -\c :provider_dsn -SELECT pglogical.synchronize_sequence('"provider.ping".test_origin_id_seq'); -SELECT pglogical.synchronize_sequence('provsub.test_origin3_id_seq'); -SELECT pglogical.synchronize_sequence('"provider.ping".provsub_id_seq'); -SELECT pglogical.synchronize_sequence('"provider.ping".test_synchronize_id_seq'); -SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL); - -\c :subscriber_dsn -SELECT N.nspname AS schemaname, C.relname AS tablename, (nextval(C.oid) > 1000) as synced - FROM pg_class C JOIN pg_namespace N ON (N.oid = C.relnamespace) - WHERE C.relkind = 'S' AND C.relname IN ('test_target_id_seq', 'test_target2_id_seq', 'test_target3_id_seq' - ,'provsub_id_seq', 'test_synchronize_id_seq') - ORDER BY 1, 2; - --- show and cleaning -\c :subscriber_dsn -SELECT * FROM pglogical.show_subscription_status('sub_map1'); -SELECT * FROM pglogical.show_subscription_table('sub_map1','"subscriber.pong".test_target'); ---- XXX add more here -SELECT * FROM pglogical.show_subscription_status('sub_map2'); -SELECT * FROM pglogical.drop_subscription('sub_map1'); -SELECT * FROM pglogical.drop_subscription('sub_map2'); - -\c :provider_dsn -SELECT nspname, relname, att_list, has_row_filter, nsptarget, reltarget -FROM pglogical.show_repset_table_info_by_target('subscriber.pong','test_target', ARRAY['map1','map2']) order by 1,2; --- XXX fonction pglogical.table_data_filtered(anyelement,regclass,text[]) ? -SELECT * FROM pglogical.replication_set_seq order by 1,2; -SELECT * FROM pglogical.replication_set_table order by 1,2; -SELECT cache_size,last_value FROM pglogical.sequence_state; -SELECT * FROM pglogical.drop_replication_set('map1'); -SELECT * FROM pglogical.drop_replication_set('map2'); -DROP SCHEMA "provider.ping" CASCADE; -DROP SCHEMA "provider2.ping2" CASCADE; -DROP SCHEMA provsub CASCADE; - -\c :subscriber_dsn -DROP SCHEMA "subscriber.pong" CASCADE; -DROP SCHEMA "subscriber2.pong2" CASCADE; -DROP SCHEMA provsub CASCADE; From 451d5a5cc8b8bacb50fd6c55bbbd896ebbdc619f Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 27 Mar 2020 16:09:46 +0100 Subject: [PATCH 4/9] Revert "synchronize structure only of replicated relations" This reverts commit 52dd586b5a3c1d8668da7131d0117e9055f16c9b. --- Makefile | 4 +- docs/README.md | 15 ++--- expected/relations_only.out | 124 ------------------------------------ pglogical_functions.c | 4 -- pglogical_rpc.c | 56 ---------------- pglogical_rpc.h | 2 - pglogical_sync.c | 110 ++------------------------------ pglogical_sync.h | 16 +---- sql/relations_only.sql | 58 ----------------- 9 files changed, 13 insertions(+), 376 deletions(-) delete mode 100644 expected/relations_only.out delete mode 100644 sql/relations_only.sql diff --git a/Makefile b/Makefile index 5fb1549..79a6b6b 100644 --- a/Makefile +++ b/Makefile @@ -34,8 +34,8 @@ OBJS = pglogical_apply.o pglogical_conflict.o pglogical_manager.o \ SCRIPTS_built = pglogical_create_subscriber REGRESS = preseed infofuncs init_fail init preseed_check basic extended conflict_secondary_unique \ - toasted replication_set add_table relations_only matview bidirectional \ - primary_key interfaces foreign_key functions copy triggers parallel row_filter \ + toasted replication_set add_table matview bidirectional primary_key \ + interfaces foreign_key functions copy triggers parallel row_filter \ row_filter_sampling att_list column_filter apply_delay multiple_upstreams \ node_origin_cascade drop diff --git a/docs/README.md b/docs/README.md index 5b83f5f..f33f7c1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -276,11 +276,10 @@ Nodes can be added and removed dynamically using the SQL interfaces. ### Subscription management - `pglogical.create_subscription(subscription_name name, provider_dsn text, - replication_sets text[], synchronize_structure text(none,all,relations_only), + replication_sets text[], synchronize_structure text(none,all), synchronize_data boolean, forward_origins text[], apply_delay interval)` - Creates a subscription from current node to the provider node, with option to - synchronize part or all the structure. Command does not block, just initiates - the action. + Creates a subscription from current node to the provider node. Command does + not block, just initiates the action. Parameters: - `subscription_name` - name of the subscription, must be unique @@ -288,9 +287,7 @@ Nodes can be added and removed dynamically using the SQL interfaces. - `replication_sets` - array of replication sets to subscribe to, these must already exist, default is "{default,default_insert_only,ddl_sql}" - `synchronize_structure` - specifies if to synchronize structure from - provider to the subscriber, default `none`. `all` for all objects, - `relations_only` for replicated tables and sequences only (in this last case - schemas themselves are not created on the subscriber). + provider to the subscriber, default `none`. `all` for all objects. - `synchronize_data` - specifies if to synchronize data from provider to the subscriber, default true - `forward_origins` - array of origin names to forward, currently only @@ -310,10 +307,6 @@ Nodes can be added and removed dynamically using the SQL interfaces. pglogical is used as part of [synchronous replication](#synchronous-replication) setup. - Pglogical currently executes `pg_dump` with a list of `-t TABLE/SEQUENCE` - parameter to synchronize relations only. The limitation of the system apply - and can limit the length of the command line. - Use `pglogical.wait_for_subscription_sync_complete(sub_name)` to wait for the subscription to asynchronously start replicating and complete any needed schema and/or data sync. diff --git a/expected/relations_only.out b/expected/relations_only.out deleted file mode 100644 index 0426dcf..0000000 --- a/expected/relations_only.out +++ /dev/null @@ -1,124 +0,0 @@ --- This should be done with pg_regress's --create-role option --- but it's blocked by bug 37906 -SELECT * FROM pglogical_regress_variables() -\gset -\c :provider_dsn -SET client_min_messages = 'warning'; -CREATE SCHEMA relations_only; -CREATE TABLE relations_only.rel_only(id int primary key); -CREATE TABLE relations_only.rel_seq(id serial primary key); -CREATE SEQUENCE relations_only.seq_only; -CREATE TABLE relations_only.no_rel_only(id int primary key); -CREATE TABLE relations_only.no_rel_seq(id serial primary key); -CREATE SEQUENCE relations_only.no_seq_only; -SELECT * FROM pglogical.create_replication_set('repset_relations_only'); - create_replication_set ------------------------- - 3691617396 -(1 row) - -SELECT * FROM pglogical.replication_set_add_table('repset_relations_only', 'relations_only.rel_only', true); - replication_set_add_table ---------------------------- - t -(1 row) - -SELECT * FROM pglogical.replication_set_add_table('repset_relations_only', 'relations_only.rel_seq', true); - replication_set_add_table ---------------------------- - t -(1 row) - -SELECT * FROM pglogical.replication_set_add_sequence('repset_relations_only', 'relations_only.seq_only', true); - replication_set_add_sequence ------------------------------- - t -(1 row) - --- test adding a sequence with add_all_sequences (special case to get schema and --- relation names) -CREATE SEQUENCE test_sequence; -SELECT * FROM pglogical.replication_set_add_all_sequences('repset_relations_only', '{public}'); - replication_set_add_all_sequences ------------------------------------ - t -(1 row) - -\c :subscriber_dsn -SET client_min_messages = 'warning'; -CREATE SCHEMA relations_only; -BEGIN; -SELECT * FROM pglogical.create_subscription( - subscription_name := 'test_subscription_relations_only', - provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'relations_only', - forward_origins := '{}', - replication_sets := '{repset_relations_only}'); - create_subscription ---------------------- - 3241649517 -(1 row) - -COMMIT; -BEGIN; -SET LOCAL statement_timeout = '30s'; -SELECT pglogical.wait_for_subscription_sync_complete('test_subscription_relations_only'); - wait_for_subscription_sync_complete -------------------------------------- - -(1 row) - -COMMIT; -select table_name from information_schema.tables where table_schema = 'relations_only' order by 1; - table_name ------------- - rel_only - rel_seq -(2 rows) - -select sequence_name from information_schema.sequences where sequence_schema = 'relations_only' order by 1; - sequence_name ----------------- - rel_seq_id_seq - seq_only -(2 rows) - -select sequence_name from information_schema.sequences where sequence_name = 'test_sequence' order by 1; - sequence_name ---------------- - test_sequence -(1 row) - -SELECT sync_kind, sync_subid, sync_nspname, sync_relname, sync_status IN ('y', 'r') FROM pglogical.local_sync_status ORDER BY 2,3,4; - sync_kind | sync_subid | sync_nspname | sync_relname | ?column? ------------+------------+----------------+--------------+---------- - f | 3241649517 | relations_only | rel_only | t - f | 3241649517 | relations_only | rel_seq | t - l | 3241649517 | | | t - f | 3848008564 | | | t -(4 rows) - -SELECT * FROM pglogical.drop_subscription('test_subscription_relations_only'); - drop_subscription -------------------- - 1 -(1 row) - -DROP SCHEMA relations_only CASCADE; -DROP SEQUENCE test_sequence CASCADE; -\c :provider_dsn -SELECT * FROM pglogical.drop_replication_set('repset_relations_only'); - drop_replication_set ----------------------- - t -(1 row) - -DROP SCHEMA relations_only CASCADE; -NOTICE: drop cascades to 6 other objects -DETAIL: drop cascades to table relations_only.rel_only -drop cascades to table relations_only.rel_seq -drop cascades to sequence relations_only.seq_only -drop cascades to table relations_only.no_rel_only -drop cascades to table relations_only.no_rel_seq -drop cascades to sequence relations_only.no_seq_only -DROP SEQUENCE test_sequence CASCADE; diff --git a/pglogical_functions.c b/pglogical_functions.c index dce3485..1e65da9 100644 --- a/pglogical_functions.c +++ b/pglogical_functions.c @@ -517,12 +517,8 @@ pglogical_create_subscription(PG_FUNCTION_ARGS) if (SyncStructureAll(sync_structure) && sync_data) sync.kind = SYNC_KIND_FULL; - else if (SyncStructureRelOnly(sync_structure) && sync_data) - sync.kind = SYNC_KIND_FULL_REL; else if (SyncStructureAll(sync_structure)) sync.kind = SYNC_KIND_STRUCTURE; - else if (SyncStructureRelOnly(sync_structure)) - sync.kind = SYNC_KIND_STRUCTURE_REL; else if (sync_data) sync.kind = SYNC_KIND_DATA; else diff --git a/pglogical_rpc.c b/pglogical_rpc.c index b7fd467..ddb2c12 100644 --- a/pglogical_rpc.c +++ b/pglogical_rpc.c @@ -181,62 +181,6 @@ pg_logical_get_remote_repset_table(PGconn *conn, RangeVar *rv, return remoterel; } -/* - * Fetch list of sequences that are grouped in specified replication sets. - */ -List * -pg_logical_get_remote_repset_sequences(PGconn *conn, List *replication_sets) -{ - PGresult *res; - int i; - List *sequences = NIL; - ListCell *lc; - bool first = true; - StringInfoData query; - StringInfoData repsetarr; - - initStringInfo(&repsetarr); - foreach (lc, replication_sets) - { - char *repset_name = lfirst(lc); - - if (first) - first = false; - else - appendStringInfoChar(&repsetarr, ','); - - appendStringInfo(&repsetarr, "%s", - PQescapeLiteral(conn, repset_name, strlen(repset_name))); - } - - initStringInfo(&query); - // TODO limit to pglogical >= 2.3 ? - appendStringInfo(&query, - "select c.relnamespace::regnamespace as set_nspname, c.relname as set_seqname FROM pglogical.replication_set_seq r " - "join pg_class c on (c.oid = r.set_seqoid)," - "pglogical.replication_set s, " - "pglogical.local_node n " - "WHERE s.set_nodeid = n.node_id AND s.set_id = r.set_id " - "AND s.set_name = ANY(ARRAY[%s])", repsetarr.data); - - res = PQexec(conn, query.data); - /* TODO: better error message? */ - if (PQresultStatus(res) != PGRES_TUPLES_OK) - elog(ERROR, "could not get sequence list: %s", PQresultErrorMessage(res)); - - for (i = 0; i < PQntuples(res); i++) - { - RangeVar *rv; - rv = makeRangeVar(pstrdup(PQgetvalue(res, i, 0)), - pstrdup(PQgetvalue(res, i, 1)), -1); - - sequences = lappend(sequences, rv); - } - - PQclear(res); - - return sequences; -} /* * Is the remote slot active?. diff --git a/pglogical_rpc.h b/pglogical_rpc.h index fbd80af..fed9cad 100644 --- a/pglogical_rpc.h +++ b/pglogical_rpc.h @@ -19,8 +19,6 @@ extern List *pg_logical_get_remote_repset_tables(PGconn *conn, List *replication_sets); extern PGLogicalRemoteRel *pg_logical_get_remote_repset_table(PGconn *conn, RangeVar *rv, List *replication_sets); -extern List *pg_logical_get_remote_repset_sequences(PGconn *conn, - List *replication_sets); extern bool pglogical_remote_slot_active(PGconn *conn, const char *slot_name); extern void pglogical_drop_remote_slot(PGconn *conn, const char *slot_name); diff --git a/pglogical_sync.c b/pglogical_sync.c index 6935dd2..10e2e3c 100644 --- a/pglogical_sync.c +++ b/pglogical_sync.c @@ -87,13 +87,12 @@ static PGLogicalSyncWorker *MySyncWorker = NULL; static void dump_structure(PGLogicalSubscription *sub, const char *destfile, - const char *snapshot, const char kind) + const char *snapshot) { char pg_dump[MAXPGPATH]; uint32 version; int res; StringInfoData schema_filter; - StringInfoData table_filter; StringInfoData command; if (find_other_exec_version(my_exec_path, PGDUMP_BINARY, &version, pg_dump) != 0) @@ -113,41 +112,10 @@ dump_structure(PGLogicalSubscription *sub, const char *destfile, appendStringInfoString(&schema_filter, " -N pglogical_origin"); CommitTransactionCommand(); - /* - * Filter tables and sequences using "pg_dump -t" switch, based on - * replication set tables and sequences from origin node. - * - * Creates new connection to origin. - * - * XXX CREATE SCHEMA is not done by pg_dump when using -t switch - * - * XXX add -T switch option ? - * - */ - initStringInfo(&table_filter); - if (SyncKindStructureRelations(kind)) - { - List *objects; - ListCell *lc; - - objects = list_replication_sets_objects(sub->origin_if->dsn, - sub->name, snapshot, - sub->replication_sets); - - /* Get every object and add it to the -t switch */ - foreach (lc, objects) - { - char *object_name = lfirst(lc); - appendStringInfo(&table_filter, " -t %s", - object_name); - } - } - initStringInfo(&command); - appendStringInfo(&command, "\"%s\" --strict-names --snapshot=\"%s\" %s %s -s -F c -f \"%s\" \"%s\"", - pg_dump, snapshot, - schema_filter.data, table_filter.data, - destfile, sub->origin_if->dsn); + appendStringInfo(&command, "\"%s\" --snapshot=\"%s\" %s -s -F c -f \"%s\" \"%s\"", + pg_dump, snapshot, schema_filter.data, destfile, + sub->origin_if->dsn); res = system(command.data); if (res != 0) @@ -591,74 +559,6 @@ copy_table_data(PGconn *origin_conn, PGconn *target_conn, remoterel->nspname, remoterel->relname); } -/* - * Returns the list of schema qualified name of replicated tables and sequences - * from provider. - * - * Creates new connection to origin. - */ -List * -list_replication_sets_objects(const char *dsn, const char *name, const char *snapshot, List *replication_sets) -{ - PGconn *origin_conn; - List *objects; - List *res = NIL; - ListCell *lc; - - /* Connect to origin node. */ - origin_conn = pglogical_connect(dsn, name, "copy"); - start_copy_origin_tx(origin_conn, snapshot); - - /* Get tables from our replication sets from origin node. */ - objects = pg_logical_get_remote_repset_tables(origin_conn, - replication_sets); - - /* And append them to the list */ - foreach (lc, objects) - { - PGLogicalRemoteRel *remoterel = lfirst(lc); - StringInfoData object; - - initStringInfo(&object); - appendStringInfo(&object, "%s.%s", - PQescapeLiteral(origin_conn, remoterel->nspname, - strlen(remoterel->nspname)), - PQescapeLiteral(origin_conn, remoterel->relname, - strlen(remoterel->relname))); - res = lappend(res, object.data); - - /* XXX probably not required here */ - CHECK_FOR_INTERRUPTS(); - } - - /* Get sequences from our replication sets from origin node. */ - objects = pg_logical_get_remote_repset_sequences(origin_conn, - replication_sets); - - /* And append them to the list */ - foreach (lc, objects) - { - RangeVar *rv = lfirst(lc); - StringInfoData object; - - initStringInfo(&object); - appendStringInfo(&object, "%s.%s", - PQescapeLiteral(origin_conn, rv->schemaname, - strlen(rv->schemaname)), - PQescapeLiteral(origin_conn, rv->relname, - strlen(rv->relname))); - res = lappend(res, object.data); - - /* XXX probably not required here */ - CHECK_FOR_INTERRUPTS(); - } - - /* Finish the transaction and disconnect. */ - finish_copy_origin_tx(origin_conn); - - return res; -} - /* * Copy data from origin node to target node. * @@ -917,7 +817,7 @@ pglogical_sync_subscription(PGLogicalSubscription *sub) CommitTransactionCommand(); /* Dump structure to temp storage. */ - dump_structure(sub, tmpfile, snapshot, sync->kind); + dump_structure(sub, tmpfile, snapshot); /* Restore base pre-data structure (types, tables, etc). */ restore_structure(sub, tmpfile, "pre-data"); diff --git a/pglogical_sync.h b/pglogical_sync.h index 33724d9..b2ac270 100644 --- a/pglogical_sync.h +++ b/pglogical_sync.h @@ -29,29 +29,20 @@ typedef struct PGLogicalSyncStatus * synchronization coordination */ } PGLogicalSyncStatus; -/* XXX use a bitmap flag instead ? */ #define SYNC_KIND_INIT 'i' #define SYNC_KIND_FULL 'f' -#define SYNC_KIND_FULL_REL 'l' #define SYNC_KIND_STRUCTURE 's' -#define SYNC_KIND_STRUCTURE_REL 'r' #define SYNC_KIND_DATA 'd' #define SyncKindData(kind) \ - (kind == SYNC_KIND_FULL || kind == SYNC_KIND_FULL_REL || kind == SYNC_KIND_DATA) + (kind == SYNC_KIND_FULL || kind == SYNC_KIND_DATA) #define SyncKindStructure(kind) \ - (kind == SYNC_KIND_FULL || kind == SYNC_KIND_FULL_REL || kind == SYNC_KIND_STRUCTURE || kind == SYNC_KIND_STRUCTURE_REL) - -#define SyncKindStructureRelations(kind) \ - (kind == SYNC_KIND_FULL_REL || kind == SYNC_KIND_STRUCTURE_REL) + (kind == SYNC_KIND_FULL || kind == SYNC_KIND_STRUCTURE) #define SyncStructureAll(sync_structure) \ (strcmp(sync_structure, "all") == 0) -#define SyncStructureRelOnly(sync_structure) \ - (strcmp(sync_structure, "relations_only") == 0) - /* XXX not used but document the sync_structure enum ... */ #define SyncStructureNone(sync_structure) \ (strcmp(sync_structure, "none") == 0) @@ -103,9 +94,6 @@ extern bool wait_for_sync_status_change(Oid subid, const char *nspname, extern void truncate_table(char *nspname, char *relname); extern List *get_subscription_tables(Oid subid); -List *list_replication_sets_objects(const char *dsn, const char *name, - const char *snapshot, - List *replication_sets); #endif /* PGLOGICAL_SYNC_H */ diff --git a/sql/relations_only.sql b/sql/relations_only.sql deleted file mode 100644 index b98805e..0000000 --- a/sql/relations_only.sql +++ /dev/null @@ -1,58 +0,0 @@ --- This should be done with pg_regress's --create-role option --- but it's blocked by bug 37906 -SELECT * FROM pglogical_regress_variables() -\gset - -\c :provider_dsn -SET client_min_messages = 'warning'; -CREATE SCHEMA relations_only; -CREATE TABLE relations_only.rel_only(id int primary key); -CREATE TABLE relations_only.rel_seq(id serial primary key); -CREATE SEQUENCE relations_only.seq_only; - -CREATE TABLE relations_only.no_rel_only(id int primary key); -CREATE TABLE relations_only.no_rel_seq(id serial primary key); -CREATE SEQUENCE relations_only.no_seq_only; - -SELECT * FROM pglogical.create_replication_set('repset_relations_only'); -SELECT * FROM pglogical.replication_set_add_table('repset_relations_only', 'relations_only.rel_only', true); -SELECT * FROM pglogical.replication_set_add_table('repset_relations_only', 'relations_only.rel_seq', true); -SELECT * FROM pglogical.replication_set_add_sequence('repset_relations_only', 'relations_only.seq_only', true); - --- test adding a sequence with add_all_sequences (special case to get schema and --- relation names) -CREATE SEQUENCE test_sequence; -SELECT * FROM pglogical.replication_set_add_all_sequences('repset_relations_only', '{public}'); - -\c :subscriber_dsn -SET client_min_messages = 'warning'; -CREATE SCHEMA relations_only; - -BEGIN; -SELECT * FROM pglogical.create_subscription( - subscription_name := 'test_subscription_relations_only', - provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'relations_only', - forward_origins := '{}', - replication_sets := '{repset_relations_only}'); -COMMIT; - -BEGIN; -SET LOCAL statement_timeout = '30s'; -SELECT pglogical.wait_for_subscription_sync_complete('test_subscription_relations_only'); -COMMIT; - -select table_name from information_schema.tables where table_schema = 'relations_only' order by 1; -select sequence_name from information_schema.sequences where sequence_schema = 'relations_only' order by 1; -select sequence_name from information_schema.sequences where sequence_name = 'test_sequence' order by 1; - -SELECT sync_kind, sync_subid, sync_nspname, sync_relname, sync_status IN ('y', 'r') FROM pglogical.local_sync_status ORDER BY 2,3,4; - -SELECT * FROM pglogical.drop_subscription('test_subscription_relations_only'); -DROP SCHEMA relations_only CASCADE; -DROP SEQUENCE test_sequence CASCADE; - -\c :provider_dsn -SELECT * FROM pglogical.drop_replication_set('repset_relations_only'); -DROP SCHEMA relations_only CASCADE; -DROP SEQUENCE test_sequence CASCADE; From 245faed8009fea3ddfca123de17ede2a29de6995 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 27 Mar 2020 16:26:28 +0100 Subject: [PATCH 5/9] Revert "Document and update test for synchronize_structure as text" This reverts commit 38c099a0885bb6b0cf546279de0a215994062368. --- docs/README.md | 4 ++-- expected/apply_delay.out | 2 +- expected/bidirectional.out | 2 +- expected/init.out | 2 +- expected/multiple_upstreams.out | 4 ++-- expected/multiple_upstreams_1.out | 4 ++-- expected/node_origin_cascade.out | 2 +- expected/parallel.out | 4 ++-- pglogical_create_subscriber.c | 2 +- pglogical_functions.c | 6 +++--- pglogical_sync.h | 7 ------- sql/apply_delay.sql | 2 +- sql/bidirectional.sql | 2 +- sql/init.sql | 2 +- sql/multiple_upstreams.sql | 4 ++-- sql/node_origin_cascade.sql | 2 +- sql/parallel.sql | 4 ++-- t/020_non_default_replication_set.pl | 2 +- t/030_pglogical_daylight_times_switching.pl | 4 ++-- t/040_pglogical_sync_during_write.pl | 2 +- 20 files changed, 28 insertions(+), 35 deletions(-) diff --git a/docs/README.md b/docs/README.md index f33f7c1..0a26028 100644 --- a/docs/README.md +++ b/docs/README.md @@ -276,7 +276,7 @@ Nodes can be added and removed dynamically using the SQL interfaces. ### Subscription management - `pglogical.create_subscription(subscription_name name, provider_dsn text, - replication_sets text[], synchronize_structure text(none,all), + replication_sets text[], synchronize_structure boolean, synchronize_data boolean, forward_origins text[], apply_delay interval)` Creates a subscription from current node to the provider node. Command does not block, just initiates the action. @@ -287,7 +287,7 @@ Nodes can be added and removed dynamically using the SQL interfaces. - `replication_sets` - array of replication sets to subscribe to, these must already exist, default is "{default,default_insert_only,ddl_sql}" - `synchronize_structure` - specifies if to synchronize structure from - provider to the subscriber, default `none`. `all` for all objects. + provider to the subscriber, default false - `synchronize_data` - specifies if to synchronize data from provider to the subscriber, default true - `forward_origins` - array of origin names to forward, currently only diff --git a/expected/apply_delay.out b/expected/apply_delay.out index 3c2c925..9ccd714 100644 --- a/expected/apply_delay.out +++ b/expected/apply_delay.out @@ -25,7 +25,7 @@ SELECT * FROM pglogical.create_subscription( provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', replication_sets := '{delay}', forward_origins := '{}', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false, apply_delay := int2interval(2) -- 2 seconds ); diff --git a/expected/bidirectional.out b/expected/bidirectional.out index aeda17f..556ec62 100644 --- a/expected/bidirectional.out +++ b/expected/bidirectional.out @@ -18,7 +18,7 @@ END;$$; SELECT * FROM pglogical.create_subscription( subscription_name := 'test_bidirectional', provider_dsn := (SELECT subscriber_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false, forward_origins := '{}'); create_subscription diff --git a/expected/init.out b/expected/init.out index 98a4f30..fe5269d 100644 --- a/expected/init.out +++ b/expected/init.out @@ -86,7 +86,7 @@ BEGIN; SELECT * FROM pglogical.create_subscription( subscription_name := 'test_subscription', provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'all', + synchronize_structure := true, forward_origins := '{}'); create_subscription --------------------- diff --git a/expected/multiple_upstreams.out b/expected/multiple_upstreams.out index 0a8a435..e626f7a 100644 --- a/expected/multiple_upstreams.out +++ b/expected/multiple_upstreams.out @@ -65,11 +65,11 @@ SELECT * FROM pglogical.replication_set_add_table('default', 'multi_ups_tbl'); \c :subscriber_dsn -- We'll use the already existing pglogical node --- notice synchronize_structure as 'none' when table definition already exists +-- notice synchronize_structure as false when table definition already exists SELECT * FROM pglogical.create_subscription( subscription_name := 'test_subscription1', provider_dsn := (SELECT provider1_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', + synchronize_structure := false, forward_origins := '{}'); create_subscription --------------------- diff --git a/expected/multiple_upstreams_1.out b/expected/multiple_upstreams_1.out index 3084e23..c61547e 100644 --- a/expected/multiple_upstreams_1.out +++ b/expected/multiple_upstreams_1.out @@ -64,12 +64,12 @@ SELECT * FROM pglogical.replication_set_add_table('default', 'multi_ups_tbl'); \c :subscriber_dsn -- We'll use the already existing pglogical node --- notice synchronize_structure as 'none' when table definition already exists +-- notice synchronize_structure as false when table definition already exists BEGIN; SELECT * FROM pglogical.create_subscription( subscription_name := 'test_subscription1', provider_dsn := (SELECT provider1_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', + synchronize_structure := false, forward_origins := '{}'); create_subscription --------------------- diff --git a/expected/node_origin_cascade.out b/expected/node_origin_cascade.out index 38e77c9..b5fbf54 100644 --- a/expected/node_origin_cascade.out +++ b/expected/node_origin_cascade.out @@ -41,7 +41,7 @@ BEGIN; SELECT * FROM pglogical.create_subscription( subscription_name := 'test_orig_subscription', provider_dsn := (SELECT orig_provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', + synchronize_structure := false, forward_origins := '{}'); create_subscription --------------------- diff --git a/expected/parallel.out b/expected/parallel.out index 2a73c66..4fec3ba 100644 --- a/expected/parallel.out +++ b/expected/parallel.out @@ -13,7 +13,7 @@ SELECT * FROM pglogical.create_subscription( provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', replication_sets := '{parallel,default}', forward_origins := '{}', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false ); ERROR: existing subscription "test_subscription" to node "test_provider" already subscribes to replication set "default" @@ -22,7 +22,7 @@ SELECT * FROM pglogical.create_subscription( provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', replication_sets := '{parallel}', forward_origins := '{}', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false ); create_subscription diff --git a/pglogical_create_subscriber.c b/pglogical_create_subscriber.c index def472f..0f9fd57 100644 --- a/pglogical_create_subscriber.c +++ b/pglogical_create_subscriber.c @@ -1114,7 +1114,7 @@ pglogical_subscribe(PGconn *conn, char *subscriber_name, char *subscriber_dsn, "subscription_name := %s, provider_dsn := %s, " "replication_sets := %s, " "apply_delay := '%d seconds'::interval, " - "synchronize_structure := 'none', " + "synchronize_structure := false, " "synchronize_data := false, " "force_text_transfer := '%s');", PQescapeLiteral(conn, subscriber_name, strlen(subscriber_name)), diff --git a/pglogical_functions.c b/pglogical_functions.c index 1e65da9..4301d1c 100644 --- a/pglogical_functions.c +++ b/pglogical_functions.c @@ -389,7 +389,7 @@ pglogical_create_subscription(PG_FUNCTION_ARGS) char *sub_name = NameStr(*PG_GETARG_NAME(0)); char *provider_dsn = text_to_cstring(PG_GETARG_TEXT_PP(1)); ArrayType *rep_set_names = PG_GETARG_ARRAYTYPE_P(2); - char *sync_structure = text_to_cstring(PG_GETARG_TEXT_PP(3)); + bool sync_structure = PG_GETARG_BOOL(3); bool sync_data = PG_GETARG_BOOL(4); ArrayType *forward_origin_names = PG_GETARG_ARRAYTYPE_P(5); Interval *apply_delay = PG_GETARG_INTERVAL_P(6); @@ -515,9 +515,9 @@ pglogical_create_subscription(PG_FUNCTION_ARGS) /* Create synchronization status for the subscription. */ memset(&sync, 0, sizeof(PGLogicalSyncStatus)); - if (SyncStructureAll(sync_structure) && sync_data) + if (sync_structure && sync_data) sync.kind = SYNC_KIND_FULL; - else if (SyncStructureAll(sync_structure)) + else if (sync_structure) sync.kind = SYNC_KIND_STRUCTURE; else if (sync_data) sync.kind = SYNC_KIND_DATA; diff --git a/pglogical_sync.h b/pglogical_sync.h index b2ac270..c4cd77a 100644 --- a/pglogical_sync.h +++ b/pglogical_sync.h @@ -40,13 +40,6 @@ typedef struct PGLogicalSyncStatus #define SyncKindStructure(kind) \ (kind == SYNC_KIND_FULL || kind == SYNC_KIND_STRUCTURE) -#define SyncStructureAll(sync_structure) \ - (strcmp(sync_structure, "all") == 0) - -/* XXX not used but document the sync_structure enum ... */ -#define SyncStructureNone(sync_structure) \ - (strcmp(sync_structure, "none") == 0) - #define SYNC_STATUS_NONE '\0' /* No sync. */ #define SYNC_STATUS_INIT 'i' /* Ask for sync. */ #define SYNC_STATUS_STRUCTURE 's' /* Sync structure */ diff --git a/sql/apply_delay.sql b/sql/apply_delay.sql index 4b64bd7..40f8e39 100644 --- a/sql/apply_delay.sql +++ b/sql/apply_delay.sql @@ -21,7 +21,7 @@ SELECT * FROM pglogical.create_subscription( provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', replication_sets := '{delay}', forward_origins := '{}', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false, apply_delay := int2interval(2) -- 2 seconds ); diff --git a/sql/bidirectional.sql b/sql/bidirectional.sql index b4917ed..8fddd4b 100644 --- a/sql/bidirectional.sql +++ b/sql/bidirectional.sql @@ -17,7 +17,7 @@ END;$$; SELECT * FROM pglogical.create_subscription( subscription_name := 'test_bidirectional', provider_dsn := (SELECT subscriber_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false, forward_origins := '{}'); diff --git a/sql/init.sql b/sql/init.sql index a9a9b1c..b6caa8f 100644 --- a/sql/init.sql +++ b/sql/init.sql @@ -83,7 +83,7 @@ BEGIN; SELECT * FROM pglogical.create_subscription( subscription_name := 'test_subscription', provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'all', + synchronize_structure := true, forward_origins := '{}'); /* * Remove the function we added in preseed because otherwise the restore of diff --git a/sql/multiple_upstreams.sql b/sql/multiple_upstreams.sql index 418dd0e..61a26ed 100644 --- a/sql/multiple_upstreams.sql +++ b/sql/multiple_upstreams.sql @@ -50,11 +50,11 @@ SELECT * FROM pglogical.replication_set_add_table('default', 'multi_ups_tbl'); \c :subscriber_dsn -- We'll use the already existing pglogical node --- notice synchronize_structure as 'none' when table definition already exists +-- notice synchronize_structure as false when table definition already exists SELECT * FROM pglogical.create_subscription( subscription_name := 'test_subscription1', provider_dsn := (SELECT provider1_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', + synchronize_structure := false, forward_origins := '{}'); BEGIN; diff --git a/sql/node_origin_cascade.sql b/sql/node_origin_cascade.sql index cd82cd6..323c601 100644 --- a/sql/node_origin_cascade.sql +++ b/sql/node_origin_cascade.sql @@ -40,7 +40,7 @@ BEGIN; SELECT * FROM pglogical.create_subscription( subscription_name := 'test_orig_subscription', provider_dsn := (SELECT orig_provider_dsn FROM pglogical_regress_variables()) || ' user=super', - synchronize_structure := 'none', + synchronize_structure := false, forward_origins := '{}'); COMMIT; diff --git a/sql/parallel.sql b/sql/parallel.sql index 874cc5f..d4e44ac 100644 --- a/sql/parallel.sql +++ b/sql/parallel.sql @@ -12,7 +12,7 @@ SELECT * FROM pglogical.create_subscription( provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', replication_sets := '{parallel,default}', forward_origins := '{}', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false ); @@ -21,7 +21,7 @@ SELECT * FROM pglogical.create_subscription( provider_dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super', replication_sets := '{parallel}', forward_origins := '{}', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false ); diff --git a/t/020_non_default_replication_set.pl b/t/020_non_default_replication_set.pl index dc97d56..fcb54e3 100755 --- a/t/020_non_default_replication_set.pl +++ b/t/020_non_default_replication_set.pl @@ -61,7 +61,7 @@ provider_dsn := '$PROVIDER_DSN', replication_sets := '{delay}', forward_origins := '{}', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false )"; diff --git a/t/030_pglogical_daylight_times_switching.pl b/t/030_pglogical_daylight_times_switching.pl index 54562fd..5138f57 100755 --- a/t/030_pglogical_daylight_times_switching.pl +++ b/t/030_pglogical_daylight_times_switching.pl @@ -79,7 +79,7 @@ subscription_name := 'test_subscription', provider_dsn := '$PROVIDER_DSN', forward_origins := '{}', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false )"; @@ -89,7 +89,7 @@ provider_dsn := '$PROVIDER_DSN', replication_sets := '{delay}', forward_origins := '{}', - synchronize_structure := 'none', + synchronize_structure := false, synchronize_data := false, apply_delay := int2interval(1) -- 1 seconds )"; diff --git a/t/040_pglogical_sync_during_write.pl b/t/040_pglogical_sync_during_write.pl index cf94ace..16a8ead 100644 --- a/t/040_pglogical_sync_during_write.pl +++ b/t/040_pglogical_sync_during_write.pl @@ -100,7 +100,7 @@ $node_subscriber->safe_psql($dbname, "SELECT pglogical.create_subscription( subscription_name := 'test_subscription', - synchronize_structure := 'all', + synchronize_structure := true, synchronize_data := true, provider_dsn := '$provider_connstr dbname=$dbname user=$super_user' );"); From 12263608f31d8c5c0db8c15f0ef4c2536f0b9849 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 28 Mar 2020 09:46:45 +0100 Subject: [PATCH 6/9] Set version number to 2.3.1 and add upgrade files --- Makefile | 5 +- expected/init.out | 2 +- pglogical--2.2.2--2.3.1.sql | 1 + pglogical--2.3.0--2.3.1.sql | 9 ++ pglogical--2.3.1.sql | 249 ++++++++++++++++++++++++++++++++++++ pglogical.h | 4 +- 6 files changed, 266 insertions(+), 4 deletions(-) create mode 100644 pglogical--2.2.2--2.3.1.sql create mode 100644 pglogical--2.3.0--2.3.1.sql create mode 100644 pglogical--2.3.1.sql diff --git a/Makefile b/Makefile index 79a6b6b..3908896 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,10 @@ DATA = pglogical--1.0.0.sql pglogical--1.0.0--1.0.1.sql \ pglogical--2.2.0--2.2.1.sql pglogical--2.2.1.sql \ pglogical--2.2.1--2.2.2.sql pglogical--2.2.2.sql \ pglogical--2.2.2--2.3.0.sql \ - pglogical--2.3.0.sql + pglogical--2.2.2--2.3.1.sql \ + pglogical--2.3.0.sql \ + pglogical--2.3.0--2.3.1.sql \ + pglogical--2.3.1.sql OBJS = pglogical_apply.o pglogical_conflict.o pglogical_manager.o \ pglogical.o pglogical_node.o pglogical_relcache.o \ diff --git a/expected/init.out b/expected/init.out index fe5269d..871fde9 100644 --- a/expected/init.out +++ b/expected/init.out @@ -58,7 +58,7 @@ ALTER EXTENSION pglogical UPDATE; List of installed extensions Name | Version | Schema | Description -----------+---------+-----------+-------------------------------- - pglogical | 2.3.0 | pglogical | PostgreSQL Logical Replication + pglogical | 2.3.1 | pglogical | PostgreSQL Logical Replication (1 row) SELECT * FROM pglogical.create_node(node_name := 'test_provider', dsn := (SELECT provider_dsn FROM pglogical_regress_variables()) || ' user=super'); diff --git a/pglogical--2.2.2--2.3.1.sql b/pglogical--2.2.2--2.3.1.sql new file mode 100644 index 0000000..e290e89 --- /dev/null +++ b/pglogical--2.2.2--2.3.1.sql @@ -0,0 +1 @@ +ALTER TABLE pglogical.subscription ADD COLUMN sub_force_text_transfer boolean NOT NULL DEFAULT 'f'; diff --git a/pglogical--2.3.0--2.3.1.sql b/pglogical--2.3.0--2.3.1.sql new file mode 100644 index 0000000..fe2e344 --- /dev/null +++ b/pglogical--2.3.0--2.3.1.sql @@ -0,0 +1,9 @@ +DROP FUNCTION pglogical.create_subscription(subscription_name name, provider_dsn text, + replication_sets text[], synchronize_structure text, synchronize_data boolean, + forward_origins text[], apply_delay interval, force_text_transfer boolean); + +CREATE FUNCTION pglogical.create_subscription(subscription_name name, provider_dsn text, + replication_sets text[] = '{default,default_insert_only,ddl_sql}', synchronize_structure boolean = false, + synchronize_data boolean = true, forward_origins text[] = '{all}', apply_delay interval DEFAULT '0', + force_text_transfer boolean = false) +RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_create_subscription'; diff --git a/pglogical--2.3.1.sql b/pglogical--2.3.1.sql new file mode 100644 index 0000000..692107b --- /dev/null +++ b/pglogical--2.3.1.sql @@ -0,0 +1,249 @@ +\echo Use "CREATE EXTENSION pglogical" to load this file. \quit + +CREATE TABLE pglogical.node ( + node_id oid NOT NULL PRIMARY KEY, + node_name name NOT NULL UNIQUE +) WITH (user_catalog_table=true); + +CREATE TABLE pglogical.node_interface ( + if_id oid NOT NULL PRIMARY KEY, + if_name name NOT NULL, -- default same as node name + if_nodeid oid REFERENCES node(node_id), + if_dsn text NOT NULL, + UNIQUE (if_nodeid, if_name) +); + +CREATE TABLE pglogical.local_node ( + node_id oid PRIMARY KEY REFERENCES node(node_id), + node_local_interface oid NOT NULL REFERENCES node_interface(if_id) +); + +CREATE TABLE pglogical.subscription ( + sub_id oid NOT NULL PRIMARY KEY, + sub_name name NOT NULL UNIQUE, + sub_origin oid NOT NULL REFERENCES node(node_id), + sub_target oid NOT NULL REFERENCES node(node_id), + sub_origin_if oid NOT NULL REFERENCES node_interface(if_id), + sub_target_if oid NOT NULL REFERENCES node_interface(if_id), + sub_enabled boolean NOT NULL DEFAULT true, + sub_slot_name name NOT NULL, + sub_replication_sets text[], + sub_forward_origins text[], + sub_apply_delay interval NOT NULL DEFAULT '0', + sub_force_text_transfer boolean NOT NULL DEFAULT 'f' +); + +CREATE TABLE pglogical.local_sync_status ( + sync_kind "char" NOT NULL CHECK (sync_kind IN ('i', 's', 'd', 'f')), + sync_subid oid NOT NULL REFERENCES pglogical.subscription(sub_id), + sync_nspname name, + sync_relname name, + sync_status "char" NOT NULL, + sync_statuslsn pg_lsn NOT NULL, + UNIQUE (sync_subid, sync_nspname, sync_relname) +); + + +CREATE FUNCTION pglogical.create_node(node_name name, dsn text) +RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_create_node'; +CREATE FUNCTION pglogical.drop_node(node_name name, ifexists boolean DEFAULT false) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_drop_node'; + +CREATE FUNCTION pglogical.alter_node_add_interface(node_name name, interface_name name, dsn text) +RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_node_add_interface'; +CREATE FUNCTION pglogical.alter_node_drop_interface(node_name name, interface_name name) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_node_drop_interface'; + +CREATE FUNCTION pglogical.create_subscription(subscription_name name, provider_dsn text, + replication_sets text[] = '{default,default_insert_only,ddl_sql}', synchronize_structure boolean = false, + synchronize_data boolean = true, forward_origins text[] = '{all}', apply_delay interval DEFAULT '0', + force_text_transfer boolean = false) +RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_create_subscription'; +CREATE FUNCTION pglogical.drop_subscription(subscription_name name, ifexists boolean DEFAULT false) +RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_drop_subscription'; + +CREATE FUNCTION pglogical.alter_subscription_interface(subscription_name name, interface_name name) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_subscription_interface'; + +CREATE FUNCTION pglogical.alter_subscription_disable(subscription_name name, immediate boolean DEFAULT false) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_subscription_disable'; +CREATE FUNCTION pglogical.alter_subscription_enable(subscription_name name, immediate boolean DEFAULT false) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_subscription_enable'; + +CREATE FUNCTION pglogical.alter_subscription_add_replication_set(subscription_name name, replication_set name) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_subscription_add_replication_set'; +CREATE FUNCTION pglogical.alter_subscription_remove_replication_set(subscription_name name, replication_set name) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_subscription_remove_replication_set'; + +CREATE FUNCTION pglogical.show_subscription_status(subscription_name name DEFAULT NULL, + OUT subscription_name text, OUT status text, OUT provider_node text, + OUT provider_dsn text, OUT slot_name text, OUT replication_sets text[], + OUT forward_origins text[]) +RETURNS SETOF record STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_subscription_status'; + +CREATE TABLE pglogical.replication_set ( + set_id oid NOT NULL PRIMARY KEY, + set_nodeid oid NOT NULL, + set_name name NOT NULL, + replicate_insert boolean NOT NULL DEFAULT true, + replicate_update boolean NOT NULL DEFAULT true, + replicate_delete boolean NOT NULL DEFAULT true, + replicate_truncate boolean NOT NULL DEFAULT true, + UNIQUE (set_nodeid, set_name) +) WITH (user_catalog_table=true); + +CREATE TABLE pglogical.replication_set_table ( + set_id oid NOT NULL, + set_reloid regclass NOT NULL, + set_att_list text[], + set_row_filter pg_node_tree, + PRIMARY KEY(set_id, set_reloid) +) WITH (user_catalog_table=true); + +CREATE TABLE pglogical.replication_set_seq ( + set_id oid NOT NULL, + set_seqoid regclass NOT NULL, + PRIMARY KEY(set_id, set_seqoid) +) WITH (user_catalog_table=true); + +CREATE TABLE pglogical.sequence_state ( + seqoid oid NOT NULL PRIMARY KEY, + cache_size integer NOT NULL, + last_value bigint NOT NULL +) WITH (user_catalog_table=true); + +CREATE TABLE pglogical.depend ( + classid oid NOT NULL, + objid oid NOT NULL, + objsubid integer NOT NULL, + + refclassid oid NOT NULL, + refobjid oid NOT NULL, + refobjsubid integer NOT NULL, + + deptype "char" NOT NULL +) WITH (user_catalog_table=true); + +CREATE VIEW pglogical.TABLES AS + WITH set_relations AS ( + SELECT s.set_name, r.set_reloid + FROM pglogical.replication_set_table r, + pglogical.replication_set s, + pglogical.local_node n + WHERE s.set_nodeid = n.node_id + AND s.set_id = r.set_id + ), + user_tables AS ( + SELECT r.oid, n.nspname, r.relname, r.relreplident + FROM pg_catalog.pg_class r, + pg_catalog.pg_namespace n + WHERE r.relkind = 'r' + AND r.relpersistence = 'p' + AND n.oid = r.relnamespace + AND n.nspname !~ '^pg_' + AND n.nspname != 'information_schema' + AND n.nspname != 'pglogical' + ) + SELECT r.oid AS relid, n.nspname, r.relname, s.set_name + FROM pg_catalog.pg_namespace n, + pg_catalog.pg_class r, + set_relations s + WHERE r.relkind = 'r' + AND n.oid = r.relnamespace + AND r.oid = s.set_reloid + UNION + SELECT t.oid AS relid, t.nspname, t.relname, NULL + FROM user_tables t + WHERE t.oid NOT IN (SELECT set_reloid FROM set_relations); + +CREATE FUNCTION pglogical.create_replication_set(set_name name, + replicate_insert boolean = true, replicate_update boolean = true, + replicate_delete boolean = true, replicate_truncate boolean = true) +RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_create_replication_set'; +CREATE FUNCTION pglogical.alter_replication_set(set_name name, + replicate_insert boolean DEFAULT NULL, replicate_update boolean DEFAULT NULL, + replicate_delete boolean DEFAULT NULL, replicate_truncate boolean DEFAULT NULL) +RETURNS oid CALLED ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_replication_set'; +CREATE FUNCTION pglogical.drop_replication_set(set_name name, ifexists boolean DEFAULT false) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_drop_replication_set'; + +CREATE FUNCTION pglogical.replication_set_add_table(set_name name, relation regclass, synchronize_data boolean DEFAULT false, + columns text[] DEFAULT NULL, row_filter text DEFAULT NULL) +RETURNS boolean CALLED ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_table'; +CREATE FUNCTION pglogical.replication_set_add_all_tables(set_name name, schema_names text[], synchronize_data boolean DEFAULT false) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_all_tables'; +CREATE FUNCTION pglogical.replication_set_remove_table(set_name name, relation regclass) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_remove_table'; + +CREATE FUNCTION pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean DEFAULT false) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_sequence'; +CREATE FUNCTION pglogical.replication_set_add_all_sequences(set_name name, schema_names text[], synchronize_data boolean DEFAULT false) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_all_sequences'; +CREATE FUNCTION pglogical.replication_set_remove_sequence(set_name name, relation regclass) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_remove_sequence'; + +CREATE FUNCTION pglogical.alter_subscription_synchronize(subscription_name name, truncate boolean DEFAULT false) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_subscription_synchronize'; + +CREATE FUNCTION pglogical.alter_subscription_resynchronize_table(subscription_name name, relation regclass, + truncate boolean DEFAULT true) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_alter_subscription_resynchronize_table'; + +CREATE FUNCTION pglogical.synchronize_sequence(relation regclass) +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_synchronize_sequence'; + +CREATE FUNCTION pglogical.table_data_filtered(reltyp anyelement, relation regclass, repsets text[]) +RETURNS SETOF anyelement CALLED ON NULL INPUT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_table_data_filtered'; + +CREATE FUNCTION pglogical.show_repset_table_info(relation regclass, repsets text[], OUT relid oid, OUT nspname text, + OUT relname text, OUT att_list text[], OUT has_row_filter boolean) +RETURNS record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info'; + +CREATE FUNCTION pglogical.show_subscription_table(subscription_name name, relation regclass, OUT nspname text, OUT relname text, OUT status text) +RETURNS record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_subscription_table'; + +CREATE TABLE pglogical.queue ( + queued_at timestamp with time zone NOT NULL, + role name NOT NULL, + replication_sets text[], + message_type "char" NOT NULL, + message json NOT NULL +); + +CREATE FUNCTION pglogical.replicate_ddl_command(command text, replication_sets text[] DEFAULT '{ddl_sql}') +RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replicate_ddl_command'; + +CREATE OR REPLACE FUNCTION pglogical.queue_truncate() +RETURNS trigger LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_queue_truncate'; + +CREATE FUNCTION pglogical.pglogical_node_info(OUT node_id oid, OUT node_name text, OUT sysid text, OUT dbname text, OUT replication_sets text) +RETURNS record +STABLE STRICT LANGUAGE c AS 'MODULE_PATHNAME'; + +CREATE FUNCTION pglogical.pglogical_gen_slot_name(name, name, name) +RETURNS name +IMMUTABLE STRICT LANGUAGE c AS 'MODULE_PATHNAME'; + +CREATE FUNCTION pglogical_version() RETURNS text +LANGUAGE c AS 'MODULE_PATHNAME'; + +CREATE FUNCTION pglogical_version_num() RETURNS integer +LANGUAGE c AS 'MODULE_PATHNAME'; + +CREATE FUNCTION pglogical_max_proto_version() RETURNS integer +LANGUAGE c AS 'MODULE_PATHNAME'; + +CREATE FUNCTION pglogical_min_proto_version() RETURNS integer +LANGUAGE c AS 'MODULE_PATHNAME'; + +CREATE FUNCTION +pglogical.wait_slot_confirm_lsn(slotname name, target pg_lsn) +RETURNS void LANGUAGE c AS 'pglogical','pglogical_wait_slot_confirm_lsn'; +CREATE FUNCTION pglogical.wait_for_subscription_sync_complete(subscription_name name) +RETURNS void RETURNS NULL ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_wait_for_subscription_sync_complete'; + +CREATE FUNCTION pglogical.wait_for_table_sync_complete(subscription_name name, relation regclass) +RETURNS void RETURNS NULL ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_wait_for_table_sync_complete'; + +CREATE FUNCTION pglogical.xact_commit_timestamp_origin("xid" xid, OUT "timestamp" timestamptz, OUT "roident" oid) +RETURNS record RETURNS NULL ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_xact_commit_timestamp_origin'; diff --git a/pglogical.h b/pglogical.h index d7732fb..5f8a9c8 100644 --- a/pglogical.h +++ b/pglogical.h @@ -26,8 +26,8 @@ #include "pglogical_compat.h" -#define PGLOGICAL_VERSION "2.3.0" -#define PGLOGICAL_VERSION_NUM 20300 +#define PGLOGICAL_VERSION "2.3.1" +#define PGLOGICAL_VERSION_NUM 20301 #define PGLOGICAL_MIN_PROTO_VERSION_NUM 1 #define PGLOGICAL_MAX_PROTO_VERSION_NUM 1 From 5d806e2bd24f4eaa5dc2f5d2bde876193f6a1491 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 28 Mar 2020 09:47:37 +0100 Subject: [PATCH 7/9] Remove unneeded upgrade file 2.2.3 was never a released version. --- pglogical--2.2.3--2.3.0.sql | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 pglogical--2.2.3--2.3.0.sql diff --git a/pglogical--2.2.3--2.3.0.sql b/pglogical--2.2.3--2.3.0.sql deleted file mode 100644 index a2dd36a..0000000 --- a/pglogical--2.2.3--2.3.0.sql +++ /dev/null @@ -1,8 +0,0 @@ -DROP FUNCTION pglogical.create_subscription(subscription_name name, provider_dsn text, - replication_sets text[], synchronize_structure boolean, synchronize_data boolean, - forward_origins text[], apply_delay interval, force_text_transfer boolean); -CREATE FUNCTION pglogical.create_subscription(subscription_name name, provider_dsn text, - replication_sets text[] = '{default,default_insert_only,ddl_sql}', synchronize_structure text = 'none', - synchronize_data boolean = true, forward_origins text[] = '{all}', apply_delay interval DEFAULT '0', - force_text_transfer boolean = false) -RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_create_subscription'; From 8e439159448f6eb50c3f295b55a477d671000ade Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 30 Mar 2020 18:33:29 +0200 Subject: [PATCH 8/9] Restore 2.3.0 schema files These were changed during the reverts, but we should keep them as they were at the time of release. --- pglogical--2.2.2--2.3.0.sql | 41 +++++++++++++++++++++++++++++++++++++ pglogical--2.3.0.sql | 16 +++++++++++---- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/pglogical--2.2.2--2.3.0.sql b/pglogical--2.2.2--2.3.0.sql index b6f02fd..e65808f 100644 --- a/pglogical--2.2.2--2.3.0.sql +++ b/pglogical--2.2.2--2.3.0.sql @@ -9,3 +9,44 @@ RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_create_s DROP FUNCTION pglogical.create_subscription(subscription_name name, provider_dsn text, replication_sets text[], synchronize_structure boolean, synchronize_data boolean, forward_origins text[], apply_delay interval); + +ALTER TABLE pglogical.replication_set_table + ADD COLUMN set_nsptarget name NOT NULL + , ADD COLUMN set_reltarget name NOT NULL; +ALTER TABLE pglogical.replication_set_seq + ADD COLUMN set_nsptarget name NOT NULL + , ADD COLUMN set_seqtarget name NOT NULL; +DROP FUNCTION pglogical.show_repset_table_info(regclass, text[]); +CREATE FUNCTION pglogical.show_repset_table_info(relation regclass, repsets text[], OUT relid oid, OUT nspname text, + OUT relname text, OUT att_list text[], OUT has_row_filter boolean, OUT nsptarget text, OUT reltarget text) +RETURNS record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info'; + +CREATE FUNCTION pglogical.show_repset_table_info_by_target(nsptarget name, reltarget name, repsets text[], OUT relid oid, OUT nspname text, + OUT relname text, OUT att_list text[], OUT has_row_filter boolean, OUT nsptarget text, OUT reltarget text) +RETURNS SETOF record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info_by_target'; + +UPDATE pglogical.replication_set_table + SET set_nsptarget = n.nspname + , set_reltarget = c.relname +FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace +WHERE c.oid = set_reloid; + +UPDATE pglogical.replication_set_seq + SET set_nsptarget = n.nspname + , set_seqtarget = c.relname +FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace +WHERE c.oid = set_seqoid; + +-- a VACUUM FULL of the table above would be nice here. + +DROP FUNCTION pglogical.replication_set_add_table(name, regclass, boolean, + text[], text); +CREATE FUNCTION pglogical.replication_set_add_table(set_name name, relation regclass, synchronize_data boolean DEFAULT false, + columns text[] DEFAULT NULL, row_filter text DEFAULT NULL, nsptarget name DEFAULT NULL, reltarget name DEFAULT NULL) +RETURNS boolean CALLED ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_table'; + +DROP FUNCTION pglogical.replication_set_add_sequence(name, regclass, boolean); +CREATE FUNCTION pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean DEFAULT false, nsptarget name DEFAULT NULL, reltarget name DEFAULT NULL) +RETURNS boolean VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_sequence'; diff --git a/pglogical--2.3.0.sql b/pglogical--2.3.0.sql index 52c1dbe..5ef62fa 100644 --- a/pglogical--2.3.0.sql +++ b/pglogical--2.3.0.sql @@ -97,12 +97,16 @@ CREATE TABLE pglogical.replication_set_table ( set_reloid regclass NOT NULL, set_att_list text[], set_row_filter pg_node_tree, + set_nsptarget name NOT NULL, + set_reltarget name NOT NULL, PRIMARY KEY(set_id, set_reloid) ) WITH (user_catalog_table=true); CREATE TABLE pglogical.replication_set_seq ( set_id oid NOT NULL, set_seqoid regclass NOT NULL, + set_nsptarget name NOT NULL, + set_seqtarget name NOT NULL, PRIMARY KEY(set_id, set_seqoid) ) WITH (user_catalog_table=true); @@ -168,15 +172,15 @@ CREATE FUNCTION pglogical.drop_replication_set(set_name name, ifexists boolean D RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_drop_replication_set'; CREATE FUNCTION pglogical.replication_set_add_table(set_name name, relation regclass, synchronize_data boolean DEFAULT false, - columns text[] DEFAULT NULL, row_filter text DEFAULT NULL) + columns text[] DEFAULT NULL, row_filter text DEFAULT NULL, nsptarget name DEFAULT NULL, reltarget name DEFAULT NULL) RETURNS boolean CALLED ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_table'; CREATE FUNCTION pglogical.replication_set_add_all_tables(set_name name, schema_names text[], synchronize_data boolean DEFAULT false) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_all_tables'; CREATE FUNCTION pglogical.replication_set_remove_table(set_name name, relation regclass) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_remove_table'; -CREATE FUNCTION pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean DEFAULT false) -RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_sequence'; +CREATE FUNCTION pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean DEFAULT false, nsptarget name DEFAULT NULL, reltarget name DEFAULT NULL) +RETURNS boolean VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_sequence'; CREATE FUNCTION pglogical.replication_set_add_all_sequences(set_name name, schema_names text[], synchronize_data boolean DEFAULT false) RETURNS boolean STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_all_sequences'; CREATE FUNCTION pglogical.replication_set_remove_sequence(set_name name, relation regclass) @@ -196,9 +200,13 @@ CREATE FUNCTION pglogical.table_data_filtered(reltyp anyelement, relation regcla RETURNS SETOF anyelement CALLED ON NULL INPUT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_table_data_filtered'; CREATE FUNCTION pglogical.show_repset_table_info(relation regclass, repsets text[], OUT relid oid, OUT nspname text, - OUT relname text, OUT att_list text[], OUT has_row_filter boolean) + OUT relname text, OUT att_list text[], OUT has_row_filter boolean, OUT nsptarget text, OUT reltarget text) RETURNS record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info'; +CREATE FUNCTION pglogical.show_repset_table_info_by_target(nsptarget name, reltarget name, repsets text[], OUT relid oid, OUT nspname text, + OUT relname text, OUT att_list text[], OUT has_row_filter boolean, OUT nsptarget text, OUT reltarget text) +RETURNS SETOF record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info_by_target'; + CREATE FUNCTION pglogical.show_subscription_table(subscription_name name, relation regclass, OUT nspname text, OUT relname text, OUT status text) RETURNS record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_subscription_table'; From 9e52a28d2f5e4ea0418a25228b38882311c4660a Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 31 Mar 2020 16:35:55 +0200 Subject: [PATCH 9/9] Fix up 2.3.0 to 2.3.1 upgrade --- pglogical--2.3.0--2.3.1.sql | 80 +++++++++++++++++++++++++++++++++++++ pglogical_functions.c | 13 ++++++ 2 files changed, 93 insertions(+) diff --git a/pglogical--2.3.0--2.3.1.sql b/pglogical--2.3.0--2.3.1.sql index fe2e344..b0b8827 100644 --- a/pglogical--2.3.0--2.3.1.sql +++ b/pglogical--2.3.0--2.3.1.sql @@ -7,3 +7,83 @@ CREATE FUNCTION pglogical.create_subscription(subscription_name name, provider_d synchronize_data boolean = true, forward_origins text[] = '{all}', apply_delay interval DEFAULT '0', force_text_transfer boolean = false) RETURNS oid STRICT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_create_subscription'; + +DROP FUNCTION pglogical.show_repset_table_info(regclass, text[]); +CREATE FUNCTION pglogical.show_repset_table_info(relation regclass, repsets text[], OUT relid oid, OUT nspname text, + OUT relname text, OUT att_list text[], OUT has_row_filter boolean) +RETURNS record STRICT STABLE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_show_repset_table_info'; + +DROP FUNCTION pglogical.show_repset_table_info_by_target(name, name, text[]); + +DROP FUNCTION pglogical.replication_set_add_table(name, regclass, boolean, text[], text, name, name); +CREATE FUNCTION pglogical.replication_set_add_table(set_name name, relation regclass, synchronize_data boolean DEFAULT false, + columns text[] DEFAULT NULL, row_filter text DEFAULT NULL) +RETURNS boolean CALLED ON NULL INPUT VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_table'; + +DROP FUNCTION pglogical.replication_set_add_sequence(name, regclass, boolean, name, name); +CREATE FUNCTION pglogical.replication_set_add_sequence(set_name name, relation regclass, synchronize_data boolean DEFAULT false) +RETURNS boolean VOLATILE LANGUAGE c AS 'MODULE_PATHNAME', 'pglogical_replication_set_add_sequence'; + + +ALTER TABLE pglogical.replication_set_table RENAME TO replication_set_table_old; + +CREATE TABLE pglogical.replication_set_table ( + set_id oid NOT NULL, + set_reloid regclass NOT NULL, + set_att_list text[], + set_row_filter pg_node_tree, + PRIMARY KEY(set_id, set_reloid) +) WITH (user_catalog_table=true); + +INSERT INTO pglogical.replication_set_table + SELECT set_id, set_reloid, set_att_list, set_row_filter FROM pglogical.replication_set_table_old; + +DROP VIEW pglogical.tables; +DROP TABLE pglogical.replication_set_table_old; + +ALTER TABLE pglogical.replication_set_seq RENAME TO replication_set_seq_old; + +CREATE TABLE pglogical.replication_set_seq ( + set_id oid NOT NULL, + set_seqoid regclass NOT NULL, + PRIMARY KEY(set_id, set_seqoid) +) WITH (user_catalog_table=true); + +INSERT INTO pglogical.replication_set_seq + SELECT set_id, set_seqoid FROM pglogical.replication_set_seq_old; + +DROP TABLE pglogical.replication_set_seq_old; + + +-- must recreate on top of new replication_set_table +CREATE VIEW pglogical.TABLES AS + WITH set_relations AS ( + SELECT s.set_name, r.set_reloid + FROM pglogical.replication_set_table r, + pglogical.replication_set s, + pglogical.local_node n + WHERE s.set_nodeid = n.node_id + AND s.set_id = r.set_id + ), + user_tables AS ( + SELECT r.oid, n.nspname, r.relname, r.relreplident + FROM pg_catalog.pg_class r, + pg_catalog.pg_namespace n + WHERE r.relkind = 'r' + AND r.relpersistence = 'p' + AND n.oid = r.relnamespace + AND n.nspname !~ '^pg_' + AND n.nspname != 'information_schema' + AND n.nspname != 'pglogical' + ) + SELECT r.oid AS relid, n.nspname, r.relname, s.set_name + FROM pg_catalog.pg_namespace n, + pg_catalog.pg_class r, + set_relations s + WHERE r.relkind = 'r' + AND n.oid = r.relnamespace + AND r.oid = s.set_reloid + UNION + SELECT t.oid AS relid, t.nspname, t.relname, NULL + FROM user_tables t + WHERE t.oid NOT IN (SELECT set_reloid FROM set_relations); diff --git a/pglogical_functions.c b/pglogical_functions.c index 4301d1c..a078039 100644 --- a/pglogical_functions.c +++ b/pglogical_functions.c @@ -143,6 +143,9 @@ PG_FUNCTION_INFO_V1(pglogical_max_proto_version); PG_FUNCTION_INFO_V1(pglogical_xact_commit_timestamp_origin); +/* Compatibility for upgrading */ +PG_FUNCTION_INFO_V1(pglogical_show_repset_table_info_by_target); + static void gen_slot_name(Name slot_name, char *dbname, const char *provider_name, const char *subscriber_name); @@ -1979,6 +1982,16 @@ pglogical_show_repset_table_info(PG_FUNCTION_ARGS) } +/* + * Dummy function to allow upgrading through all intermediate versions + */ +Datum +pglogical_show_repset_table_info_by_target(PG_FUNCTION_ARGS) +{ + abort(); +} + + /* * Decide if to return tuple or not. */