I wrote:
> On the whole I think resurrecting the rd_islocaltemp flag might be the
> best thing. We can keep the use of "relpersistence ==
> RELPERSISTENCE_TEMP" to do what rd_istemp used to do, it's just the
> equation of "rd_backend == MyBackendId" with "is my temp table" that's
> bogus. And this way gets rid of some unnecessary cross-branch coding
> differences.
Here is a draft patch for this. Thoughts/objections?
One thing I noticed that maybe needs more work is that tablecmds.c in
general seems mighty willing to hack upon temp tables belonging to other
sessions. I added tests for that in the places where there already were
checks on relpersistence, but I wonder whether we ought not simply
forbid all forms of ALTER on nonlocal temp rels, right up at the top.
regards, tom lane
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 2979819e966b2aed45f29a33be413962df18fcf9..4424260605b164f0a8b31c0b9e7c1216ae3ec12a 100644
*** a/src/backend/catalog/toasting.c
--- b/src/backend/catalog/toasting.c
*************** create_toast_table(Relation rel, Oid toa
*** 196,202 ****
* Toast tables for regular relations go in pg_toast; those for temp
* relations go into the per-backend temp-toast-table namespace.
*/
! if (RelationUsesTempNamespace(rel))
namespaceid = GetTempToastNamespace();
else
namespaceid = PG_TOAST_NAMESPACE;
--- 196,202 ----
* Toast tables for regular relations go in pg_toast; those for temp
* relations go into the per-backend temp-toast-table namespace.
*/
! if (isTempOrToastNamespace(rel->rd_rel->relnamespace))
namespaceid = GetTempToastNamespace();
else
namespaceid = PG_TOAST_NAMESPACE;
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 8200d98139933a0f1cb4a15a239bdf86a03984e2..4172c0cfbe68a8a9c6c960d1b40d1865766ada10 100644
*** a/src/backend/commands/copy.c
--- b/src/backend/commands/copy.c
*************** DoCopy(const CopyStmt *stmt, const char
*** 806,812 ****
Assert(rel);
/* check read-only transaction */
! if (XactReadOnly && rel->rd_backend != MyBackendId)
PreventCommandIfReadOnly("COPY FROM");
cstate = BeginCopyFrom(rel, stmt->filename,
--- 806,812 ----
Assert(rel);
/* check read-only transaction */
! if (XactReadOnly && !rel->rd_islocaltemp)
PreventCommandIfReadOnly("COPY FROM");
cstate = BeginCopyFrom(rel, stmt->filename,
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 634ce3f7188933eb354468a2e5f337cfa57cbd57..5583e721ead8f51d9b8627e1ee73200e2abd7eee 100644
*** a/src/backend/commands/sequence.c
--- b/src/backend/commands/sequence.c
*************** nextval_internal(Oid relid)
*** 553,559 ****
RelationGetRelationName(seqrel))));
/* read-only transactions may only modify temp sequences */
! if (seqrel->rd_backend != MyBackendId)
PreventCommandIfReadOnly("nextval()");
if (elm->last != elm->cached) /* some numbers were cached */
--- 553,559 ----
RelationGetRelationName(seqrel))));
/* read-only transactions may only modify temp sequences */
! if (!seqrel->rd_islocaltemp)
PreventCommandIfReadOnly("nextval()");
if (elm->last != elm->cached) /* some numbers were cached */
*************** do_setval(Oid relid, int64 next, bool is
*** 846,852 ****
RelationGetRelationName(seqrel))));
/* read-only transactions may only modify temp sequences */
! if (seqrel->rd_backend != MyBackendId)
PreventCommandIfReadOnly("setval()");
/* lock page' buffer and read tuple */
--- 846,852 ----
RelationGetRelationName(seqrel))));
/* read-only transactions may only modify temp sequences */
! if (!seqrel->rd_islocaltemp)
PreventCommandIfReadOnly("setval()");
/* lock page' buffer and read tuple */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 4065740b336079305bc663b57ef8ae96b9692100..761374741db9f7c329f845e9952e4daed05f288d 100644
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** MergeAttributes(List *schema, List *supe
*** 1451,1463 ****
errmsg("inherited relation \"%s\" is not a table",
parent->relname)));
/* Permanent rels cannot inherit from temporary ones */
! if (relpersistence != RELPERSISTENCE_TEMP
! && RelationUsesTempNamespace(relation))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot inherit from temporary relation \"%s\"",
parent->relname)));
/*
* We should have an UNDER permission flag for this, but for now,
* demand that creator of a child table own the parent.
--- 1451,1470 ----
errmsg("inherited relation \"%s\" is not a table",
parent->relname)));
/* Permanent rels cannot inherit from temporary ones */
! if (relpersistence != RELPERSISTENCE_TEMP &&
! relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot inherit from temporary relation \"%s\"",
parent->relname)));
+ /* If existing rel is temp, it must belong to this session */
+ if (relation->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
+ !relation->rd_islocaltemp)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot inherit from temporary relation of another session")));
+
/*
* We should have an UNDER permission flag for this, but for now,
* demand that creator of a child table own the parent.
*************** ATAddForeignKeyConstraint(AlteredTableIn
*** 5768,5773 ****
--- 5775,5784 ----
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("constraints on temporary tables may reference only temporary tables")));
+ if (!pkrel->rd_islocaltemp || !rel->rd_islocaltemp)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("constraints on temporary tables must involve temporary tables of this session")));
break;
}
*************** ATExecAddInherit(Relation child_rel, Ran
*** 8884,8896 ****
ATSimplePermissions(parent_rel, ATT_TABLE);
/* Permanent rels cannot inherit from temporary ones */
! if (RelationUsesTempNamespace(parent_rel)
! && !RelationUsesTempNamespace(child_rel))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot inherit from temporary relation \"%s\"",
RelationGetRelationName(parent_rel))));
/*
* Check for duplicates in the list of parents, and determine the highest
* inhseqno already present; we'll use the next one for the new parent.
--- 8895,8921 ----
ATSimplePermissions(parent_rel, ATT_TABLE);
/* Permanent rels cannot inherit from temporary ones */
! if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
! child_rel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot inherit from temporary relation \"%s\"",
RelationGetRelationName(parent_rel))));
+ /* If parent rel is temp, it must belong to this session */
+ if (parent_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
+ !parent_rel->rd_islocaltemp)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot inherit from temporary relation of another session")));
+
+ /* Ditto for the child */
+ if (child_rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
+ !child_rel->rd_islocaltemp)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("cannot inherit to temporary relation of another session")));
+
/*
* Check for duplicates in the list of parents, and determine the highest
* inhseqno already present; we'll use the next one for the new parent.
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index cd23334a1a5118269f96428c54c27bdef1db7012..581fbfd7fa764bba9c794c54eb54dcec87f531dd 100644
*** a/src/backend/utils/adt/dbsize.c
--- b/src/backend/utils/adt/dbsize.c
*************** pg_tablespace_size_name(PG_FUNCTION_ARGS
*** 260,265 ****
--- 260,268 ----
/*
* calculate size of (one fork of) a relation
+ *
+ * Note: we can safely apply this to temp tables of other sessions, so there
+ * is no check here or at the call sites for that.
*/
static int64
calculate_relation_size(RelFileNode *rfn, BackendId backend, ForkNumber forknum)
*************** pg_relation_size(PG_FUNCTION_ARGS)
*** 314,320 ****
* that makes queries like "SELECT pg_relation_size(oid) FROM pg_class"
* less robust, because while we scan pg_class with an MVCC snapshot,
* someone else might drop the table. It's better to return NULL for
! * alread-dropped tables than throw an error and abort the whole query.
*/
if (rel == NULL)
PG_RETURN_NULL();
--- 317,323 ----
* that makes queries like "SELECT pg_relation_size(oid) FROM pg_class"
* less robust, because while we scan pg_class with an MVCC snapshot,
* someone else might drop the table. It's better to return NULL for
! * already-dropped tables than throw an error and abort the whole query.
*/
if (rel == NULL)
PG_RETURN_NULL();
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 9a504f80251b6c1c548672282612ec130ba70401..f2a9c5dffb24084001d9cd3d05eca21c638d420e 100644
*** a/src/backend/utils/cache/relcache.c
--- b/src/backend/utils/cache/relcache.c
*************** RelationBuildDesc(Oid targetRelId, bool
*** 853,872 ****
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
relation->rd_backend = InvalidBackendId;
break;
case RELPERSISTENCE_TEMP:
if (isTempOrToastNamespace(relation->rd_rel->relnamespace))
relation->rd_backend = MyBackendId;
else
{
/*
! * If it's a local temp table, but not one of ours, we have to
! * use the slow, grotty method to figure out the owning
! * backend.
*/
relation->rd_backend =
GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
Assert(relation->rd_backend != InvalidBackendId);
}
break;
default:
--- 853,885 ----
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
relation->rd_backend = InvalidBackendId;
+ relation->rd_islocaltemp = false;
break;
case RELPERSISTENCE_TEMP:
if (isTempOrToastNamespace(relation->rd_rel->relnamespace))
+ {
relation->rd_backend = MyBackendId;
+ relation->rd_islocaltemp = true;
+ }
else
{
/*
! * If it's a temp table, but not one of ours, we have to use
! * the slow, grotty method to figure out the owning backend.
! *
! * Note: it's possible that rd_backend gets set to MyBackendId
! * here, in case we are looking at a pg_class entry left over
! * from a crashed backend that coincidentally had the same
! * BackendId we're using. We should *not* consider such a
! * table to be "ours"; this is why we need the separate
! * rd_islocaltemp flag. The pg_class entry will get flushed
! * if/when we clean out the corresponding temp table namespace
! * in preparation for using it.
*/
relation->rd_backend =
GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
Assert(relation->rd_backend != InvalidBackendId);
+ relation->rd_islocaltemp = false;
}
break;
default:
*************** formrdesc(const char *relationName, Oid
*** 1387,1392 ****
--- 1400,1406 ----
relation->rd_createSubid = InvalidSubTransactionId;
relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
relation->rd_backend = InvalidBackendId;
+ relation->rd_islocaltemp = false;
/*
* initialize relation tuple form
*************** RelationBuildLocalRelation(const char *r
*** 2538,2553 ****
/* needed when bootstrapping: */
rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
! /* set up persistence; rd_backend is a function of persistence type */
rel->rd_rel->relpersistence = relpersistence;
switch (relpersistence)
{
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
rel->rd_backend = InvalidBackendId;
break;
case RELPERSISTENCE_TEMP:
rel->rd_backend = MyBackendId;
break;
default:
elog(ERROR, "invalid relpersistence: %c", relpersistence);
--- 2552,2570 ----
/* needed when bootstrapping: */
rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
! /* set up persistence and relcache fields dependent on it */
rel->rd_rel->relpersistence = relpersistence;
switch (relpersistence)
{
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT:
rel->rd_backend = InvalidBackendId;
+ rel->rd_islocaltemp = false;
break;
case RELPERSISTENCE_TEMP:
+ Assert(isTempOrToastNamespace(relnamespace));
rel->rd_backend = MyBackendId;
+ rel->rd_islocaltemp = true;
break;
default:
elog(ERROR, "invalid relpersistence: %c", relpersistence);
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 4669d8a67ef4298c591accbc81710c76e1efa535..f7f84e6f71e8e4c36e66dbb3b5b8614b846a0bae 100644
*** a/src/include/utils/rel.h
--- b/src/include/utils/rel.h
*************** typedef struct RelationData
*** 81,86 ****
--- 81,87 ----
struct SMgrRelationData *rd_smgr; /* cached file handle, or NULL */
int rd_refcnt; /* reference count */
BackendId rd_backend; /* owning backend id, if temporary relation */
+ bool rd_islocaltemp; /* rel is a temp rel of this session */
bool rd_isnailed; /* rel is nailed in cache */
bool rd_isvalid; /* relcache entry is valid */
char rd_indexvalid; /* state of rd_indexlist: 0 = not valid, 1 =
*************** typedef struct StdRdOptions
*** 363,383 ****
((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
/*
- * RelationUsesTempNamespace
- * True if relation's catalog entries live in a private namespace.
- */
- #define RelationUsesTempNamespace(relation) \
- ((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
-
- /*
* RELATION_IS_LOCAL
* If a rel is either temp or newly created in the current transaction,
! * it can be assumed to be visible only to the current backend.
*
* Beware of multiple eval of argument
*/
#define RELATION_IS_LOCAL(relation) \
! ((relation)->rd_backend == MyBackendId || \
(relation)->rd_createSubid != InvalidSubTransactionId)
/*
--- 364,378 ----
((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
/*
* RELATION_IS_LOCAL
* If a rel is either temp or newly created in the current transaction,
! * it can be assumed to be accessible only to the current backend.
! * This is typically used to decide that we can skip acquiring locks.
*
* Beware of multiple eval of argument
*/
#define RELATION_IS_LOCAL(relation) \
! ((relation)->rd_islocaltemp || \
(relation)->rd_createSubid != InvalidSubTransactionId)
/*
*************** typedef struct StdRdOptions
*** 387,394 ****
* Beware of multiple eval of argument
*/
#define RELATION_IS_OTHER_TEMP(relation) \
! ((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP \
! && (relation)->rd_backend != MyBackendId)
/* routines in utils/cache/relcache.c */
extern void RelationIncrementReferenceCount(Relation rel);
--- 382,389 ----
* Beware of multiple eval of argument
*/
#define RELATION_IS_OTHER_TEMP(relation) \
! ((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP && \
! !(relation)->rd_islocaltemp)
/* routines in utils/cache/relcache.c */
extern void RelationIncrementReferenceCount(Relation rel);
--
Sent via pgsql-bugs mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs