diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/transam/xact.c | 12 | ||||
-rw-r--r-- | src/backend/catalog/namespace.c | 59 | ||||
-rw-r--r-- | src/backend/commands/dropcmds.c | 8 | ||||
-rw-r--r-- | src/backend/commands/extension.c | 7 | ||||
-rw-r--r-- | src/backend/commands/lockcmds.c | 10 |
5 files changed, 81 insertions, 15 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index f665e38ecfc..18467d96d28 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -2279,6 +2279,18 @@ PrepareTransaction(void) 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"))); + + /* * Likewise, don't allow PREPARE after pg_export_snapshot. This could be * supported if we added cleanup logic to twophase.c, but for now it * doesn't seem worth the trouble. diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 5a6eb495d48..cdd5006a72f 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -192,6 +192,7 @@ char *namespace_search_path = NULL; /* Local functions */ static void recomputeNamespacePath(void); +static void AccessTempTableNamespace(bool force); static void InitTempTableNamespace(void); static void RemoveTempRelations(Oid tempNamespaceId); static void RemoveTempRelationsCallback(int code, Datum arg); @@ -459,9 +460,8 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) /* check for pg_temp alias */ if (strcmp(newRelation->schemaname, "pg_temp") == 0) { - /* Initialize temp namespace if first time through */ - if (!OidIsValid(myTempNamespace)) - InitTempTableNamespace(); + /* Initialize temp namespace */ + AccessTempTableNamespace(false); return myTempNamespace; } /* use exact schema given */ @@ -470,9 +470,8 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) } else if (newRelation->relpersistence == RELPERSISTENCE_TEMP) { - /* Initialize temp namespace if first time through */ - if (!OidIsValid(myTempNamespace)) - InitTempTableNamespace(); + /* Initialize temp namespace */ + AccessTempTableNamespace(false); return myTempNamespace; } else @@ -482,7 +481,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) if (activeTempCreationPending) { /* Need to initialize temp namespace */ - InitTempTableNamespace(); + AccessTempTableNamespace(true); return myTempNamespace; } namespaceId = activeCreationNamespace; @@ -2921,9 +2920,8 @@ LookupCreationNamespace(const char *nspname) /* check for pg_temp alias */ if (strcmp(nspname, "pg_temp") == 0) { - /* Initialize temp namespace if first time through */ - if (!OidIsValid(myTempNamespace)) - InitTempTableNamespace(); + /* Initialize temp namespace */ + AccessTempTableNamespace(false); return myTempNamespace; } @@ -2986,9 +2984,8 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p) /* check for pg_temp alias */ if (strcmp(schemaname, "pg_temp") == 0) { - /* Initialize temp namespace if first time through */ - if (!OidIsValid(myTempNamespace)) - InitTempTableNamespace(); + /* Initialize temp namespace */ + AccessTempTableNamespace(false); return myTempNamespace; } /* use exact schema given */ @@ -3002,7 +2999,7 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p) if (activeTempCreationPending) { /* Need to initialize temp namespace */ - InitTempTableNamespace(); + AccessTempTableNamespace(true); return myTempNamespace; } namespaceId = activeCreationNamespace; @@ -3833,6 +3830,38 @@ recomputeNamespacePath(void) } /* + * AccessTempTableNamespace + * Provide access to a temporary namespace, potentially creating it + * if not present yet. This routine registers if the namespace gets + * in use in this transaction. 'force' can be set to true to allow + * the caller to enforce the creation of the temporary namespace for + * use in this backend, which happens if its creation is pending. + */ +static void +AccessTempTableNamespace(bool force) +{ + /* + * Make note that this temporary namespace has been accessed in this + * transaction. + */ + MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE; + + /* + * If the caller attempting to access a temporary schema expects the + * creation of the namespace to be pending and should be enforced, then go + * through the creation. + */ + if (!force && OidIsValid(myTempNamespace)) + return; + + /* + * The temporary tablespace does not exist yet and is wanted, so + * initialize it. + */ + InitTempTableNamespace(); +} + +/* * InitTempTableNamespace * Initialize temp table namespace on first use in a particular backend */ @@ -4275,7 +4304,7 @@ fetch_search_path(bool includeImplicit) */ if (activeTempCreationPending) { - InitTempTableNamespace(); + AccessTempTableNamespace(true); recomputeNamespacePath(); } diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index 1dc1c746f1f..980ce89c62b 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -14,6 +14,7 @@ */ #include "postgres.h" +#include "access/xact.h" #include "access/heapam.h" #include "access/htup_details.h" #include "catalog/dependency.h" @@ -107,6 +108,13 @@ RemoveObjects(DropStmt *stmt) check_object_ownership(GetUserId(), stmt->removeType, address, object, relation); + /* + * Make note if a temporary namespace has been accessed in this + * transaction. + */ + if (OidIsValid(namespaceId) && isTempNamespace(namespaceId)) + MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE; + /* Release any relcache reference count, but keep lock until commit. */ if (relation) heap_close(relation, NoLock); diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index e381a307601..4fe71196c41 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1476,6 +1476,13 @@ CreateExtensionInternal(char *extensionName, } /* + * Make note if a temporary namespace has been accessed in this + * transaction. + */ + if (isTempNamespace(schemaOid)) + MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE; + + /* * We don't check creation rights on the target namespace here. If the * extension script actually creates any objects there, it will fail if * the user doesn't have such permissions. But there are cases such as diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c index 1b33be18958..4cd7ec2d5fa 100644 --- a/src/backend/commands/lockcmds.c +++ b/src/backend/commands/lockcmds.c @@ -14,6 +14,7 @@ */ #include "postgres.h" +#include "access/xact.h" #include "catalog/namespace.h" #include "catalog/pg_inherits.h" #include "commands/lockcmds.h" @@ -83,6 +84,7 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid, { LOCKMODE lockmode = *(LOCKMODE *) arg; char relkind; + char relpersistence; AclResult aclresult; if (!OidIsValid(relid)) @@ -100,6 +102,14 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid, errmsg("\"%s\" is not a table or a view", rv->relname))); + /* + * Make note if a temporary relation has been accessed in this + * transaction. + */ + relpersistence = get_rel_persistence(relid); + if (relpersistence == RELPERSISTENCE_TEMP) + MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPREL; + /* Check permissions. */ aclresult = LockTableAclCheck(relid, lockmode, GetUserId()); if (aclresult != ACLCHECK_OK) |