Skip to content

Commit efe706e

Browse files
author
Amit Kapila
committed
Fix fetching default toast value during decoding of in-progress transactions.
During logical decoding of in-progress transactions, we perform the toast table scan while fetching the default toast value for an attribute. We forgot to initialize the flag during this scan to indicate that the system table scan is in progress. We need this flag to ensure that during logical decoding we never directly access the tableam or heap APIs because we check for concurrent aborts only in systable_* APIs. Reported-by: Alexander Lakhin Author: Takeshi Ideriha, Hou Zhijie Reviewed-by: Amit Kapila, Hou Zhijie Backpatch-through: 14 Discussion: https://postgr.es/m/18641-6687273b7f15269d@postgresql.org
1 parent 3922c9e commit efe706e

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

contrib/test_decoding/expected/stream.out

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,26 @@ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'incl
106106
committing streamed transaction
107107
(17 rows)
108108

109+
-- Test that accessing a TOAST table in streaming mode is allowed.
110+
-- Create a table with a column that uses a TOASTed default value.
111+
-- (temporarily hide query, to avoid the long CREATE TABLE stmt)
112+
\set ECHO none
113+
BEGIN;
114+
INSERT INTO test_tab SELECT repeat('a', 6000) || g.i FROM generate_series(1, 350) g(i);
115+
-- Force WAL flush, so that the above changes will be streamed.
116+
SELECT 'force flush' FROM pg_switch_wal();
117+
?column?
118+
-------------
119+
force flush
120+
(1 row)
121+
122+
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1');
123+
count
124+
-------
125+
315
126+
(1 row)
127+
128+
COMMIT;
109129
DROP TABLE stream_test;
110130
SELECT pg_drop_replication_slot('regression_slot');
111131
pg_drop_replication_slot

contrib/test_decoding/sql/stream.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,23 @@ toasted-123456789012345678901234567890123456789012345678901234567890123456789012
4444

4545
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL,NULL, 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1');
4646

47+
-- Test that accessing a TOAST table in streaming mode is allowed.
48+
49+
-- Create a table with a column that uses a TOASTed default value.
50+
-- (temporarily hide query, to avoid the long CREATE TABLE stmt)
51+
\set ECHO none
52+
SELECT 'CREATE TABLE test_tab (a text DEFAULT ''' || string_agg('toast value', '') || ''');' FROM generate_series(1, 4000)
53+
\gexec
54+
\set ECHO all
55+
56+
BEGIN;
57+
INSERT INTO test_tab SELECT repeat('a', 6000) || g.i FROM generate_series(1, 350) g(i);
58+
59+
-- Force WAL flush, so that the above changes will be streamed.
60+
SELECT 'force flush' FROM pg_switch_wal();
61+
62+
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1', 'stream-changes', '1');
63+
COMMIT;
64+
4765
DROP TABLE stream_test;
4866
SELECT pg_drop_replication_slot('regression_slot');

src/backend/access/index/genam.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,14 @@ systable_beginscan_ordered(Relation heapRelation,
700700
index_rescan(sysscan->iscan, key, nkeys, NULL, 0);
701701
sysscan->scan = NULL;
702702

703+
/*
704+
* If CheckXidAlive is set then set a flag to indicate that system table
705+
* scan is in-progress. See detailed comments in xact.c where these
706+
* variables are declared.
707+
*/
708+
if (TransactionIdIsValid(CheckXidAlive))
709+
bsysscan = true;
710+
703711
return sysscan;
704712
}
705713

@@ -744,6 +752,14 @@ systable_endscan_ordered(SysScanDesc sysscan)
744752
index_endscan(sysscan->iscan);
745753
if (sysscan->snapshot)
746754
UnregisterSnapshot(sysscan->snapshot);
755+
756+
/*
757+
* Reset the bsysscan flag at the end of the systable scan. See detailed
758+
* comments in xact.c where these variables are declared.
759+
*/
760+
if (TransactionIdIsValid(CheckXidAlive))
761+
bsysscan = false;
762+
747763
pfree(sysscan);
748764
}
749765

0 commit comments

Comments
 (0)