diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/catalog/pg_publication.c | 211 | ||||
-rw-r--r-- | src/backend/commands/subscriptioncmds.c | 59 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.dat | 12 | ||||
-rw-r--r-- | src/test/regress/expected/rules.out | 2 | ||||
-rw-r--r-- | src/test/subscription/t/013_partition.pl | 25 | ||||
-rw-r--r-- | src/test/subscription/t/028_row_filter.pl | 42 | ||||
-rw-r--r-- | src/test/subscription/t/031_column_list.pl | 9 | ||||
-rw-r--r-- | src/tools/pgindent/typedefs.list | 1 |
9 files changed, 264 insertions, 99 deletions
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index a98fcad421f..47637f28ab6 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -45,6 +45,14 @@ #include "utils/rel.h" #include "utils/syscache.h" +/* Records association between publication and published table */ +typedef struct +{ + Oid relid; /* OID of published table */ + Oid pubid; /* OID of publication that publishes this + * table. */ +} published_rel; + static void publication_translate_columns(Relation targetrel, List *columns, int *natts, AttrNumber **attrs); @@ -172,42 +180,57 @@ pg_relation_is_publishable(PG_FUNCTION_ARGS) } /* - * Filter out the partitions whose parent tables were also specified in - * the publication. + * Returns true if the ancestor is in the list of published relations. + * Otherwise, returns false. */ -static List * -filter_partitions(List *relids) +static bool +is_ancestor_member_tableinfos(Oid ancestor, List *table_infos) +{ + ListCell *lc; + + foreach(lc, table_infos) + { + Oid relid = ((published_rel *) lfirst(lc))->relid; + + if (relid == ancestor) + return true; + } + + return false; +} + +/* + * Filter out the partitions whose parent tables are also present in the list. + */ +static void +filter_partitions(List *table_infos) { - List *result = NIL; ListCell *lc; - ListCell *lc2; - foreach(lc, relids) + foreach(lc, table_infos) { bool skip = false; List *ancestors = NIL; - Oid relid = lfirst_oid(lc); + ListCell *lc2; + published_rel *table_info = (published_rel *) lfirst(lc); - if (get_rel_relispartition(relid)) - ancestors = get_partition_ancestors(relid); + if (get_rel_relispartition(table_info->relid)) + ancestors = get_partition_ancestors(table_info->relid); foreach(lc2, ancestors) { Oid ancestor = lfirst_oid(lc2); - /* Check if the parent table exists in the published table list. */ - if (list_member_oid(relids, ancestor)) + if (is_ancestor_member_tableinfos(ancestor, table_infos)) { skip = true; break; } } - if (!skip) - result = lappend_oid(result, relid); + if (skip) + table_infos = foreach_delete_current(table_infos, lc); } - - return result; } /* @@ -1026,22 +1049,27 @@ GetPublicationByName(const char *pubname, bool missing_ok) } /* - * Returns information of tables in a publication. + * Get information of the tables in the given publication array. + * + * Returns pubid, relid, column list, row filter for each table. */ Datum pg_get_publication_tables(PG_FUNCTION_ARGS) { -#define NUM_PUBLICATION_TABLES_ELEM 3 +#define NUM_PUBLICATION_TABLES_ELEM 4 FuncCallContext *funcctx; - char *pubname = text_to_cstring(PG_GETARG_TEXT_PP(0)); - Publication *publication; - List *tables; + List *table_infos = NIL; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { TupleDesc tupdesc; MemoryContext oldcontext; + ArrayType *arr; + Datum *elems; + int nelems, + i; + bool viaroot = false; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); @@ -1049,68 +1077,108 @@ pg_get_publication_tables(PG_FUNCTION_ARGS) /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - publication = GetPublicationByName(pubname, false); - /* - * Publications support partitioned tables, although all changes are - * replicated using leaf partition identity and schema, so we only - * need those. + * Deconstruct the parameter into elements where each element is a + * publication name. */ - if (publication->alltables) - { - tables = GetAllTablesPublicationRelations(publication->pubviaroot); - } - else + arr = PG_GETARG_ARRAYTYPE_P(0); + deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT, + &elems, NULL, &nelems); + + /* Get Oids of tables from each publication. */ + for (i = 0; i < nelems; i++) { - List *relids, - *schemarelids; - - relids = GetPublicationRelations(publication->oid, - publication->pubviaroot ? - PUBLICATION_PART_ROOT : - PUBLICATION_PART_LEAF); - schemarelids = GetAllSchemaPublicationRelations(publication->oid, - publication->pubviaroot ? - PUBLICATION_PART_ROOT : - PUBLICATION_PART_LEAF); - tables = list_concat_unique_oid(relids, schemarelids); + Publication *pub_elem; + List *pub_elem_tables = NIL; + ListCell *lc; + + pub_elem = GetPublicationByName(TextDatumGetCString(elems[i]), false); /* - * If the publication publishes partition changes via their - * respective root partitioned tables, we must exclude partitions - * in favor of including the root partitioned tables. Otherwise, - * the function could return both the child and parent tables - * which could cause data of the child table to be - * double-published on the subscriber side. + * Publications support partitioned tables. If + * publish_via_partition_root is false, all changes are replicated + * using leaf partition identity and schema, so we only need + * those. Otherwise, get the partitioned table itself. */ - if (publication->pubviaroot) - tables = filter_partitions(tables); + if (pub_elem->alltables) + pub_elem_tables = GetAllTablesPublicationRelations(pub_elem->pubviaroot); + else + { + List *relids, + *schemarelids; + + relids = GetPublicationRelations(pub_elem->oid, + pub_elem->pubviaroot ? + PUBLICATION_PART_ROOT : + PUBLICATION_PART_LEAF); + schemarelids = GetAllSchemaPublicationRelations(pub_elem->oid, + pub_elem->pubviaroot ? + PUBLICATION_PART_ROOT : + PUBLICATION_PART_LEAF); + pub_elem_tables = list_concat_unique_oid(relids, schemarelids); + } + + /* + * Record the published table and the corresponding publication so + * that we can get row filters and column lists later. + * + * When a table is published by multiple publications, to obtain + * all row filters and column lists, the structure related to this + * table will be recorded multiple times. + */ + foreach(lc, pub_elem_tables) + { + published_rel *table_info = (published_rel *) palloc(sizeof(published_rel)); + + table_info->relid = lfirst_oid(lc); + table_info->pubid = pub_elem->oid; + table_infos = lappend(table_infos, table_info); + } + + /* At least one publication is using publish_via_partition_root. */ + if (pub_elem->pubviaroot) + viaroot = true; } + /* + * If the publication publishes partition changes via their respective + * root partitioned tables, we must exclude partitions in favor of + * including the root partitioned tables. Otherwise, the function + * could return both the child and parent tables which could cause + * data of the child table to be double-published on the subscriber + * side. + */ + if (viaroot) + filter_partitions(table_infos); + /* Construct a tuple descriptor for the result rows. */ tupdesc = CreateTemplateTupleDesc(NUM_PUBLICATION_TABLES_ELEM); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relid", + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pubid", OIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "attrs", + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relid", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "attrs", INT2VECTOROID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "qual", + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "qual", PG_NODE_TREEOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); - funcctx->user_fctx = (void *) tables; + funcctx->user_fctx = (void *) table_infos; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); - tables = (List *) funcctx->user_fctx; + table_infos = (List *) funcctx->user_fctx; - if (funcctx->call_cntr < list_length(tables)) + if (funcctx->call_cntr < list_length(table_infos)) { HeapTuple pubtuple = NULL; HeapTuple rettuple; - Oid relid = list_nth_oid(tables, funcctx->call_cntr); + Publication *pub; + published_rel *table_info = (published_rel *) list_nth(table_infos, funcctx->call_cntr); + Oid relid = table_info->relid; Oid schemaid = get_rel_namespace(relid); Datum values[NUM_PUBLICATION_TABLES_ELEM] = {0}; bool nulls[NUM_PUBLICATION_TABLES_ELEM] = {0}; @@ -1119,42 +1187,43 @@ pg_get_publication_tables(PG_FUNCTION_ARGS) * Form tuple with appropriate data. */ - publication = GetPublicationByName(pubname, false); + pub = GetPublication(table_info->pubid); - values[0] = ObjectIdGetDatum(relid); + values[0] = ObjectIdGetDatum(pub->oid); + values[1] = ObjectIdGetDatum(relid); /* * We don't consider row filters or column lists for FOR ALL TABLES or * FOR TABLES IN SCHEMA publications. */ - if (!publication->alltables && + if (!pub->alltables && !SearchSysCacheExists2(PUBLICATIONNAMESPACEMAP, ObjectIdGetDatum(schemaid), - ObjectIdGetDatum(publication->oid))) + ObjectIdGetDatum(pub->oid))) pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP, ObjectIdGetDatum(relid), - ObjectIdGetDatum(publication->oid)); + ObjectIdGetDatum(pub->oid)); if (HeapTupleIsValid(pubtuple)) { /* Lookup the column list attribute. */ - values[1] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple, + values[2] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple, Anum_pg_publication_rel_prattrs, - &(nulls[1])); + &(nulls[2])); /* Null indicates no filter. */ - values[2] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple, + values[3] = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple, Anum_pg_publication_rel_prqual, - &(nulls[2])); + &(nulls[3])); } else { - nulls[1] = true; nulls[2] = true; + nulls[3] = true; } /* Show all columns when the column list is not specified. */ - if (nulls[1] == true) + if (nulls[2]) { Relation rel = table_open(relid, AccessShareLock); int nattnums = 0; @@ -1176,8 +1245,8 @@ pg_get_publication_tables(PG_FUNCTION_ARGS) if (nattnums > 0) { - values[1] = PointerGetDatum(buildint2vector(attnums, nattnums)); - nulls[1] = false; + values[2] = PointerGetDatum(buildint2vector(attnums, nattnums)); + nulls[2] = false; } table_close(rel, AccessShareLock); diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index 8a26ddab1c7..93a238412aa 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -1936,21 +1936,60 @@ fetch_table_list(WalReceiverConn *wrconn, List *publications) WalRcvExecResult *res; StringInfoData cmd; TupleTableSlot *slot; - Oid tableRow[3] = {TEXTOID, TEXTOID, NAMEARRAYOID}; + Oid tableRow[3] = {TEXTOID, TEXTOID, InvalidOid}; List *tablelist = NIL; - bool check_columnlist = (walrcv_server_version(wrconn) >= 150000); + int server_version = walrcv_server_version(wrconn); + bool check_columnlist = (server_version >= 150000); initStringInfo(&cmd); - appendStringInfoString(&cmd, "SELECT DISTINCT t.schemaname, t.tablename \n"); - /* Get column lists for each relation if the publisher supports it */ - if (check_columnlist) - appendStringInfoString(&cmd, ", t.attnames\n"); + /* Get the list of tables from the publisher. */ + if (server_version >= 160000) + { + StringInfoData pub_names; - appendStringInfoString(&cmd, "FROM pg_catalog.pg_publication_tables t\n" - " WHERE t.pubname IN ("); - get_publications_str(publications, &cmd, true); - appendStringInfoChar(&cmd, ')'); + tableRow[2] = INT2VECTOROID; + initStringInfo(&pub_names); + get_publications_str(publications, &pub_names, true); + + /* + * From version 16, we allowed passing multiple publications to the + * function pg_get_publication_tables. This helped to filter out the + * partition table whose ancestor is also published in this + * publication array. + * + * Join pg_get_publication_tables with pg_publication to exclude + * non-existing publications. + * + * Note that attrs are always stored in sorted order so we don't need + * to worry if different publications have specified them in a + * different order. See publication_translate_columns. + */ + appendStringInfo(&cmd, "SELECT DISTINCT n.nspname, c.relname, gpt.attrs\n" + " FROM pg_class c\n" + " JOIN pg_namespace n ON n.oid = c.relnamespace\n" + " JOIN ( SELECT (pg_get_publication_tables(VARIADIC array_agg(pubname::text))).*\n" + " FROM pg_publication\n" + " WHERE pubname IN ( %s )) AS gpt\n" + " ON gpt.relid = c.oid\n", + pub_names.data); + + pfree(pub_names.data); + } + else + { + tableRow[2] = NAMEARRAYOID; + appendStringInfoString(&cmd, "SELECT DISTINCT t.schemaname, t.tablename \n"); + + /* Get column lists for each relation if the publisher supports it */ + if (check_columnlist) + appendStringInfoString(&cmd, ", t.attnames\n"); + + appendStringInfoString(&cmd, "FROM pg_catalog.pg_publication_tables t\n" + " WHERE t.pubname IN ("); + get_publications_str(publications, &cmd, true); + appendStringInfoChar(&cmd, ')'); + } res = walrcv_exec(wrconn, cmd.data, check_columnlist ? 3 : 2, tableRow); pfree(cmd.data); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index c187d47eb27..db590b6bf07 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202303281 +#define CATALOG_VERSION_NO 202303291 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 7c358cff162..def8ee20455 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -11756,11 +11756,13 @@ prosrc => 'pg_show_replication_origin_status' }, # publications -{ oid => '6119', descr => 'get information of tables in a publication', - proname => 'pg_get_publication_tables', prorows => '1000', proretset => 't', - provolatile => 's', prorettype => 'record', proargtypes => 'text', - proallargtypes => '{text,oid,int2vector,pg_node_tree}', - proargmodes => '{i,o,o,o}', proargnames => '{pubname,relid,attrs,qual}', +{ oid => '6119', + descr => 'get information of the tables that are part of the specified publications', + proname => 'pg_get_publication_tables', prorows => '1000', + provariadic => 'text', proretset => 't', provolatile => 's', + prorettype => 'record', proargtypes => '_text', + proallargtypes => '{_text,oid,oid,int2vector,pg_node_tree}', + proargmodes => '{v,o,o,o,o}', proargnames => '{pubname,pubid,relid,attrs,qual}', prosrc => 'pg_get_publication_tables' }, { oid => '6121', descr => 'returns whether a relation can be part of a publication', diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 996d22b7ddf..c71758db46e 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1449,7 +1449,7 @@ pg_publication_tables| SELECT p.pubname, WHERE ((a.attrelid = gpt.relid) AND (a.attnum = ANY ((gpt.attrs)::smallint[])))) AS attnames, pg_get_expr(gpt.qual, gpt.relid) AS rowfilter FROM pg_publication p, - LATERAL pg_get_publication_tables((p.pubname)::text) gpt(relid, attrs, qual), + LATERAL pg_get_publication_tables(VARIADIC ARRAY[(p.pubname)::text]) gpt(pubid, relid, attrs, qual), (pg_class c JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.oid = gpt.relid); diff --git a/src/test/subscription/t/013_partition.pl b/src/test/subscription/t/013_partition.pl index 11a5c3c03ef..f03cd24246d 100644 --- a/src/test/subscription/t/013_partition.pl +++ b/src/test/subscription/t/013_partition.pl @@ -409,10 +409,10 @@ $node_publisher->safe_psql('postgres', $node_publisher->safe_psql('postgres', "CREATE TABLE tab4 (a int PRIMARY KEY) PARTITION BY LIST (a)"); $node_publisher->safe_psql('postgres', - "CREATE TABLE tab4_1 PARTITION OF tab4 FOR VALUES IN (0, 1) PARTITION BY LIST (a)" + "CREATE TABLE tab4_1 PARTITION OF tab4 FOR VALUES IN (-1, 0, 1) PARTITION BY LIST (a)" ); $node_publisher->safe_psql('postgres', - "CREATE TABLE tab4_1_1 PARTITION OF tab4_1 FOR VALUES IN (0, 1)"); + "CREATE TABLE tab4_1_1 PARTITION OF tab4_1 FOR VALUES IN (-1, 0, 1)"); $node_publisher->safe_psql('postgres', "ALTER PUBLICATION pub_all SET (publish_via_partition_root = true)"); @@ -424,13 +424,13 @@ $node_publisher->safe_psql('postgres', "CREATE PUBLICATION pub_viaroot FOR TABLE tab2, tab2_1, tab3_1 WITH (publish_via_partition_root = true)" ); -# for tab4, we publish changes through the "middle" partitioned table $node_publisher->safe_psql('postgres', "CREATE PUBLICATION pub_lower_level FOR TABLE tab4_1 WITH (publish_via_partition_root = true)" ); # prepare data for the initial sync $node_publisher->safe_psql('postgres', "INSERT INTO tab2 VALUES (1)"); +$node_publisher->safe_psql('postgres', "INSERT INTO tab4 VALUES (-1)"); # subscriber 1 $node_subscriber1->safe_psql('postgres', "DROP SUBSCRIPTION sub1"); @@ -479,9 +479,10 @@ $node_subscriber2->safe_psql('postgres', "CREATE TABLE tab4 (a int PRIMARY KEY)"); $node_subscriber2->safe_psql('postgres', "CREATE TABLE tab4_1 (a int PRIMARY KEY)"); -# Publication that sub2 points to now publishes via root, so must update -# subscription target relations. We set the list of publications so that -# the FOR ALL TABLES publication is second (the list order matters). +# Since we specified publish_via_partition_root in pub_all and +# pub_lower_level, all partition tables use their root tables' identity and +# schema. We set the list of publications so that the FOR ALL TABLES +# publication is second (the list order matters). $node_subscriber2->safe_psql('postgres', "ALTER SUBSCRIPTION sub2 SET PUBLICATION pub_lower_level, pub_all"); @@ -492,6 +493,12 @@ $node_subscriber2->wait_for_subscription_sync; # check that data is synced correctly $result = $node_subscriber1->safe_psql('postgres', "SELECT c, a FROM tab2"); is($result, qq(sub1_tab2|1), 'initial data synced for pub_viaroot'); +$result = + $node_subscriber2->safe_psql('postgres', "SELECT a FROM tab4 ORDER BY 1"); +is($result, qq(-1), 'initial data synced for pub_lower_level and pub_all'); +$result = + $node_subscriber2->safe_psql('postgres', "SELECT a FROM tab4_1 ORDER BY 1"); +is($result, qq(), 'initial data synced for pub_lower_level and pub_all'); # insert $node_publisher->safe_psql('postgres', "INSERT INTO tab1 VALUES (1), (0)"); @@ -548,7 +555,8 @@ sub2_tab3|5), 'inserts into tab3 replicated'); # maps to the tab4 relation on subscriber. $result = $node_subscriber2->safe_psql('postgres', "SELECT a FROM tab4 ORDER BY 1"); -is($result, qq(0), 'inserts into tab4 replicated'); +is( $result, qq(-1 +0), 'inserts into tab4 replicated'); $result = $node_subscriber2->safe_psql('postgres', "SELECT a FROM tab4_1 ORDER BY 1"); @@ -574,7 +582,8 @@ $node_publisher->wait_for_catchup('sub2'); # maps to the tab4 relation on subscriber. $result = $node_subscriber2->safe_psql('postgres', "SELECT a FROM tab4 ORDER BY 1"); -is( $result, qq(0 +is( $result, qq(-1 +0 1), 'inserts into tab4 replicated'); $result = diff --git a/src/test/subscription/t/028_row_filter.pl b/src/test/subscription/t/028_row_filter.pl index def3fbc54bd..b0d4b2d5b17 100644 --- a/src/test/subscription/t/028_row_filter.pl +++ b/src/test/subscription/t/028_row_filter.pl @@ -235,6 +235,11 @@ $node_publisher->safe_psql('postgres', $node_publisher->safe_psql('postgres', "CREATE TABLE tab_rowfilter_viaroot_part_1 PARTITION OF tab_rowfilter_viaroot_part FOR VALUES FROM (1) TO (20)" ); +$node_publisher->safe_psql('postgres', + "CREATE TABLE tab_rowfilter_parent_sync (a int) PARTITION BY RANGE (a)"); +$node_publisher->safe_psql('postgres', + "CREATE TABLE tab_rowfilter_child_sync PARTITION OF tab_rowfilter_parent_sync FOR VALUES FROM (1) TO (20)" +); # setup structure on subscriber $node_subscriber->safe_psql('postgres', @@ -285,6 +290,10 @@ $node_subscriber->safe_psql('postgres', "CREATE TABLE tab_rowfilter_viaroot_part (a int)"); $node_subscriber->safe_psql('postgres', "CREATE TABLE tab_rowfilter_viaroot_part_1 (a int)"); +$node_subscriber->safe_psql('postgres', + "CREATE TABLE tab_rowfilter_parent_sync (a int)"); +$node_subscriber->safe_psql('postgres', + "CREATE TABLE tab_rowfilter_child_sync (a int)"); # setup logical replication $node_publisher->safe_psql('postgres', @@ -341,6 +350,15 @@ $node_publisher->safe_psql('postgres', "CREATE PUBLICATION tap_pub_viaroot_2 FOR TABLE tab_rowfilter_viaroot_part_1 WHERE (a < 15) WITH (publish_via_partition_root)" ); +# two publications, one publishing through ancestor and another one directly +# publishing the partition, with different row filters +$node_publisher->safe_psql('postgres', + "CREATE PUBLICATION tap_pub_parent_sync FOR TABLE tab_rowfilter_parent_sync WHERE (a > 15) WITH (publish_via_partition_root)" +); +$node_publisher->safe_psql('postgres', + "CREATE PUBLICATION tap_pub_child_sync FOR TABLE tab_rowfilter_child_sync WHERE (a < 15)" +); + # # The following INSERTs are executed before the CREATE SUBSCRIPTION, so these # SQL commands are for testing the initial data copy using logical replication. @@ -362,6 +380,9 @@ $node_publisher->safe_psql('postgres', $node_publisher->safe_psql('postgres', "INSERT INTO tab_rowfilter_4 (c) SELECT generate_series(1, 10)"); +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_rowfilter_parent_sync(a) VALUES(14), (16)"); + # insert data into partitioned table and directly on the partition $node_publisher->safe_psql('postgres', "INSERT INTO tab_rowfilter_partitioned (a, b) VALUES(1, 100),(7000, 101),(15000, 102),(5500, 300)" @@ -387,7 +408,7 @@ $node_publisher->safe_psql('postgres', ); $node_subscriber->safe_psql('postgres', - "CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub_1, tap_pub_2, tap_pub_3, tap_pub_4a, tap_pub_4b, tap_pub_5a, tap_pub_5b, tap_pub_toast, tap_pub_inherits, tap_pub_viaroot_2, tap_pub_viaroot_1" + "CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub_1, tap_pub_2, tap_pub_3, tap_pub_4a, tap_pub_4b, tap_pub_5a, tap_pub_5b, tap_pub_toast, tap_pub_inherits, tap_pub_viaroot_2, tap_pub_viaroot_1, tap_pub_parent_sync, tap_pub_child_sync" ); # wait for initial table synchronization to finish @@ -512,6 +533,25 @@ is( $result, qq(20 30 40), 'check initial data copy from table tab_rowfilter_inherited'); +# Check expected replicated rows for tap_pub_parent_sync and +# tap_pub_child_sync. +# Since the option publish_via_partition_root of tap_pub_parent_sync is true, +# so the row filter of tap_pub_parent_sync will be used: +# tap_pub_parent_sync filter is: (a > 15) +# tap_pub_child_sync filter is: (a < 15) +# - INSERT (14) NO, 14 < 15 +# - INSERT (16) YES, 16 > 15 +$result = + $node_subscriber->safe_psql('postgres', + "SELECT a FROM tab_rowfilter_parent_sync ORDER BY 1"); +is( $result, qq(16), + 'check initial data copy from tab_rowfilter_parent_sync'); +$result = + $node_subscriber->safe_psql('postgres', + "SELECT a FROM tab_rowfilter_child_sync ORDER BY 1"); +is( $result, qq(), + 'check initial data copy from tab_rowfilter_child_sync'); + # The following commands are executed after CREATE SUBSCRIPTION, so these SQL # commands are for testing normal logical replication behavior. # diff --git a/src/test/subscription/t/031_column_list.pl b/src/test/subscription/t/031_column_list.pl index fd77757352a..b67292ba9c6 100644 --- a/src/test/subscription/t/031_column_list.pl +++ b/src/test/subscription/t/031_column_list.pl @@ -959,16 +959,21 @@ $node_publisher->safe_psql( CREATE TABLE test_root_1 PARTITION OF test_root FOR VALUES FROM (1) TO (10); CREATE TABLE test_root_2 PARTITION OF test_root FOR VALUES FROM (10) TO (20); - CREATE PUBLICATION pub_root_true FOR TABLE test_root (a) WITH (publish_via_partition_root = true); + CREATE PUBLICATION pub_test_root FOR TABLE test_root (a) WITH (publish_via_partition_root = true); + CREATE PUBLICATION pub_test_root_1 FOR TABLE test_root_1 (a, b); -- initial data INSERT INTO test_root VALUES (1, 2, 3); INSERT INTO test_root VALUES (10, 20, 30); )); +# Subscribe to pub_test_root and pub_test_root_1 at the same time, which means +# that the initial data will be synced once, and only the column list of the +# parent table (test_root) in the publication pub_test_root will be used for +# both table sync and data replication. $node_subscriber->safe_psql( 'postgres', qq( - CREATE SUBSCRIPTION sub1 CONNECTION '$publisher_connstr' PUBLICATION pub_root_true; + CREATE SUBSCRIPTION sub1 CONNECTION '$publisher_connstr' PUBLICATION pub_test_root, pub_test_root_1; )); $node_subscriber->wait_for_subscription_sync; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 0b7bc457671..f45bcc52d39 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -3603,6 +3603,7 @@ pthread_mutex_t pthread_once_t pthread_t ptrdiff_t +published_rel pull_var_clause_context pull_varattnos_context pull_varnos_context |