aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/transam/xact.c12
-rw-r--r--src/backend/catalog/namespace.c59
-rw-r--r--src/backend/commands/dropcmds.c8
-rw-r--r--src/backend/commands/extension.c7
-rw-r--r--src/backend/commands/lockcmds.c10
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)