aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/catalog/pg_publication.c30
-rw-r--r--src/backend/catalog/system_views.sql5
-rw-r--r--src/backend/replication/pgoutput/pgoutput.c17
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/test/regress/expected/rules.out2
-rw-r--r--src/test/subscription/t/031_column_list.pl47
6 files changed, 97 insertions, 6 deletions
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 9571c669f77..a98fcad421f 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -1153,6 +1153,36 @@ pg_get_publication_tables(PG_FUNCTION_ARGS)
nulls[2] = true;
}
+ /* Show all columns when the column list is not specified. */
+ if (nulls[1] == true)
+ {
+ Relation rel = table_open(relid, AccessShareLock);
+ int nattnums = 0;
+ int16 *attnums;
+ TupleDesc desc = RelationGetDescr(rel);
+ int i;
+
+ attnums = (int16 *) palloc(desc->natts * sizeof(int16));
+
+ for (i = 0; i < desc->natts; i++)
+ {
+ Form_pg_attribute att = TupleDescAttr(desc, i);
+
+ if (att->attisdropped || att->attgenerated)
+ continue;
+
+ attnums[nattnums++] = att->attnum;
+ }
+
+ if (nattnums > 0)
+ {
+ values[1] = PointerGetDatum(buildint2vector(attnums, nattnums));
+ nulls[1] = false;
+ }
+
+ table_close(rel, AccessShareLock);
+ }
+
rettuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(rettuple));
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 447c9b970f1..d2a8c82900e 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -371,9 +371,8 @@ CREATE VIEW pg_publication_tables AS
C.relname AS tablename,
( SELECT array_agg(a.attname ORDER BY a.attnum)
FROM pg_attribute a
- WHERE a.attrelid = GPT.relid AND a.attnum > 0 AND
- NOT a.attisdropped AND
- (a.attnum = ANY(GPT.attrs) OR GPT.attrs IS NULL)
+ WHERE a.attrelid = GPT.relid AND
+ a.attnum = ANY(GPT.attrs)
) AS attnames,
pg_get_expr(GPT.qual, GPT.relid) AS rowfilter
FROM pg_publication P,
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 19c10c028f9..1a80d67bb9c 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -1058,16 +1058,31 @@ pgoutput_column_list_init(PGOutputData *data, List *publications,
/* Build the column list bitmap in the per-entry context. */
if (!pub_no_list) /* when not null */
{
+ int i;
+ int nliveatts = 0;
+ TupleDesc desc = RelationGetDescr(relation);
+
pgoutput_ensure_entry_cxt(data, entry);
cols = pub_collist_to_bitmapset(cols, cfdatum,
entry->entry_cxt);
+ /* Get the number of live attributes. */
+ for (i = 0; i < desc->natts; i++)
+ {
+ Form_pg_attribute att = TupleDescAttr(desc, i);
+
+ if (att->attisdropped || att->attgenerated)
+ continue;
+
+ nliveatts++;
+ }
+
/*
* If column list includes all the columns of the table,
* set it to NULL.
*/
- if (bms_num_members(cols) == RelationGetNumberOfAttributes(relation))
+ if (bms_num_members(cols) == nliveatts)
{
bms_free(cols);
cols = NULL;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 3a0ef3d8740..2afed46b899 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202301092
+#define CATALOG_VERSION_NO 202301131
#endif
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index fb9f936d43a..a969ae63eb5 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1446,7 +1446,7 @@ pg_publication_tables| SELECT p.pubname,
c.relname AS tablename,
( SELECT array_agg(a.attname ORDER BY a.attnum) AS array_agg
FROM pg_attribute a
- WHERE ((a.attrelid = gpt.relid) AND (a.attnum > 0) AND (NOT a.attisdropped) AND ((a.attnum = ANY ((gpt.attrs)::smallint[])) OR (gpt.attrs IS NULL)))) AS attnames,
+ 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),
diff --git a/src/test/subscription/t/031_column_list.pl b/src/test/subscription/t/031_column_list.pl
index 8835ab30ff6..7c313e26eea 100644
--- a/src/test/subscription/t/031_column_list.pl
+++ b/src/test/subscription/t/031_column_list.pl
@@ -1184,6 +1184,53 @@ $result = $node_publisher->safe_psql(
is( $result, qq(t
t), 'check the number of columns in the old tuple');
+# TEST: Generated and dropped columns are not considered for the column list.
+# So, the publication having a column list except for those columns and a
+# publication without any column (aka all columns as part of the columns
+# list) are considered to have the same column list.
+$node_publisher->safe_psql(
+ 'postgres', qq(
+ CREATE TABLE test_mix_4 (a int PRIMARY KEY, b int, c int, d int GENERATED ALWAYS AS (a + 1) STORED);
+ ALTER TABLE test_mix_4 DROP COLUMN c;
+
+ CREATE PUBLICATION pub_mix_7 FOR TABLE test_mix_4 (a, b);
+ CREATE PUBLICATION pub_mix_8 FOR TABLE test_mix_4;
+
+ -- initial data
+ INSERT INTO test_mix_4 VALUES (1, 2);
+));
+
+$node_subscriber->safe_psql(
+ 'postgres', qq(
+ DROP SUBSCRIPTION sub1;
+ CREATE TABLE test_mix_4 (a int PRIMARY KEY, b int, c int, d int);
+));
+
+$node_subscriber->safe_psql(
+ 'postgres', qq(
+ CREATE SUBSCRIPTION sub1 CONNECTION '$publisher_connstr' PUBLICATION pub_mix_7, pub_mix_8;
+));
+
+$node_subscriber->wait_for_subscription_sync;
+
+is( $node_subscriber->safe_psql(
+ 'postgres', "SELECT * FROM test_mix_4 ORDER BY a"),
+ qq(1|2||),
+ 'initial synchronization with multiple publications with the same column list'
+);
+
+$node_publisher->safe_psql(
+ 'postgres', qq(
+ INSERT INTO test_mix_4 VALUES (3, 4);
+));
+
+$node_publisher->wait_for_catchup('sub1');
+
+is( $node_subscriber->safe_psql(
+ 'postgres', "SELECT * FROM test_mix_4 ORDER BY a"),
+ qq(1|2||
+3|4||),
+ 'replication with multiple publications with the same column list');
# TEST: With a table included in multiple publications with different column
# lists, we should catch the error when creating the subscription.