Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5da7916

Browse files
committed
Fix bugs in relpersistence handling during table creation.
Unlike the relistemp field which it replaced, relpersistence must be set correctly quite early during the table creation process, as we rely on it quite early on for a number of purposes, including security checks. Normally, this is set based on whether the user enters CREATE TABLE, CREATE UNLOGGED TABLE, or CREATE TEMPORARY TABLE, but a relation may also be made implicitly temporary by creating it in pg_temp. This patch fixes the handling of that case, and also disables creation of unlogged tables in temporary tablespace (such table indeed skip WAL-logging, but we reject an explicit specification) and creation of relations in the temporary schemas of other sessions (which is not very sensible, and didn't work right anyway). Report by Amit Khandekar.
1 parent acb9198 commit 5da7916

File tree

8 files changed

+81
-39
lines changed

8 files changed

+81
-39
lines changed

src/backend/catalog/namespace.c

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -311,19 +311,6 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
311311
newRelation->relname)));
312312
}
313313

314-
if (newRelation->relpersistence == RELPERSISTENCE_TEMP)
315-
{
316-
/* TEMP tables are created in our backend-local temp namespace */
317-
if (newRelation->schemaname)
318-
ereport(ERROR,
319-
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
320-
errmsg("temporary tables cannot specify a schema name")));
321-
/* Initialize temp namespace if first time through */
322-
if (!OidIsValid(myTempNamespace))
323-
InitTempTableNamespace();
324-
return myTempNamespace;
325-
}
326-
327314
if (newRelation->schemaname)
328315
{
329316
/* check for pg_temp alias */
@@ -338,6 +325,13 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
338325
namespaceId = get_namespace_oid(newRelation->schemaname, false);
339326
/* we do not check for USAGE rights here! */
340327
}
328+
else if (newRelation->relpersistence == RELPERSISTENCE_TEMP)
329+
{
330+
/* Initialize temp namespace if first time through */
331+
if (!OidIsValid(myTempNamespace))
332+
InitTempTableNamespace();
333+
return myTempNamespace;
334+
}
341335
else
342336
{
343337
/* use the default creation namespace */
@@ -389,6 +383,43 @@ RangeVarGetAndCheckCreationNamespace(const RangeVar *newRelation)
389383
return namespaceId;
390384
}
391385

386+
/*
387+
* Adjust the relpersistence for an about-to-be-created relation based on the
388+
* creation namespace, and throw an error for invalid combinations.
389+
*/
390+
void
391+
RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
392+
{
393+
switch (newRelation->relpersistence)
394+
{
395+
case RELPERSISTENCE_TEMP:
396+
if (!isTempOrToastNamespace(nspid))
397+
{
398+
if (isAnyTempNamespace(nspid))
399+
ereport(ERROR,
400+
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
401+
errmsg("cannot create relations in temporary schemas of other sessions")));
402+
else
403+
ereport(ERROR,
404+
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
405+
errmsg("cannot create temporary relation in non-temporary schema")));
406+
}
407+
break;
408+
case RELPERSISTENCE_PERMANENT:
409+
if (isTempOrToastNamespace(nspid))
410+
newRelation->relpersistence = RELPERSISTENCE_TEMP;
411+
else if (isAnyTempNamespace(nspid))
412+
ereport(ERROR,
413+
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
414+
errmsg("cannot create relations in temporary schemas of other sessions")));
415+
break;
416+
default:
417+
ereport(ERROR,
418+
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
419+
errmsg("only temporary relations may be created in temporary schemas")));
420+
}
421+
}
422+
392423
/*
393424
* RelnameGetRelid
394425
* Try to resolve an unqualified relation name.

src/backend/commands/tablecmds.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,13 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
431431
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
432432
errmsg("constraints on foreign tables are not supported")));
433433

434+
/*
435+
* Look up the namespace in which we are supposed to create the relation,
436+
* and check we have permission to create there.
437+
*/
438+
namespaceId = RangeVarGetAndCheckCreationNamespace(stmt->relation);
439+
RangeVarAdjustRelationPersistence(stmt->relation, namespaceId);
440+
434441
/*
435442
* Security check: disallow creating temp tables from security-restricted
436443
* code. This is needed because calling code might not expect untrusted
@@ -442,12 +449,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
442449
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
443450
errmsg("cannot create temporary table within security-restricted operation")));
444451

445-
/*
446-
* Look up the namespace in which we are supposed to create the relation,
447-
* and check we have permission to create there.
448-
*/
449-
namespaceId = RangeVarGetAndCheckCreationNamespace(stmt->relation);
450-
451452
/*
452453
* Select tablespace to use. If not specified, use default tablespace
453454
* (which may in turn default to database's default).

src/backend/commands/typecmds.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1610,6 +1610,7 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
16101610
* instead of below about a "relation".
16111611
*/
16121612
typeNamespace = RangeVarGetCreationNamespace(createStmt->relation);
1613+
RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
16131614
old_type_oid =
16141615
GetSysCacheOid2(TYPENAMENSP,
16151616
CStringGetDatum(createStmt->relation->relname),

src/backend/commands/view.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@ isViewOnTempTable_walker(Node *node, void *context)
9797
*---------------------------------------------------------------------
9898
*/
9999
static Oid
100-
DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
100+
DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace,
101+
Oid namespaceId)
101102
{
102-
Oid viewOid,
103-
namespaceId;
103+
Oid viewOid;
104104
CreateStmt *createStmt = makeNode(CreateStmt);
105105
List *attrList;
106106
ListCell *t;
@@ -160,7 +160,6 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
160160
/*
161161
* Check to see if we want to replace an existing view.
162162
*/
163-
namespaceId = RangeVarGetCreationNamespace(relation);
164163
viewOid = get_relname_relid(relation->relname, namespaceId);
165164

166165
if (OidIsValid(viewOid) && replace)
@@ -417,6 +416,7 @@ DefineView(ViewStmt *stmt, const char *queryString)
417416
{
418417
Query *viewParse;
419418
Oid viewOid;
419+
Oid namespaceId;
420420
RangeVar *view;
421421

422422
/*
@@ -480,28 +480,31 @@ DefineView(ViewStmt *stmt, const char *queryString)
480480
"names than columns")));
481481
}
482482

483+
/* Unlogged views are not sensible. */
484+
if (stmt->view->relpersistence == RELPERSISTENCE_UNLOGGED)
485+
ereport(ERROR,
486+
(errcode(ERRCODE_SYNTAX_ERROR),
487+
errmsg("views cannot be unlogged because they do not have storage")));
488+
483489
/*
484490
* If the user didn't explicitly ask for a temporary view, check whether
485491
* we need one implicitly. We allow TEMP to be inserted automatically as
486492
* long as the CREATE command is consistent with that --- no explicit
487493
* schema name.
488494
*/
489-
view = stmt->view;
495+
view = copyObject(stmt->view); /* don't corrupt original command */
490496
if (view->relpersistence == RELPERSISTENCE_PERMANENT
491497
&& isViewOnTempTable(viewParse))
492498
{
493-
view = copyObject(view); /* don't corrupt original command */
494499
view->relpersistence = RELPERSISTENCE_TEMP;
495500
ereport(NOTICE,
496501
(errmsg("view \"%s\" will be a temporary view",
497502
view->relname)));
498503
}
499504

500-
/* Unlogged views are not sensible. */
501-
if (view->relpersistence == RELPERSISTENCE_UNLOGGED)
502-
ereport(ERROR,
503-
(errcode(ERRCODE_SYNTAX_ERROR),
504-
errmsg("views cannot be unlogged because they do not have storage")));
505+
/* Might also need to make it temporary if placed in temp schema. */
506+
namespaceId = RangeVarGetCreationNamespace(view);
507+
RangeVarAdjustRelationPersistence(view, namespaceId);
505508

506509
/*
507510
* Create the view relation
@@ -510,7 +513,7 @@ DefineView(ViewStmt *stmt, const char *queryString)
510513
* aborted.
511514
*/
512515
viewOid = DefineVirtualRelation(view, viewParse->targetList,
513-
stmt->replace);
516+
stmt->replace, namespaceId);
514517

515518
/*
516519
* The relation we have just created is not visible to any other commands

src/backend/executor/execMain.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,6 +2413,13 @@ OpenIntoRel(QueryDesc *queryDesc)
24132413
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
24142414
errmsg("ON COMMIT can only be used on temporary tables")));
24152415

2416+
/*
2417+
* Find namespace to create in, check its permissions
2418+
*/
2419+
intoName = into->rel->relname;
2420+
namespaceId = RangeVarGetAndCheckCreationNamespace(into->rel);
2421+
RangeVarAdjustRelationPersistence(into->rel, namespaceId);
2422+
24162423
/*
24172424
* Security check: disallow creating temp tables from security-restricted
24182425
* code. This is needed because calling code might not expect untrusted
@@ -2424,12 +2431,6 @@ OpenIntoRel(QueryDesc *queryDesc)
24242431
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
24252432
errmsg("cannot create temporary table within security-restricted operation")));
24262433

2427-
/*
2428-
* Find namespace to create in, check its permissions
2429-
*/
2430-
intoName = into->rel->relname;
2431-
namespaceId = RangeVarGetAndCheckCreationNamespace(into->rel);
2432-
24332434
/*
24342435
* Select tablespace to use. If not specified, use default tablespace
24352436
* (which may in turn default to database's default).

src/backend/parser/parse_utilcmd.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
162162
* possible.
163163
*/
164164
namespaceid = RangeVarGetAndCheckCreationNamespace(stmt->relation);
165+
RangeVarAdjustRelationPersistence(stmt->relation, namespaceid);
165166

166167
/*
167168
* If the relation already exists and the user specified "IF NOT EXISTS",
@@ -374,7 +375,10 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
374375
if (cxt->rel)
375376
snamespaceid = RelationGetNamespace(cxt->rel);
376377
else
378+
{
377379
snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
380+
RangeVarAdjustRelationPersistence(cxt->relation, snamespaceid);
381+
}
378382
snamespace = get_namespace_name(snamespaceid);
379383
sname = ChooseRelationName(cxt->relation->relname,
380384
column->colname,

src/include/catalog/namespace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ typedef struct OverrideSearchPath
5050
extern Oid RangeVarGetRelid(const RangeVar *relation, bool failOK);
5151
extern Oid RangeVarGetCreationNamespace(const RangeVar *newRelation);
5252
extern Oid RangeVarGetAndCheckCreationNamespace(const RangeVar *newRelation);
53+
extern void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid);
5354
extern Oid RelnameGetRelid(const char *relname);
5455
extern bool RelationIsVisible(Oid relid);
5556

src/test/regress/expected/create_view.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ CREATE VIEW temp_view_test.v2 AS SELECT * FROM base_table;
8181
-- should fail
8282
CREATE VIEW temp_view_test.v3_temp AS SELECT * FROM temp_table;
8383
NOTICE: view "v3_temp" will be a temporary view
84-
ERROR: temporary tables cannot specify a schema name
84+
ERROR: cannot create temporary relation in non-temporary schema
8585
-- should fail
8686
CREATE SCHEMA test_schema
8787
CREATE TEMP VIEW testview AS SELECT 1;
88-
ERROR: temporary tables cannot specify a schema name
88+
ERROR: cannot create temporary relation in non-temporary schema
8989
-- joins: if any of the join relations are temporary, the view
9090
-- should also be temporary
9191
-- should be non-temp

0 commit comments

Comments
 (0)