aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/catalog/namespace.c57
-rw-r--r--src/backend/commands/tablecmds.c13
-rw-r--r--src/backend/commands/typecmds.c1
-rw-r--r--src/backend/commands/view.c27
-rw-r--r--src/backend/executor/execMain.c13
-rw-r--r--src/backend/parser/parse_utilcmd.c4
-rw-r--r--src/include/catalog/namespace.h1
-rw-r--r--src/test/regress/expected/create_view.out4
8 files changed, 81 insertions, 39 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 41e92992dee..ce795a61c5b 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 */
@@ -390,6 +384,43 @@ RangeVarGetAndCheckCreationNamespace(const RangeVar *newRelation)
}
/*
+ * 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.
* Returns OID if relation found in search path, else InvalidOid.
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cfc685b9499..a3a99d28806 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -432,6 +432,13 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
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
* tables to appear in pg_temp at the front of its search path.
@@ -443,12 +450,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
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 3f3e0bce34d..85a7585c6c9 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 be681e3fd4f..b2381996586 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 2f8deb470c5..eacd863647d 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2414,6 +2414,13 @@ OpenIntoRel(QueryDesc *queryDesc)
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
* tables to appear in pg_temp at the front of its search path.
@@ -2425,12 +2432,6 @@ OpenIntoRel(QueryDesc *queryDesc)
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 d40a963b744..1771fee6478 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 53600969ad7..7e1e194794c 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 f2c06854d0f..f9490a3a550 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