0001-Use-more-safe-procedure-to-check-a-non-transactional.patch

text/plain

Filename: 0001-Use-more-safe-procedure-to-check-a-non-transactional.patch
Type: text/plain
Part: 0
Message: Assertion on create index concurrently

Patch

Format: format-patch
Series: patch 0001
Subject: Use more safe procedure to check a non-transactional CONCURRENT operation on transactional updates.
File+
src/backend/catalog/index.c 6 2
src/test/regress/expected/create_index.out 17 0
src/test/regress/sql/create_index.sql 13 0
From 2d658eb9830c78e875b08daa86c608d5f327b1f3 Mon Sep 17 00:00:00 2001
From: "Andrey V. Lepikhov" <a.lepikhov@postgrespro.ru>
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