diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 41e92992deec95301fdda6d51972f090ec5f9b72..ce795a61c5bb1ec82f1989980b8c4a0c76033fae 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -311,19 +311,6 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) newRelation->relname))); } - if (newRelation->relpersistence == RELPERSISTENCE_TEMP) - { - /* TEMP tables are created in our backend-local temp namespace */ - if (newRelation->schemaname) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TABLE_DEFINITION), - errmsg("temporary tables cannot specify a schema name"))); - /* Initialize temp namespace if first time through */ - if (!OidIsValid(myTempNamespace)) - InitTempTableNamespace(); - return myTempNamespace; - } - if (newRelation->schemaname) { /* check for pg_temp alias */ @@ -338,6 +325,13 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation) namespaceId = get_namespace_oid(newRelation->schemaname, false); /* we do not check for USAGE rights here! */ } + else if (newRelation->relpersistence == RELPERSISTENCE_TEMP) + { + /* Initialize temp namespace if first time through */ + if (!OidIsValid(myTempNamespace)) + InitTempTableNamespace(); + return myTempNamespace; + } else { /* use the default creation namespace */ @@ -389,6 +383,43 @@ RangeVarGetAndCheckCreationNamespace(const RangeVar *newRelation) return namespaceId; } +/* + * Adjust the relpersistence for an about-to-be-created relation based on the + * creation namespace, and throw an error for invalid combinations. + */ +void +RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid) +{ + switch (newRelation->relpersistence) + { + case RELPERSISTENCE_TEMP: + if (!isTempOrToastNamespace(nspid)) + { + if (isAnyTempNamespace(nspid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot create relations in temporary schemas of other sessions"))); + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot create temporary relation in non-temporary schema"))); + } + break; + case RELPERSISTENCE_PERMANENT: + if (isTempOrToastNamespace(nspid)) + newRelation->relpersistence = RELPERSISTENCE_TEMP; + else if (isAnyTempNamespace(nspid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot create relations in temporary schemas of other sessions"))); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("only temporary relations may be created in temporary schemas"))); + } +} + /* * RelnameGetRelid * Try to resolve an unqualified relation name. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index cfc685b94996f55f7ef7dfeaa9f2cd523c44d2c5..a3a99d28806c0902cb407144a79b03ba01768204 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -431,6 +431,13 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId) (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("constraints on foreign tables are not supported"))); + /* + * Look up the namespace in which we are supposed to create the relation, + * and check we have permission to create there. + */ + namespaceId = RangeVarGetAndCheckCreationNamespace(stmt->relation); + RangeVarAdjustRelationPersistence(stmt->relation, namespaceId); + /* * Security check: disallow creating temp tables from security-restricted * code. This is needed because calling code might not expect untrusted @@ -442,12 +449,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("cannot create temporary table within security-restricted operation"))); - /* - * Look up the namespace in which we are supposed to create the relation, - * and check we have permission to create there. - */ - namespaceId = RangeVarGetAndCheckCreationNamespace(stmt->relation); - /* * Select tablespace to use. If not specified, use default tablespace * (which may in turn default to database's default). diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 3f3e0bce34d42dc7391e9f5c238221f482dec0e9..85a7585c6c9ff568fecc9aea62b0af38a437c6fd 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -1610,6 +1610,7 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist) * instead of below about a "relation". */ typeNamespace = RangeVarGetCreationNamespace(createStmt->relation); + RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace); old_type_oid = GetSysCacheOid2(TYPENAMENSP, CStringGetDatum(createStmt->relation->relname), diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index be681e3fd4f9fa24c3b8fe4fc22dd13549e02f03..b23819965869a58af27ac5633cb20af1664228bc 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -97,10 +97,10 @@ isViewOnTempTable_walker(Node *node, void *context) *--------------------------------------------------------------------- */ static Oid -DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace) +DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace, + Oid namespaceId) { - Oid viewOid, - namespaceId; + Oid viewOid; CreateStmt *createStmt = makeNode(CreateStmt); List *attrList; ListCell *t; @@ -160,7 +160,6 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace) /* * Check to see if we want to replace an existing view. */ - namespaceId = RangeVarGetCreationNamespace(relation); viewOid = get_relname_relid(relation->relname, namespaceId); if (OidIsValid(viewOid) && replace) @@ -417,6 +416,7 @@ DefineView(ViewStmt *stmt, const char *queryString) { Query *viewParse; Oid viewOid; + Oid namespaceId; RangeVar *view; /* @@ -480,28 +480,31 @@ DefineView(ViewStmt *stmt, const char *queryString) "names than columns"))); } + /* Unlogged views are not sensible. */ + if (stmt->view->relpersistence == RELPERSISTENCE_UNLOGGED) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("views cannot be unlogged because they do not have storage"))); + /* * If the user didn't explicitly ask for a temporary view, check whether * we need one implicitly. We allow TEMP to be inserted automatically as * long as the CREATE command is consistent with that --- no explicit * schema name. */ - view = stmt->view; + view = copyObject(stmt->view); /* don't corrupt original command */ if (view->relpersistence == RELPERSISTENCE_PERMANENT && isViewOnTempTable(viewParse)) { - view = copyObject(view); /* don't corrupt original command */ view->relpersistence = RELPERSISTENCE_TEMP; ereport(NOTICE, (errmsg("view \"%s\" will be a temporary view", view->relname))); } - /* Unlogged views are not sensible. */ - if (view->relpersistence == RELPERSISTENCE_UNLOGGED) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("views cannot be unlogged because they do not have storage"))); + /* Might also need to make it temporary if placed in temp schema. */ + namespaceId = RangeVarGetCreationNamespace(view); + RangeVarAdjustRelationPersistence(view, namespaceId); /* * Create the view relation @@ -510,7 +513,7 @@ DefineView(ViewStmt *stmt, const char *queryString) * aborted. */ viewOid = DefineVirtualRelation(view, viewParse->targetList, - stmt->replace); + stmt->replace, namespaceId); /* * The relation we have just created is not visible to any other commands diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 2f8deb470c56fb901bb063c4a9287cd8b14b0256..eacd863647d2b09de71670806d8cbe84a93159ce 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -2413,6 +2413,13 @@ OpenIntoRel(QueryDesc *queryDesc) (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("ON COMMIT can only be used on temporary tables"))); + /* + * Find namespace to create in, check its permissions + */ + intoName = into->rel->relname; + namespaceId = RangeVarGetAndCheckCreationNamespace(into->rel); + RangeVarAdjustRelationPersistence(into->rel, namespaceId); + /* * Security check: disallow creating temp tables from security-restricted * code. This is needed because calling code might not expect untrusted @@ -2424,12 +2431,6 @@ OpenIntoRel(QueryDesc *queryDesc) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("cannot create temporary table within security-restricted operation"))); - /* - * Find namespace to create in, check its permissions - */ - intoName = into->rel->relname; - namespaceId = RangeVarGetAndCheckCreationNamespace(into->rel); - /* * Select tablespace to use. If not specified, use default tablespace * (which may in turn default to database's default). diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index d40a963b744e08087028cff43ae51f4313241219..1771fee6478d6ce2f1d3dcbfb712d25c169f70e3 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -162,6 +162,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) * possible. */ namespaceid = RangeVarGetAndCheckCreationNamespace(stmt->relation); + RangeVarAdjustRelationPersistence(stmt->relation, namespaceid); /* * If the relation already exists and the user specified "IF NOT EXISTS", @@ -374,7 +375,10 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column) if (cxt->rel) snamespaceid = RelationGetNamespace(cxt->rel); else + { snamespaceid = RangeVarGetCreationNamespace(cxt->relation); + RangeVarAdjustRelationPersistence(cxt->relation, snamespaceid); + } snamespace = get_namespace_name(snamespaceid); sname = ChooseRelationName(cxt->relation->relname, column->colname, diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index 53600969ad7e29ef5875ff3c1feb3edd59e2c822..7e1e194794c2055912a6dcff27777e49235c4158 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -50,6 +50,7 @@ typedef struct OverrideSearchPath extern Oid RangeVarGetRelid(const RangeVar *relation, bool failOK); extern Oid RangeVarGetCreationNamespace(const RangeVar *newRelation); extern Oid RangeVarGetAndCheckCreationNamespace(const RangeVar *newRelation); +extern void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid); extern Oid RelnameGetRelid(const char *relname); extern bool RelationIsVisible(Oid relid); diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out index f2c06854d0f8ce54e40737f838b5fc06d79ee226..f9490a3a5506268a8e462f165a2c0530d725c4c1 100644 --- a/src/test/regress/expected/create_view.out +++ b/src/test/regress/expected/create_view.out @@ -81,11 +81,11 @@ CREATE VIEW temp_view_test.v2 AS SELECT * FROM base_table; -- should fail CREATE VIEW temp_view_test.v3_temp AS SELECT * FROM temp_table; NOTICE: view "v3_temp" will be a temporary view -ERROR: temporary tables cannot specify a schema name +ERROR: cannot create temporary relation in non-temporary schema -- should fail CREATE SCHEMA test_schema CREATE TEMP VIEW testview AS SELECT 1; -ERROR: temporary tables cannot specify a schema name +ERROR: cannot create temporary relation in non-temporary schema -- joins: if any of the join relations are temporary, the view -- should also be temporary -- should be non-temp