Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b52adba

Browse files
Ensure we have a snapshot when updating pg_index entries.
Creating, reindexing, and dropping an index concurrently could entail accessing pg_index's TOAST table, which was recently added in commit b52c4fc. These code paths start and commit their own transactions, but they do not always set an active snapshot. This rightfully leads to assertion failures and ERRORs when trying to access pg_index's TOAST table, such as the following: ERROR: cannot fetch toast data without an active snapshot To fix, push an active snapshot just before each section of code that might require accessing pg_index's TOAST table, and pop it shortly afterwards. Reported-by: Alexander Lakhin Reviewed-by: Michael Paquier Discussion: https://postgr.es/m/a97d7401-e7c9-f771-6a00-037379f0a8bb%40gmail.com
1 parent 9726653 commit b52adba

File tree

4 files changed

+76
-0
lines changed

4 files changed

+76
-0
lines changed

src/backend/catalog/index.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2276,9 +2276,17 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
22762276
*/
22772277
WaitForLockers(heaplocktag, AccessExclusiveLock, true);
22782278

2279+
/*
2280+
* Updating pg_index might involve TOAST table access, so ensure we
2281+
* have a valid snapshot.
2282+
*/
2283+
PushActiveSnapshot(GetTransactionSnapshot());
2284+
22792285
/* Finish invalidation of index and mark it as dead */
22802286
index_concurrently_set_dead(heapId, indexId);
22812287

2288+
PopActiveSnapshot();
2289+
22822290
/*
22832291
* Again, commit the transaction to make the pg_index update visible
22842292
* to other sessions.
@@ -2326,6 +2334,16 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
23262334

23272335
RelationForgetRelation(indexId);
23282336

2337+
/*
2338+
* Updating pg_index might involve TOAST table access, so ensure we have a
2339+
* valid snapshot. We only expect to get here without a snapshot in the
2340+
* concurrent path.
2341+
*/
2342+
if (concurrent)
2343+
PushActiveSnapshot(GetTransactionSnapshot());
2344+
else
2345+
Assert(HaveRegisteredOrActiveSnapshot());
2346+
23292347
/*
23302348
* fix INDEX relation, and check for expressional index
23312349
*/
@@ -2343,6 +2361,9 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
23432361
ReleaseSysCache(tuple);
23442362
table_close(indexRelation, RowExclusiveLock);
23452363

2364+
if (concurrent)
2365+
PopActiveSnapshot();
2366+
23462367
/*
23472368
* if it has any expression columns, we might have stored statistics about
23482369
* them.

src/backend/commands/indexcmds.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,11 +1798,19 @@ DefineIndex(Oid tableId,
17981798
PROGRESS_CREATEIDX_PHASE_WAIT_3);
17991799
WaitForOlderSnapshots(limitXmin, true);
18001800

1801+
/*
1802+
* Updating pg_index might involve TOAST table access, so ensure we have a
1803+
* valid snapshot.
1804+
*/
1805+
PushActiveSnapshot(GetTransactionSnapshot());
1806+
18011807
/*
18021808
* Index can now be marked valid -- update its pg_index entry
18031809
*/
18041810
index_set_state_flags(indexRelationId, INDEX_CREATE_SET_VALID);
18051811

1812+
PopActiveSnapshot();
1813+
18061814
/*
18071815
* The pg_index update will cause backends (including this one) to update
18081816
* relcache entries for the index itself, but we should also send a
@@ -4256,12 +4264,20 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
42564264
get_rel_namespace(oldidx->tableId),
42574265
false);
42584266

4267+
/*
4268+
* Updating pg_index might involve TOAST table access, so ensure we
4269+
* have a valid snapshot.
4270+
*/
4271+
PushActiveSnapshot(GetTransactionSnapshot());
4272+
42594273
/*
42604274
* Swap old index with the new one. This also marks the new one as
42614275
* valid and the old one as not valid.
42624276
*/
42634277
index_concurrently_swap(newidx->indexId, oldidx->indexId, oldName);
42644278

4279+
PopActiveSnapshot();
4280+
42654281
/*
42664282
* Invalidate the relcache for the table, so that after this commit
42674283
* all sessions will refresh any cached plans that might reference the
@@ -4312,7 +4328,15 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
43124328
*/
43134329
CHECK_FOR_INTERRUPTS();
43144330

4331+
/*
4332+
* Updating pg_index might involve TOAST table access, so ensure we
4333+
* have a valid snapshot.
4334+
*/
4335+
PushActiveSnapshot(GetTransactionSnapshot());
4336+
43154337
index_concurrently_set_dead(oldidx->tableId, oldidx->indexId);
4338+
4339+
PopActiveSnapshot();
43164340
}
43174341

43184342
/* Commit this transaction to make the updates visible. */

src/test/regress/expected/indexing.out

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,3 +1640,18 @@ select indexrelid::regclass, indisvalid, indisreplident,
16401640
(3 rows)
16411641

16421642
drop table parted_replica_tab;
1643+
-- test that indexing commands work with TOASTed values in pg_index
1644+
create table test_pg_index_toast_table (a int);
1645+
create or replace function test_pg_index_toast_func (a int, b int[])
1646+
returns bool as $$ select true $$ language sql immutable;
1647+
select array_agg(n) b from generate_series(1, 10000) n \gset
1648+
create index concurrently test_pg_index_toast_index
1649+
on test_pg_index_toast_table (test_pg_index_toast_func(a, :'b'));
1650+
reindex index concurrently test_pg_index_toast_index;
1651+
drop index concurrently test_pg_index_toast_index;
1652+
create index test_pg_index_toast_index
1653+
on test_pg_index_toast_table (test_pg_index_toast_func(a, :'b'));
1654+
reindex index test_pg_index_toast_index;
1655+
drop index test_pg_index_toast_index;
1656+
drop function test_pg_index_toast_func;
1657+
drop table test_pg_index_toast_table;

src/test/regress/sql/indexing.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,3 +919,19 @@ select indexrelid::regclass, indisvalid, indisreplident,
919919
where indexrelid::regclass::text like 'parted_replica%'
920920
order by indexrelid::regclass::text collate "C";
921921
drop table parted_replica_tab;
922+
923+
-- test that indexing commands work with TOASTed values in pg_index
924+
create table test_pg_index_toast_table (a int);
925+
create or replace function test_pg_index_toast_func (a int, b int[])
926+
returns bool as $$ select true $$ language sql immutable;
927+
select array_agg(n) b from generate_series(1, 10000) n \gset
928+
create index concurrently test_pg_index_toast_index
929+
on test_pg_index_toast_table (test_pg_index_toast_func(a, :'b'));
930+
reindex index concurrently test_pg_index_toast_index;
931+
drop index concurrently test_pg_index_toast_index;
932+
create index test_pg_index_toast_index
933+
on test_pg_index_toast_table (test_pg_index_toast_func(a, :'b'));
934+
reindex index test_pg_index_toast_index;
935+
drop index test_pg_index_toast_index;
936+
drop function test_pg_index_toast_func;
937+
drop table test_pg_index_toast_table;

0 commit comments

Comments
 (0)