Skip to content

Commit e8de627

Browse files
committed
Fix construction of updated-columns bitmap in logical replication.
Commit b9c130a failed to apply the publisher-to-subscriber column mapping while checking which columns were updated. Perhaps less significantly, it didn't exclude dropped columns either. This could result in an incorrect updated-columns bitmap and thus wrong decisions about whether to fire column-specific triggers on the subscriber while applying updates. In HEAD (since commit 9de77b5), it could also result in accesses off the end of the colstatus array, as detected by buildfarm member skink. Fix the logic, and adjust 003_constraints.pl so that the problem is exposed in unpatched code. In HEAD, also add some assertions to check that we don't access off the ends of these newly variable-sized arrays. Back-patch to v10, as b9c130a was. Discussion: https://postgr.es/m/CAH2-Wz=79hKQ4++c5A060RYbjTHgiYTHz=fw6mptCtgghH2gJA@mail.gmail.com
1 parent dcd6718 commit e8de627

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

src/backend/replication/logical/worker.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -748,9 +748,16 @@ apply_handle_update(StringInfo s)
748748
target_rte = list_nth(estate->es_range_table, 0);
749749
for (i = 0; i < remoteslot->tts_tupleDescriptor->natts; i++)
750750
{
751-
if (newtup.changed[i])
752-
target_rte->updatedCols = bms_add_member(target_rte->updatedCols,
753-
i + 1 - FirstLowInvalidHeapAttributeNumber);
751+
Form_pg_attribute att = TupleDescAttr(remoteslot->tts_tupleDescriptor, i);
752+
int remoteattnum = rel->attrmap[i];
753+
754+
if (!att->attisdropped && remoteattnum >= 0)
755+
{
756+
if (newtup.changed[remoteattnum])
757+
target_rte->updatedCols =
758+
bms_add_member(target_rte->updatedCols,
759+
i + 1 - FirstLowInvalidHeapAttributeNumber);
760+
}
754761
}
755762

756763
PushActiveSnapshot(GetTransactionSnapshot());

src/test/subscription/t/003_constraints.pl

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
$node_publisher->safe_psql('postgres',
2020
"CREATE TABLE tab_fk (bid int PRIMARY KEY);");
2121
$node_publisher->safe_psql('postgres',
22-
"CREATE TABLE tab_fk_ref (id int PRIMARY KEY, bid int REFERENCES tab_fk (bid));"
22+
"CREATE TABLE tab_fk_ref (id int PRIMARY KEY, junk text, bid int REFERENCES tab_fk (bid));"
2323
);
2424

25-
# Setup structure on subscriber
25+
# Setup structure on subscriber; column order intentionally different
2626
$node_subscriber->safe_psql('postgres',
2727
"CREATE TABLE tab_fk (bid int PRIMARY KEY);");
2828
$node_subscriber->safe_psql('postgres',
29-
"CREATE TABLE tab_fk_ref (id int PRIMARY KEY, bid int REFERENCES tab_fk (bid));"
29+
"CREATE TABLE tab_fk_ref (id int PRIMARY KEY, bid int REFERENCES tab_fk (bid), junk text);"
3030
);
3131

3232
# Setup logical replication
@@ -43,8 +43,10 @@
4343

4444
$node_publisher->safe_psql('postgres',
4545
"INSERT INTO tab_fk (bid) VALUES (1);");
46+
# "junk" value is meant to be large enough to force out-of-line storage
4647
$node_publisher->safe_psql('postgres',
47-
"INSERT INTO tab_fk_ref (id, bid) VALUES (1, 1);");
48+
"INSERT INTO tab_fk_ref (id, bid, junk) VALUES (1, 1, repeat(pi()::text,20000));"
49+
);
4850

4951
$node_publisher->wait_for_catchup($appname);
5052

@@ -127,7 +129,8 @@ BEGIN
127129

128130
$result = $node_subscriber->safe_psql('postgres',
129131
"SELECT count(*), min(id), max(id) FROM tab_fk_ref;");
130-
is($result, qq(2|1|2), 'check column trigger applied on even for other column');
132+
is($result, qq(2|1|2),
133+
'check column trigger applied even on update for other column');
131134

132135
$node_subscriber->stop('fast');
133136
$node_publisher->stop('fast');

0 commit comments

Comments
 (0)