mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
Simplify restriction handling of two-phase commit for temporary objects
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
This commit is contained in:
parent
df4c904440
commit
c9b75c5838
@ -71,7 +71,7 @@ relation_open(Oid relationId, LOCKMODE lockmode)
|
|||||||
|
|
||||||
/* Make note that we've accessed a temporary relation */
|
/* Make note that we've accessed a temporary relation */
|
||||||
if (RelationUsesLocalBuffers(r))
|
if (RelationUsesLocalBuffers(r))
|
||||||
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL;
|
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
|
||||||
|
|
||||||
pgstat_initstats(r);
|
pgstat_initstats(r);
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
|
|||||||
|
|
||||||
/* Make note that we've accessed a temporary relation */
|
/* Make note that we've accessed a temporary relation */
|
||||||
if (RelationUsesLocalBuffers(r))
|
if (RelationUsesLocalBuffers(r))
|
||||||
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL;
|
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
|
||||||
|
|
||||||
pgstat_initstats(r);
|
pgstat_initstats(r);
|
||||||
|
|
||||||
|
@ -2266,6 +2266,11 @@ PrepareTransaction(void)
|
|||||||
* clean up the source backend's local buffers and ON COMMIT state if the
|
* clean up the source backend's local buffers and ON COMMIT state if the
|
||||||
* prepared xact includes a DROP of a temp table.
|
* 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
|
* We must check this after executing any ON COMMIT actions, because they
|
||||||
* might still access a temp relation.
|
* might still access a temp relation.
|
||||||
*
|
*
|
||||||
@ -2273,22 +2278,10 @@ PrepareTransaction(void)
|
|||||||
* cases, such as a temp table created and dropped all within the
|
* cases, such as a temp table created and dropped all within the
|
||||||
* transaction. That seems to require much more bookkeeping though.
|
* 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))
|
if ((MyXactFlags & XACT_FLAGS_ACCESSEDTEMPNAMESPACE))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(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
|
* Likewise, don't allow PREPARE after pg_export_snapshot. This could be
|
||||||
|
@ -108,7 +108,7 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
|
|||||||
*/
|
*/
|
||||||
relpersistence = get_rel_persistence(relid);
|
relpersistence = get_rel_persistence(relid);
|
||||||
if (relpersistence == RELPERSISTENCE_TEMP)
|
if (relpersistence == RELPERSISTENCE_TEMP)
|
||||||
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL;
|
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
|
||||||
|
|
||||||
/* Check permissions. */
|
/* Check permissions. */
|
||||||
aclresult = LockTableAclCheck(relid, lockmode, GetUserId());
|
aclresult = LockTableAclCheck(relid, lockmode, GetUserId());
|
||||||
|
@ -13642,7 +13642,7 @@ PreCommit_on_commit_actions(void)
|
|||||||
* relations, we can skip truncating ON COMMIT DELETE ROWS
|
* relations, we can skip truncating ON COMMIT DELETE ROWS
|
||||||
* tables, as they must still be empty.
|
* 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);
|
oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid);
|
||||||
break;
|
break;
|
||||||
case ONCOMMIT_DROP:
|
case ONCOMMIT_DROP:
|
||||||
|
@ -87,10 +87,10 @@ extern int synchronous_commit;
|
|||||||
extern int MyXactFlags;
|
extern int MyXactFlags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XACT_FLAGS_ACCESSEDTEMPREL - set when a temporary relation is accessed. We
|
* XACT_FLAGS_ACCESSEDTEMPNAMESPACE - set when a temporary object is accessed.
|
||||||
* don't allow PREPARE TRANSACTION in that case.
|
* 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
|
* XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK - records whether the top level xact
|
||||||
@ -98,12 +98,6 @@ extern int MyXactFlags;
|
|||||||
*/
|
*/
|
||||||
#define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK (1U << 1)
|
#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
|
* start- and end-of-transaction callbacks for dynamically loaded modules
|
||||||
*/
|
*/
|
||||||
|
@ -148,7 +148,7 @@ SELECT create_extension_with_temp_schema();
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
PREPARE TRANSACTION 'twophase_extension';
|
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
|
-- Clean up
|
||||||
DROP TABLE test_ext4_tab;
|
DROP TABLE test_ext4_tab;
|
||||||
DROP FUNCTION create_extension_with_temp_schema();
|
DROP FUNCTION create_extension_with_temp_schema();
|
||||||
|
@ -310,32 +310,32 @@ begin;
|
|||||||
create function pg_temp.twophase_func() returns void as
|
create function pg_temp.twophase_func() returns void as
|
||||||
$$ select '2pc_func'::text $$ language sql;
|
$$ select '2pc_func'::text $$ language sql;
|
||||||
prepare transaction '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
|
||||||
-- Function drop
|
-- Function drop
|
||||||
create function pg_temp.twophase_func() returns void as
|
create function pg_temp.twophase_func() returns void as
|
||||||
$$ select '2pc_func'::text $$ language sql;
|
$$ select '2pc_func'::text $$ language sql;
|
||||||
begin;
|
begin;
|
||||||
drop function pg_temp.twophase_func();
|
drop function pg_temp.twophase_func();
|
||||||
prepare transaction '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
|
-- Operator creation
|
||||||
begin;
|
begin;
|
||||||
create operator pg_temp.@@ (leftarg = int4, rightarg = int4, procedure = int4mi);
|
create operator pg_temp.@@ (leftarg = int4, rightarg = int4, procedure = int4mi);
|
||||||
prepare transaction 'twophase_operator';
|
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.
|
-- These generate errors about temporary tables.
|
||||||
begin;
|
begin;
|
||||||
create type pg_temp.twophase_type as (a int);
|
create type pg_temp.twophase_type as (a int);
|
||||||
prepare transaction 'twophase_type';
|
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;
|
begin;
|
||||||
create view pg_temp.twophase_view as select 1;
|
create view pg_temp.twophase_view as select 1;
|
||||||
prepare transaction 'twophase_view';
|
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;
|
begin;
|
||||||
create sequence pg_temp.twophase_seq;
|
create sequence pg_temp.twophase_seq;
|
||||||
prepare transaction 'twophase_sequence';
|
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.
|
-- Temporary tables cannot be used with two-phase commit.
|
||||||
create temp table twophase_tab (a int);
|
create temp table twophase_tab (a int);
|
||||||
begin;
|
begin;
|
||||||
@ -345,19 +345,19 @@ select a from twophase_tab;
|
|||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
prepare transaction '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
|
||||||
begin;
|
begin;
|
||||||
insert into twophase_tab values (1);
|
insert into twophase_tab values (1);
|
||||||
prepare transaction '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
|
||||||
begin;
|
begin;
|
||||||
lock twophase_tab in access exclusive mode;
|
lock twophase_tab in access exclusive mode;
|
||||||
prepare transaction '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
|
||||||
begin;
|
begin;
|
||||||
drop table twophase_tab;
|
drop table twophase_tab;
|
||||||
prepare transaction '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
|
-- Corner case: current_schema may create a temporary schema if namespace
|
||||||
-- creation is pending, so check after that. First reset the connection
|
-- creation is pending, so check after that. First reset the connection
|
||||||
-- to remove the temporary namespace, and make sure that non-parallel plans
|
-- 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)
|
(1 row)
|
||||||
|
|
||||||
PREPARE TRANSACTION 'twophase_search';
|
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user