diff options
Diffstat (limited to 'src/backend/commands/indexcmds.c')
-rw-r--r-- | src/backend/commands/indexcmds.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index f9f3ff3b629..127ba7835da 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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); /* |