Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4c9c359

Browse files
committed
Refactor code in tablecmds.c to check and process tablespace moves
Two code paths of tablecmds.c (for relations with storage and withoutstorage) use the same logic to check if the move of a relation to anew tablespace is allowed or not and to update pg_class.reltablespaceand pg_class.relfilenode.A potential TABLESPACE clause for REINDEX, CLUSTER and VACUUM FULL needssimilar checks to make sure that nothing is moved around in illegal ways(no mapped relations, shared relations only in pg_global, no move oftemp tables owned by other backends).This reorganizes the existing code of ALTER TABLE so as all this logicis controlled by two new routines that can be reused for the othercommands able to move relations across tablespaces, limiting the numberof code paths in need of the same protections. This also removes somecode that was duplicated for tables with and without storage for ALTERTABLE.Author: Alexey Kondratov, Michael PaquierDiscussion:https://postgr.es/m/YA+9mAMWYLXJMVPL@paquier.xyz
1 parentd5a83d7 commit4c9c359

File tree

2 files changed

+124
-91
lines changed

2 files changed

+124
-91
lines changed

‎src/backend/commands/tablecmds.c

Lines changed: 120 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -3037,6 +3037,113 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass)
30373037
table_close(relationRelation, RowExclusiveLock);
30383038
}
30393039

3040+
/*
3041+
* CheckRelationTableSpaceMove
3042+
*Check if relation can be moved to new tablespace.
3043+
*
3044+
* NOTE: Caller must be holding an appropriate lock on the relation.
3045+
* ShareUpdateExclusiveLock is sufficient.
3046+
*
3047+
* Returns true if the relation can be moved to the new tablespace;
3048+
* false otherwise.
3049+
*/
3050+
bool
3051+
CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
3052+
{
3053+
OidoldTableSpaceId;
3054+
3055+
/*
3056+
* No work if no change in tablespace. Note that MyDatabaseTableSpace is
3057+
* stored as 0.
3058+
*/
3059+
oldTableSpaceId = rel->rd_rel->reltablespace;
3060+
if (newTableSpaceId == oldTableSpaceId ||
3061+
(newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
3062+
return false;
3063+
3064+
/*
3065+
* We cannot support moving mapped relations into different tablespaces.
3066+
* (In particular this eliminates all shared catalogs.)
3067+
*/
3068+
if (RelationIsMapped(rel))
3069+
ereport(ERROR,
3070+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3071+
errmsg("cannot move system relation \"%s\"",
3072+
RelationGetRelationName(rel))));
3073+
3074+
/* Cannot move a non-shared relation into pg_global */
3075+
if (newTableSpaceId == GLOBALTABLESPACE_OID)
3076+
ereport(ERROR,
3077+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3078+
errmsg("only shared relations can be placed in pg_global tablespace")));
3079+
3080+
/*
3081+
* Do not allow moving temp tables of other backends ... their local
3082+
* buffer manager is not going to cope.
3083+
*/
3084+
if (RELATION_IS_OTHER_TEMP(rel))
3085+
ereport(ERROR,
3086+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3087+
errmsg("cannot move temporary tables of other sessions")));
3088+
3089+
return true;
3090+
}
3091+
3092+
/*
3093+
* SetRelationTableSpace
3094+
*Set new reltablespace and relfilenode in pg_class entry.
3095+
*
3096+
* newTableSpaceId is the new tablespace for the relation, and
3097+
* newRelFileNode its new filenode. If newrelfilenode is InvalidOid,
3098+
* this field is not updated.
3099+
*
3100+
* NOTE: Caller must be holding an appropriate lock on the relation.
3101+
* ShareUpdateExclusiveLock is sufficient.
3102+
*
3103+
* The caller of this routine had better check if a relation can be
3104+
* moved to this new tablespace by calling CheckRelationTableSpaceMove()
3105+
* first, and is responsible for making the change visible with
3106+
* CommandCounterIncrement().
3107+
*/
3108+
void
3109+
SetRelationTableSpace(Relation rel,
3110+
Oid newTableSpaceId,
3111+
Oid newRelFileNode)
3112+
{
3113+
Relationpg_class;
3114+
HeapTupletuple;
3115+
Form_pg_class rd_rel;
3116+
Oidreloid = RelationGetRelid(rel);
3117+
3118+
Assert(CheckRelationTableSpaceMove(rel, newTableSpaceId));
3119+
3120+
/* Get a modifiable copy of the relation's pg_class row. */
3121+
pg_class = table_open(RelationRelationId, RowExclusiveLock);
3122+
3123+
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
3124+
if (!HeapTupleIsValid(tuple))
3125+
elog(ERROR, "cache lookup failed for relation %u", reloid);
3126+
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
3127+
3128+
/* Update the pg_class row. */
3129+
rd_rel->reltablespace = (newTableSpaceId == MyDatabaseTableSpace) ?
3130+
InvalidOid : newTableSpaceId;
3131+
if (OidIsValid(newRelFileNode))
3132+
rd_rel->relfilenode = newRelFileNode;
3133+
CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
3134+
3135+
/*
3136+
* Record dependency on tablespace. This is only required for relations
3137+
* that have no physical storage.
3138+
*/
3139+
if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
3140+
changeDependencyOnTablespace(RelationRelationId, reloid,
3141+
rd_rel->reltablespace);
3142+
3143+
heap_freetuple(tuple);
3144+
table_close(pg_class, RowExclusiveLock);
3145+
}
3146+
30403147
/*
30413148
*renameatt_check- basic sanity checks before attribute rename
30423149
*/
@@ -13160,13 +13267,9 @@ static void
1316013267
ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
1316113268
{
1316213269
Relationrel;
13163-
OidoldTableSpace;
1316413270
Oidreltoastrelid;
1316513271
Oidnewrelfilenode;
1316613272
RelFileNode newrnode;
13167-
Relationpg_class;
13168-
HeapTupletuple;
13169-
Form_pg_class rd_rel;
1317013273
List *reltoastidxids = NIL;
1317113274
ListCell *lc;
1317213275

@@ -13175,45 +13278,15 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
1317513278
*/
1317613279
rel = relation_open(tableOid, lockmode);
1317713280

13178-
/*
13179-
* No work if no change in tablespace.
13180-
*/
13181-
oldTableSpace = rel->rd_rel->reltablespace;
13182-
if (newTableSpace == oldTableSpace ||
13183-
(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
13281+
/* Check first if relation can be moved to new tablespace */
13282+
if (!CheckRelationTableSpaceMove(rel, newTableSpace))
1318413283
{
1318513284
InvokeObjectPostAlterHook(RelationRelationId,
1318613285
RelationGetRelid(rel), 0);
13187-
1318813286
relation_close(rel, NoLock);
1318913287
return;
1319013288
}
1319113289

13192-
/*
13193-
* We cannot support moving mapped relations into different tablespaces.
13194-
* (In particular this eliminates all shared catalogs.)
13195-
*/
13196-
if (RelationIsMapped(rel))
13197-
ereport(ERROR,
13198-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13199-
errmsg("cannot move system relation \"%s\"",
13200-
RelationGetRelationName(rel))));
13201-
13202-
/* Can't move a non-shared relation into pg_global */
13203-
if (newTableSpace == GLOBALTABLESPACE_OID)
13204-
ereport(ERROR,
13205-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13206-
errmsg("only shared relations can be placed in pg_global tablespace")));
13207-
13208-
/*
13209-
* Don't allow moving temp tables of other backends ... their local buffer
13210-
* manager is not going to cope.
13211-
*/
13212-
if (RELATION_IS_OTHER_TEMP(rel))
13213-
ereport(ERROR,
13214-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13215-
errmsg("cannot move temporary tables of other sessions")));
13216-
1321713290
reltoastrelid = rel->rd_rel->reltoastrelid;
1321813291
/* Fetch the list of indexes on toast relation if necessary */
1321913292
if (OidIsValid(reltoastrelid))
@@ -13224,14 +13297,6 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
1322413297
relation_close(toastRel, lockmode);
1322513298
}
1322613299

13227-
/* Get a modifiable copy of the relation's pg_class row */
13228-
pg_class = table_open(RelationRelationId, RowExclusiveLock);
13229-
13230-
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(tableOid));
13231-
if (!HeapTupleIsValid(tuple))
13232-
elog(ERROR, "cache lookup failed for relation %u", tableOid);
13233-
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
13234-
1323513300
/*
1323613301
* Relfilenodes are not unique in databases across tablespaces, so we need
1323713302
* to allocate a new one in the new tablespace.
@@ -13262,18 +13327,13 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
1326213327
*
1326313328
* NB: This wouldn't work if ATExecSetTableSpace() were allowed to be
1326413329
* executed on pg_class or its indexes (the above copy wouldn't contain
13265-
* the updated pg_class entry), but that's forbidden above.
13330+
* the updated pg_class entry), but that's forbidden with
13331+
* CheckRelationTableSpaceMove().
1326613332
*/
13267-
rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
13268-
rd_rel->relfilenode = newrelfilenode;
13269-
CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
13333+
SetRelationTableSpace(rel, newTableSpace, newrelfilenode);
1327013334

1327113335
InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
1327213336

13273-
heap_freetuple(tuple);
13274-
13275-
table_close(pg_class, RowExclusiveLock);
13276-
1327713337
RelationAssumeNewRelfilenode(rel);
1327813338

1327913339
relation_close(rel, NoLock);
@@ -13301,56 +13361,25 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
1330113361
static void
1330213362
ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace)
1330313363
{
13304-
HeapTupletuple;
13305-
OidoldTableSpace;
13306-
Relationpg_class;
13307-
Form_pg_class rd_rel;
13308-
Oidreloid = RelationGetRelid(rel);
13309-
1331013364
/*
1331113365
* Shouldn't be called on relations having storage; these are processed in
1331213366
* phase 3.
1331313367
*/
1331413368
Assert(!RELKIND_HAS_STORAGE(rel->rd_rel->relkind));
1331513369

13316-
/* Can't allow a non-shared relation in pg_global */
13317-
if (newTableSpace == GLOBALTABLESPACE_OID)
13318-
ereport(ERROR,
13319-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13320-
errmsg("only shared relations can be placed in pg_global tablespace")));
13321-
13322-
/*
13323-
* No work if no change in tablespace.
13324-
*/
13325-
oldTableSpace = rel->rd_rel->reltablespace;
13326-
if (newTableSpace == oldTableSpace ||
13327-
(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
13370+
/* check if relation can be moved to its new tablespace */
13371+
if (!CheckRelationTableSpaceMove(rel, newTableSpace))
1332813372
{
13329-
InvokeObjectPostAlterHook(RelationRelationId, reloid, 0);
13373+
InvokeObjectPostAlterHook(RelationRelationId,
13374+
RelationGetRelid(rel),
13375+
0);
1333013376
return;
1333113377
}
1333213378

13333-
/* Get a modifiable copy of the relation's pg_class row */
13334-
pg_class = table_open(RelationRelationId, RowExclusiveLock);
13335-
13336-
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
13337-
if (!HeapTupleIsValid(tuple))
13338-
elog(ERROR, "cache lookup failed for relation %u", reloid);
13339-
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
13340-
13341-
/* update the pg_class row */
13342-
rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
13343-
CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);
13344-
13345-
/* Record dependency on tablespace */
13346-
changeDependencyOnTablespace(RelationRelationId,
13347-
reloid, rd_rel->reltablespace);
13348-
13349-
InvokeObjectPostAlterHook(RelationRelationId, reloid, 0);
13379+
/* Update can be done, so change reltablespace */
13380+
SetRelationTableSpace(rel, newTableSpace, InvalidOid);
1335013381

13351-
heap_freetuple(tuple);
13352-
13353-
table_close(pg_class, RowExclusiveLock);
13382+
InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
1335413383

1335513384
/* Make sure the reltablespace change is visible */
1335613385
CommandCounterIncrement();

‎src/include/commands/tablecmds.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ extern void ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_
6161

6262
externvoidSetRelationHasSubclass(OidrelationId,boolrelhassubclass);
6363

64+
externboolCheckRelationTableSpaceMove(Relationrel,OidnewTableSpaceId);
65+
externvoidSetRelationTableSpace(Relationrel,OidnewTableSpaceId,
66+
OidnewRelFileNode);
67+
6468
externObjectAddressrenameatt(RenameStmt*stmt);
6569

6670
externObjectAddressRenameConstraint(RenameStmt*stmt);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp