From 6e2a6bdfb77870213d051f31b2b6683ccea45ab2 Mon Sep 17 00:00:00 2001 From: Himanshu Upadhyaya Date: Mon, 5 Apr 2021 21:04:56 +0530 Subject: [PATCH v1] PREPARE TRANSACTION must fail when mixed with temporary object. --- src/backend/utils/cache/typcache.c | 30 ++++++++++++++++-------------- src/test/regress/expected/temp.out | 14 ++++++++++++++ src/test/regress/sql/temp.sql | 14 ++++++++++++++ 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index 4915ef5934..36fac6150d 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -813,7 +813,6 @@ lookup_type_cache(Oid type_id, int flags) * If it's a composite type (row type), get tupdesc if requested */ if ((flags & TYPECACHE_TUPDESC) && - typentry->tupDesc == NULL && typentry->typtype == TYPTYPE_COMPOSITE) { load_typcache_tupdesc(typentry); @@ -881,21 +880,25 @@ load_typcache_tupdesc(TypeCacheEntry *typentry) /* * Link to the tupdesc and increment its refcount (we assert it's a - * refcounted descriptor). We don't use IncrTupleDescRefCount() for this, - * because the reference mustn't be entered in the current resource owner; + * refcounted descriptor), do this only if it was not populated previously. + * We don't use IncrTupleDescRefCount() for this, because the reference + * mustn't be entered in the current resource owner; * it can outlive the current query. */ - typentry->tupDesc = RelationGetDescr(rel); + if (typentry->tupDesc == NULL) + { + typentry->tupDesc = RelationGetDescr(rel); - Assert(typentry->tupDesc->tdrefcount > 0); - typentry->tupDesc->tdrefcount++; + Assert(typentry->tupDesc->tdrefcount > 0); + typentry->tupDesc->tdrefcount++; - /* - * In future, we could take some pains to not change tupDesc_identifier if - * the tupdesc didn't really change; but for now it's not worth it. - */ - typentry->tupDesc_identifier = ++tupledesc_id_counter; + /* + * In future, we could take some pains to not change tupDesc_identifier if + * the tupdesc didn't really change; but for now it's not worth it. + */ + typentry->tupDesc_identifier = ++tupledesc_id_counter; + } relation_close(rel, AccessShareLock); } @@ -1529,9 +1532,8 @@ cache_record_field_properties(TypeCacheEntry *typentry) int newflags; int i; - /* Fetch composite type's tupdesc if we don't have it already */ - if (typentry->tupDesc == NULL) - load_typcache_tupdesc(typentry); + /* Fetch composite type's tupdesc */ + load_typcache_tupdesc(typentry); tupdesc = typentry->tupDesc; /* Must bump the refcount while we do additional catalog lookups */ diff --git a/src/test/regress/expected/temp.out b/src/test/regress/expected/temp.out index a5b3ed34a3..ebf5909389 100644 --- a/src/test/regress/expected/temp.out +++ b/src/test/regress/expected/temp.out @@ -319,6 +319,20 @@ select relname from pg_class where relname ~ '^temp_inh_oncommit_test'; (1 row) drop table temp_inh_oncommit_test; +-- Test for accessing Temporary table +-- in prepare transaction. +-- These cases must fail and generate errors about Temporary objects. +CREATE TEMP TABLE temp_tbl (first TEXT, last TEXT); +BEGIN; +CREATE FUNCTION longname(temp_tbl) RETURNS TEXT LANGUAGE SQL +AS $$SELECT $1.first || ' ' || $1.last$$; +PREPARE TRANSACTION 'temp_tbl_access'; +ERROR: cannot PREPARE a transaction that has operated on temporary objects +BEGIN; +CREATE FUNCTION longname(temp_tbl) RETURNS TEXT LANGUAGE SQL +AS $$SELECT $1.first || ' ' || $1.last$$; +PREPARE TRANSACTION 'temp_tbl_access'; +ERROR: cannot PREPARE a transaction that has operated on temporary objects -- Tests with two-phase commit -- Transactions creating objects in a temporary namespace cannot be used -- with two-phase commit. diff --git a/src/test/regress/sql/temp.sql b/src/test/regress/sql/temp.sql index 424d12b283..7cda474782 100644 --- a/src/test/regress/sql/temp.sql +++ b/src/test/regress/sql/temp.sql @@ -240,6 +240,20 @@ select * from temp_inh_oncommit_test; select relname from pg_class where relname ~ '^temp_inh_oncommit_test'; drop table temp_inh_oncommit_test; +-- Test for accessing Temporary table +-- in prepare transaction. +-- These cases must fail and generate errors about Temporary objects. +CREATE TEMP TABLE temp_tbl (first TEXT, last TEXT); +BEGIN; +CREATE FUNCTION longname(temp_tbl) RETURNS TEXT LANGUAGE SQL +AS $$SELECT $1.first || ' ' || $1.last$$; +PREPARE TRANSACTION 'temp_tbl_access'; + +BEGIN; +CREATE FUNCTION longname(temp_tbl) RETURNS TEXT LANGUAGE SQL +AS $$SELECT $1.first || ' ' || $1.last$$; +PREPARE TRANSACTION 'temp_tbl_access'; + -- Tests with two-phase commit -- Transactions creating objects in a temporary namespace cannot be used -- with two-phase commit. -- 2.25.1