From 2d658eb9830c78e875b08daa86c608d5f327b1f3 Mon Sep 17 00:00:00 2001 From: "Andrey V. Lepikhov" Date: Sat, 26 Jun 2021 19:54:25 +0300 Subject: [PATCH] Use more safe procedure to check a non-transactional CONCURRENT operation on transactional updates. --- src/backend/catalog/index.c | 8 ++++++-- src/test/regress/expected/create_index.out | 17 +++++++++++++++++ src/test/regress/sql/create_index.sql | 13 +++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index b9eed8ec38..ca91a7c74f 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -3395,8 +3395,12 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action) HeapTuple indexTuple; Form_pg_index indexForm; - /* Assert that current xact hasn't done any transactional updates */ - Assert(GetTopTransactionIdIfAny() == InvalidTransactionId); + /* Check that current xact hasn't done any transactional updates */ + if (GetTopTransactionIdIfAny() != InvalidTransactionId) + ereport(ERROR, + (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), + errmsg("Some transactional updates were made during a concurrent index operation"))); + /* Open pg_index and fetch a writable copy of the index's tuple */ pg_index = table_open(IndexRelationId, RowExclusiveLock); diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 8e11c089b1..93103334d8 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -1393,6 +1393,23 @@ BEGIN; CREATE INDEX CONCURRENTLY concur_index7 ON concur_heap(f1); ERROR: CREATE INDEX CONCURRENTLY cannot run inside a transaction block COMMIT; +CREATE FUNCTION predicate() RETURNS bool IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + EXECUTE 'SELECT txid_current()'; + RETURN true; +END; $$; +-- You can't do any transactional updates during concurrent index build. +CREATE INDEX CONCURRENTLY concur_index8 ON concur_heap (f1) WHERE predicate(); +ERROR: Some transactional updates were made during a concurrent index operation +-- Index exists but invalid. It must be actualized after REINDEX TABLE command. +SELECT relname,indisvalid FROM pg_class, pg_index + WHERE relname = 'concur_index8' AND oid = indexrelid; + relname | indisvalid +---------------+------------ + concur_index8 | f +(1 row) + +DROP INDEX concur_index8; -- But you can do a regular index build in a transaction BEGIN; CREATE INDEX std_index on concur_heap(f2); diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index c0392f052d..71779e3dce 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -487,6 +487,19 @@ BEGIN; CREATE INDEX CONCURRENTLY concur_index7 ON concur_heap(f1); COMMIT; +CREATE FUNCTION predicate() RETURNS bool IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + EXECUTE 'SELECT txid_current()'; + RETURN true; +END; $$; + +-- You can't do any transactional updates during concurrent index build. +CREATE INDEX CONCURRENTLY concur_index8 ON concur_heap (f1) WHERE predicate(); +-- Index exists but invalid. It must be actualized after REINDEX TABLE command. +SELECT relname,indisvalid FROM pg_class, pg_index + WHERE relname = 'concur_index8' AND oid = indexrelid; +DROP INDEX concur_index8; + -- But you can do a regular index build in a transaction BEGIN; CREATE INDEX std_index on concur_heap(f2); -- 2.31.1