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 (pgsql-bugs@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-bugs