mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
Add TABLESPACE option to REINDEX
This patch adds the possibility to move indexes to a new tablespace while rebuilding them. Both the concurrent and the non-concurrent cases are supported, and the following set of restrictions apply: - When using TABLESPACE with a REINDEX command that targets a partitioned table or index, all the indexes of the leaf partitions are moved to the new tablespace. The tablespace references of the non-leaf, partitioned tables in pg_class.reltablespace are not changed. This requires an extra ALTER TABLE SET TABLESPACE. - Any index on a toast table rebuilt as part of a parent table is kept in its original tablespace. - The operation is forbidden on system catalogs, including trying to directly move a toast relation with REINDEX. This results in an error if doing REINDEX on a single object. REINDEX SCHEMA, DATABASE and SYSTEM skip system relations when TABLESPACE is used. Author: Alexey Kondratov, Michael Paquier, Justin Pryzby Reviewed-by: Álvaro Herrera, Michael Paquier Discussion: https://postgr.es/m/8a8f5f73-00d3-55f8-7583-1375ca8f6a91@postgrespro.ru
This commit is contained in:
@ -2474,6 +2474,7 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
|
||||
ListCell *lc;
|
||||
bool concurrently = false;
|
||||
bool verbose = false;
|
||||
char *tablespacename = NULL;
|
||||
|
||||
/* Parse option list */
|
||||
foreach(lc, stmt->params)
|
||||
@ -2484,6 +2485,8 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
|
||||
verbose = defGetBoolean(opt);
|
||||
else if (strcmp(opt->defname, "concurrently") == 0)
|
||||
concurrently = defGetBoolean(opt);
|
||||
else if (strcmp(opt->defname, "tablespace") == 0)
|
||||
tablespacename = defGetString(opt);
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
@ -2500,6 +2503,30 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
|
||||
(verbose ? REINDEXOPT_VERBOSE : 0) |
|
||||
(concurrently ? REINDEXOPT_CONCURRENTLY : 0);
|
||||
|
||||
/*
|
||||
* Assign the tablespace OID to move indexes to, with InvalidOid to do
|
||||
* nothing.
|
||||
*/
|
||||
if (tablespacename != NULL)
|
||||
{
|
||||
params.tablespaceOid = get_tablespace_oid(tablespacename, false);
|
||||
|
||||
/* Check permissions except when moving to database's default */
|
||||
if (OidIsValid(params.tablespaceOid) &&
|
||||
params.tablespaceOid != MyDatabaseTableSpace)
|
||||
{
|
||||
AclResult aclresult;
|
||||
|
||||
aclresult = pg_tablespace_aclcheck(params.tablespaceOid,
|
||||
GetUserId(), ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, OBJECT_TABLESPACE,
|
||||
get_tablespace_name(params.tablespaceOid));
|
||||
}
|
||||
}
|
||||
else
|
||||
params.tablespaceOid = InvalidOid;
|
||||
|
||||
switch (stmt->kind)
|
||||
{
|
||||
case REINDEX_OBJECT_INDEX:
|
||||
@ -2730,6 +2757,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
|
||||
List *relids = NIL;
|
||||
int num_keys;
|
||||
bool concurrent_warning = false;
|
||||
bool tablespace_warning = false;
|
||||
|
||||
AssertArg(objectName);
|
||||
Assert(objectKind == REINDEX_OBJECT_SCHEMA ||
|
||||
@ -2856,6 +2884,40 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a new tablespace is set, check if this relation has to be
|
||||
* skipped.
|
||||
*/
|
||||
if (OidIsValid(params->tablespaceOid))
|
||||
{
|
||||
bool skip_rel = false;
|
||||
|
||||
/*
|
||||
* Mapped relations cannot be moved to different tablespaces (in
|
||||
* particular this eliminates all shared catalogs.).
|
||||
*/
|
||||
if (RELKIND_HAS_STORAGE(classtuple->relkind) &&
|
||||
!OidIsValid(classtuple->relfilenode))
|
||||
skip_rel = true;
|
||||
|
||||
/*
|
||||
* A system relation is always skipped, even with
|
||||
* allow_system_table_mods enabled.
|
||||
*/
|
||||
if (IsSystemClass(relid, classtuple))
|
||||
skip_rel = true;
|
||||
|
||||
if (skip_rel)
|
||||
{
|
||||
if (!tablespace_warning)
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("cannot move system relations, skipping all")));
|
||||
tablespace_warning = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the list of relation OIDs in private context */
|
||||
old = MemoryContextSwitchTo(private_context);
|
||||
|
||||
@ -3032,6 +3094,24 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check permissions except when moving to database's default if a new
|
||||
* tablespace is chosen. Note that this check also happens in
|
||||
* ExecReindex(), but we do an extra check here as this runs across
|
||||
* multiple transactions.
|
||||
*/
|
||||
if (OidIsValid(params->tablespaceOid) &&
|
||||
params->tablespaceOid != MyDatabaseTableSpace)
|
||||
{
|
||||
AclResult aclresult;
|
||||
|
||||
aclresult = pg_tablespace_aclcheck(params->tablespaceOid,
|
||||
GetUserId(), ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, OBJECT_TABLESPACE,
|
||||
get_tablespace_name(params->tablespaceOid));
|
||||
}
|
||||
|
||||
relkind = get_rel_relkind(relid);
|
||||
relpersistence = get_rel_persistence(relid);
|
||||
|
||||
@ -3210,6 +3290,13 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
|
||||
heapRelation = table_open(relationOid,
|
||||
ShareUpdateExclusiveLock);
|
||||
|
||||
if (OidIsValid(params->tablespaceOid) &&
|
||||
IsSystemRelation(heapRelation))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot move system relation \"%s\"",
|
||||
RelationGetRelationName(heapRelation))));
|
||||
|
||||
/* Add all the valid indexes of relation to list */
|
||||
foreach(lc, RelationGetIndexList(heapRelation))
|
||||
{
|
||||
@ -3346,6 +3433,14 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
|
||||
else
|
||||
heapRelation = table_open(heapId,
|
||||
ShareUpdateExclusiveLock);
|
||||
|
||||
if (OidIsValid(params->tablespaceOid) &&
|
||||
IsSystemRelation(heapRelation))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot move system relation \"%s\"",
|
||||
get_rel_name(relationOid))));
|
||||
|
||||
table_close(heapRelation, NoLock);
|
||||
|
||||
/* Save the list of relation OIDs in private context */
|
||||
@ -3390,6 +3485,13 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* It's not a shared catalog, so refuse to move it to shared tablespace */
|
||||
if (params->tablespaceOid == GLOBALTABLESPACE_OID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot move non-shared relation to tablespace \"%s\"",
|
||||
get_tablespace_name(params->tablespaceOid))));
|
||||
|
||||
Assert(heapRelationIds != NIL);
|
||||
|
||||
/*-----
|
||||
@ -3427,6 +3529,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
|
||||
Relation heapRel;
|
||||
Relation newIndexRel;
|
||||
LockRelId *lockrelid;
|
||||
Oid tablespaceid;
|
||||
|
||||
indexRel = index_open(idx->indexId, ShareUpdateExclusiveLock);
|
||||
heapRel = table_open(indexRel->rd_index->indrelid,
|
||||
@ -3458,9 +3561,17 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
|
||||
get_rel_namespace(indexRel->rd_index->indrelid),
|
||||
false);
|
||||
|
||||
/* Choose the new tablespace, indexes of toast tables are not moved */
|
||||
if (OidIsValid(params->tablespaceOid) &&
|
||||
heapRel->rd_rel->relkind != RELKIND_TOASTVALUE)
|
||||
tablespaceid = params->tablespaceOid;
|
||||
else
|
||||
tablespaceid = indexRel->rd_rel->reltablespace;
|
||||
|
||||
/* Create new index definition based on given index */
|
||||
newIndexId = index_concurrently_create_copy(heapRel,
|
||||
idx->indexId,
|
||||
tablespaceid,
|
||||
concurrentName);
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user