From e483d14888058cd424de60ead95980bf297ccc97 Mon Sep 17 00:00:00 2001 From: Daniil Davidov Date: Mon, 14 Apr 2025 11:01:56 +0700 Subject: [PATCH] Fix accessing other sessions temp tables --- src/backend/catalog/namespace.c | 56 ++++++++++++++++++++------------ src/backend/commands/tablecmds.c | 3 +- src/backend/nodes/makefuncs.c | 6 +++- src/backend/parser/gram.y | 11 ++++++- src/include/catalog/namespace.h | 2 ++ 5 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index d97d632a7ef5..f407efd94474 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -499,28 +499,44 @@ RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, */ if (relation->relpersistence == RELPERSISTENCE_TEMP) { - if (!OidIsValid(myTempNamespace)) - relId = InvalidOid; /* this probably can't happen? */ - else - { - if (relation->schemaname) - { - Oid namespaceId; + Oid namespaceId; - namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok); + if (relation->schemaname) + { + namespaceId = LookupExplicitNamespace(relation->schemaname, missing_ok); + /* + * If the user has specified an existing temporary schema + * owned by another user. + */ + if (OidIsValid(namespaceId) && namespaceId != myTempNamespace) + { /* - * For missing_ok, allow a non-existent schema name to - * return InvalidOid. + * We don't allow users to access temp tables of other + * sessions except for the case of dropping tables. */ - if (namespaceId != myTempNamespace) + if (!(flags & RVR_OTHER_TEMP_OK)) ereport(ERROR, - (errcode(ERRCODE_INVALID_TABLE_DEFINITION), - errmsg("temporary tables cannot specify a schema name"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("could not access temporary relations of other sessions"))); } + } + else + { + namespaceId = myTempNamespace; - relId = get_relname_relid(relation->relname, myTempNamespace); + /* + * If this table was recognized as temporary, it means that we + * found it because backend's temporary namespace was specified + * in search_path. Thus, MyTempNamespace must contain valid oid. + */ + Assert(OidIsValid(namespaceId)); } + + if (missing_ok && !OidIsValid(namespaceId)) + relId = InvalidOid; + else + relId = get_relname_relid(relation->relname, namespaceId); } else if (relation->schemaname) { @@ -3553,21 +3569,19 @@ get_namespace_oid(const char *nspname, bool missing_ok) RangeVar * makeRangeVarFromNameList(const List *names) { - RangeVar *rel = makeRangeVar(NULL, NULL, -1); + RangeVar *rel; switch (list_length(names)) { case 1: - rel->relname = strVal(linitial(names)); + rel = makeRangeVar(NULL, strVal(linitial(names)), -1); break; case 2: - rel->schemaname = strVal(linitial(names)); - rel->relname = strVal(lsecond(names)); + rel = makeRangeVar(strVal(linitial(names)), strVal(lsecond(names)), -1); break; case 3: + rel = makeRangeVar(strVal(lsecond(names)), strVal(lthird(names)), -1); rel->catalogname = strVal(linitial(names)); - rel->schemaname = strVal(lsecond(names)); - rel->relname = strVal(lthird(names)); break; default: ereport(ERROR, @@ -3774,6 +3788,8 @@ GetTempNamespaceProcNumber(Oid namespaceId) return INVALID_PROC_NUMBER; /* no such namespace? */ if (strncmp(nspname, "pg_temp_", 8) == 0) result = atoi(nspname + 8); + else if (strcmp(nspname, "pg_temp") == 0) + result = MyProcNumber; else if (strncmp(nspname, "pg_toast_temp_", 14) == 0) result = atoi(nspname + 14); else diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 2705cf11330d..bc15de2311f6 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1623,7 +1623,8 @@ RemoveRelations(DropStmt *drop) state.heapOid = InvalidOid; state.partParentOid = InvalidOid; - relOid = RangeVarGetRelidExtended(rel, lockmode, RVR_MISSING_OK, + relOid = RangeVarGetRelidExtended(rel, lockmode, + RVR_MISSING_OK | RVR_OTHER_TEMP_OK, RangeVarCallbackForDropRelation, &state); diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index e2d9e9be41a6..62edf24b5c2d 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -478,10 +478,14 @@ makeRangeVar(char *schemaname, char *relname, int location) r->schemaname = schemaname; r->relname = relname; r->inh = true; - r->relpersistence = RELPERSISTENCE_PERMANENT; r->alias = NULL; r->location = location; + if (r->schemaname && strncmp(r->schemaname, "pg_temp", 7) == 0) + r->relpersistence = RELPERSISTENCE_TEMP; + else + r->relpersistence = RELPERSISTENCE_PERMANENT; + return r; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3c4268b271a4..af7a6bc13230 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -19421,7 +19421,11 @@ makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner) break; } - r->relpersistence = RELPERSISTENCE_PERMANENT; + if (r->schemaname && strncmp(r->schemaname, "pg_temp", 7) == 0) + r->relpersistence = RELPERSISTENCE_TEMP; + else + r->relpersistence = RELPERSISTENCE_PERMANENT; + r->location = position; return r; @@ -19461,6 +19465,11 @@ makeRangeVarFromQualifiedName(char *name, List *namelist, int location, break; } + if (r->schemaname && strncmp(r->schemaname, "pg_temp", 7) == 0) + r->relpersistence = RELPERSISTENCE_TEMP; + else + r->relpersistence = RELPERSISTENCE_PERMANENT; + return r; } diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index 8c7ccc69a3c3..9c45a30516e9 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -72,6 +72,8 @@ typedef enum RVROption RVR_MISSING_OK = 1 << 0, /* don't error if relation doesn't exist */ RVR_NOWAIT = 1 << 1, /* error if relation cannot be locked */ RVR_SKIP_LOCKED = 1 << 2, /* skip if relation cannot be locked */ + RVR_OTHER_TEMP_OK = 1 << 3 /* don't error if relation is temp relation of + other session (needed for DROP command) */ } RVROption; typedef void (*RangeVarGetRelidCallback) (const RangeVar *relation, Oid relId,