]> granicus.if.org Git - postgresql/commitdiff
Simplify restriction handling of two-phase commit for temporary objects
authorMichael Paquier <michael@paquier.xyz>
Sat, 26 Jan 2019 01:45:23 +0000 (10:45 +0900)
committerMichael Paquier <michael@paquier.xyz>
Sat, 26 Jan 2019 01:45:23 +0000 (10:45 +0900)
There were two flags used to track the access to temporary tables and
to the temporary namespace of a session which are used to restrict
PREPARE TRANSACTION, however the first control flag is a concept
included in the second.  This removes the flag for temporary table
tracking, keeping around only the one at namespace level.

Author: Michael Paquier
Reviewed-by: Álvaro Herrera
Discussion: https://postgr.es/m/20190118053126.GH1883@paquier.xyz

src/backend/access/common/relation.c
src/backend/access/transam/xact.c
src/backend/commands/lockcmds.c
src/backend/commands/tablecmds.c
src/include/access/xact.h
src/test/modules/test_extensions/expected/test_extensions.out
src/test/regress/expected/temp.out

index beec34f126f23d553676022b67d04a863aa59b24..41a0051f88ef07338f22d91a389398d8764301e3 100644 (file)
@@ -71,7 +71,7 @@ relation_open(Oid relationId, LOCKMODE lockmode)
 
        /* Make note that we've accessed a temporary relation */
        if (RelationUsesLocalBuffers(r))
-               MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL;
+               MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
 
        pgstat_initstats(r);
 
@@ -121,7 +121,7 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
 
        /* Make note that we've accessed a temporary relation */
        if (RelationUsesLocalBuffers(r))
-               MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL;
+               MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
 
        pgstat_initstats(r);
 
index 7c3a9c1e899a6a978b795efee710315cee7ed9ca..0181976964c54b80dd4de9e545e52e19ebe7e1f3 100644 (file)
@@ -2266,6 +2266,11 @@ PrepareTransaction(void)
         * clean up the source backend's local buffers and ON COMMIT state if the
         * prepared xact includes a DROP of a temp table.
         *
+        * Other objects types, like functions, operators or extensions, share the
+        * same restriction as they should not be created, locked or dropped as
+        * this can mess up with this session or even a follow-up session trying
+        * to use the same temporary namespace.
+        *
         * We must check this after executing any ON COMMIT actions, because they
         * might still access a temp relation.
         *
@@ -2273,22 +2278,10 @@ PrepareTransaction(void)
         * cases, such as a temp table created and dropped all within the
         * transaction.  That seems to require much more bookkeeping though.
         */
-       if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPREL))
-               ereport(ERROR,
-                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                errmsg("cannot PREPARE a transaction that has operated on temporary tables")));
-
-       /*
-        * Similarly, PREPARE TRANSACTION is not allowed if the temporary
-        * namespace has been involved in this transaction as we cannot allow it
-        * to create, lock, or even drop objects within the temporary namespace
-        * as this can mess up with this session or even a follow-up session
-        * trying to use the same temporary namespace.
-        */
        if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPNAMESPACE))
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                errmsg("cannot PREPARE a transaction that has operated on temporary namespace")));
+                                errmsg("cannot PREPARE a transaction that has operated on temporary objects")));
 
        /*
         * Likewise, don't allow PREPARE after pg_export_snapshot.  This could be
index f4da564e012b8e638467ad27ff1c6a25ddc904c8..43bba717f222895b132606037518c23412ec1f5b 100644 (file)
@@ -108,7 +108,7 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
         */
        relpersistence = get_rel_persistence(relid);
        if (relpersistence == RELPERSISTENCE_TEMP)
-               MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL;
+               MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
 
        /* Check permissions. */
        aclresult = LockTableAclCheck(relid, lockmode, GetUserId());
index 36fdcc0d52cd7d66fe902fb8edd74b50c97907d9..9daf3e6588fb355fd8bceb5f9466a483351e133b 100644 (file)
@@ -13642,7 +13642,7 @@ PreCommit_on_commit_actions(void)
                                 * relations, we can skip truncating ON COMMIT DELETE ROWS
                                 * tables, as they must still be empty.
                                 */
-                               if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPREL))
+                               if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPNAMESPACE))
                                        oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
                                break;
                        case ONCOMMIT_DROP:
index ed21a13896f49315d133ce40a3100d9aabfbe208..426e77846f9278988e94c21f57d6257de0028350 100644 (file)
@@ -87,10 +87,10 @@ extern int  synchronous_commit;
 extern int     MyXactFlags;
 
 /*
- * XACT_FLAGS_ACCESSEDTEMPREL - set when a temporary relation is accessed. We
- * don't allow PREPARE TRANSACTION in that case.
+ * XACT_FLAGS_ACCESSEDTEMPNAMESPACE - set when a temporary object is accessed.
+ * We don't allow PREPARE TRANSACTION in that case.
  */
-#define XACT_FLAGS_ACCESSEDTEMPREL                             (1U << 0)
+#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE               (1U << 0)
 
 /*
  * XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK - records whether the top level xact
@@ -98,12 +98,6 @@ extern int   MyXactFlags;
  */
 #define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK (1U << 1)
 
-/*
- * XACT_FLAGS_ACCESSEDTEMPNAMESPACE - set when a temporary namespace is
- * accessed.  We don't allow PREPARE TRANSACTION in that case.
- */
-#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE               (1U << 2)
-
 /*
  *     start- and end-of-transaction callbacks for dynamically loaded modules
  */
index 1eec5a37d33c8f4eedbd2681e2f01fd707880988..b5cbdfcad4f337c820c34e864fb662d5bb6ea52b 100644 (file)
@@ -148,7 +148,7 @@ SELECT create_extension_with_temp_schema();
 (1 row)
 
 PREPARE TRANSACTION 'twophase_extension';
-ERROR:  cannot PREPARE a transaction that has operated on temporary namespace
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 -- Clean up
 DROP TABLE test_ext4_tab;
 DROP FUNCTION create_extension_with_temp_schema();
index d6d8f25141e1a2bb75eebf9b16d5c745ca9263bc..056e5ecf33c9c621d7d12ced9f3b3ba0b812b266 100644 (file)
@@ -310,32 +310,32 @@ begin;
 create function pg_temp.twophase_func() returns void as
   $$ select '2pc_func'::text $$ language sql;
 prepare transaction 'twophase_func';
-ERROR:  cannot PREPARE a transaction that has operated on temporary namespace
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 -- Function drop
 create function pg_temp.twophase_func() returns void as
   $$ select '2pc_func'::text $$ language sql;
 begin;
 drop function pg_temp.twophase_func();
 prepare transaction 'twophase_func';
-ERROR:  cannot PREPARE a transaction that has operated on temporary namespace
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 -- Operator creation
 begin;
 create operator pg_temp.@@ (leftarg = int4, rightarg = int4, procedure = int4mi);
 prepare transaction 'twophase_operator';
-ERROR:  cannot PREPARE a transaction that has operated on temporary namespace
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 -- These generate errors about temporary tables.
 begin;
 create type pg_temp.twophase_type as (a int);
 prepare transaction 'twophase_type';
-ERROR:  cannot PREPARE a transaction that has operated on temporary tables
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 begin;
 create view pg_temp.twophase_view as select 1;
 prepare transaction 'twophase_view';
-ERROR:  cannot PREPARE a transaction that has operated on temporary tables
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 begin;
 create sequence pg_temp.twophase_seq;
 prepare transaction 'twophase_sequence';
-ERROR:  cannot PREPARE a transaction that has operated on temporary tables
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 -- Temporary tables cannot be used with two-phase commit.
 create temp table twophase_tab (a int);
 begin;
@@ -345,19 +345,19 @@ select a from twophase_tab;
 (0 rows)
 
 prepare transaction 'twophase_tab';
-ERROR:  cannot PREPARE a transaction that has operated on temporary tables
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 begin;
 insert into twophase_tab values (1);
 prepare transaction 'twophase_tab';
-ERROR:  cannot PREPARE a transaction that has operated on temporary tables
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 begin;
 lock twophase_tab in access exclusive mode;
 prepare transaction 'twophase_tab';
-ERROR:  cannot PREPARE a transaction that has operated on temporary tables
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 begin;
 drop table twophase_tab;
 prepare transaction 'twophase_tab';
-ERROR:  cannot PREPARE a transaction that has operated on temporary tables
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects
 -- Corner case: current_schema may create a temporary schema if namespace
 -- creation is pending, so check after that.  First reset the connection
 -- to remove the temporary namespace, and make sure that non-parallel plans
@@ -374,4 +374,4 @@ SELECT current_schema() ~ 'pg_temp' AS is_temp_schema;
 (1 row)
 
 PREPARE TRANSACTION 'twophase_search';
-ERROR:  cannot PREPARE a transaction that has operated on temporary namespace
+ERROR:  cannot PREPARE a transaction that has operated on temporary objects