diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/indexcmds.c | 110 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 35 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 15 |
3 files changed, 109 insertions, 51 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 12b4ac7b3ce..a3e8a151413 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1777,34 +1777,58 @@ ReindexTable(RangeVar *relation) } /* - * ReindexDatabase - * Recreate indexes of a database. + * ReindexObject + * Recreate indexes of object whose type is defined by objectKind. * * To reduce the probability of deadlocks, each table is reindexed in a * separate transaction, so we can release the lock on it right away. * That means this must not be called within a user transaction block! */ Oid -ReindexDatabase(const char *databaseName, bool do_system, bool do_user) +ReindexObject(const char *objectName, ReindexObjectType objectKind) { + Oid objectOid; Relation relationRelation; HeapScanDesc scan; + ScanKeyData *scan_keys = NULL; HeapTuple tuple; MemoryContext private_context; MemoryContext old; List *relids = NIL; ListCell *l; + int num_keys; - AssertArg(databaseName); + AssertArg(objectName); + Assert(objectKind == REINDEX_OBJECT_SCHEMA || + objectKind == REINDEX_OBJECT_SYSTEM || + objectKind == REINDEX_OBJECT_DATABASE); - if (strcmp(databaseName, get_database_name(MyDatabaseId)) != 0) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("can only reindex the currently open database"))); + /* + * Get OID of object to reindex, being the database currently being + * used by session for a database or for system catalogs, or the schema + * defined by caller. At the same time do permission checks that need + * different processing depending on the object type. + */ + if (objectKind == REINDEX_OBJECT_SCHEMA) + { + objectOid = get_namespace_oid(objectName, false); - if (!pg_database_ownercheck(MyDatabaseId, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - databaseName); + if (!pg_namespace_ownercheck(objectOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, + objectName); + } + else + { + objectOid = MyDatabaseId; + + if (strcmp(objectName, get_database_name(MyDatabaseId)) != 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("can only reindex the currently open database"))); + if (!pg_database_ownercheck(MyDatabaseId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + objectName); + } /* * Create a memory context that will survive forced transaction commits we @@ -1813,18 +1837,23 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) * abort cleanup logic. */ private_context = AllocSetContextCreate(PortalContext, - "ReindexDatabase", + (objectKind == REINDEX_OBJECT_SCHEMA) ? + "ReindexSchema" : "ReindexDatabase", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* - * We always want to reindex pg_class first. This ensures that if there - * is any corruption in pg_class' indexes, they will be fixed before we - * process any other tables. This is critical because reindexing itself - * will try to update pg_class. + * We always want to reindex pg_class first when reindexing system + * catalogs or a database. This ensures that if there is any corruption + * in pg_class' indexes, they will be fixed before we process any other + * tables. This is critical because reindexing itself will try to + * update pg_class. */ - if (do_system) + if (objectKind == REINDEX_OBJECT_DATABASE || + objectKind == REINDEX_OBJECT_SYSTEM || + (objectKind == REINDEX_OBJECT_SCHEMA && + IsSystemNamespace(objectOid))) { old = MemoryContextSwitchTo(private_context); relids = lappend_oid(relids, RelationRelationId); @@ -1832,13 +1861,34 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) } /* + * Define the search keys to find the objects to reindex. For a schema, + * we search target relations using relnamespace and relkind, something + * not necessary for a database-wide operation. + */ + if (objectKind == REINDEX_OBJECT_SCHEMA) + { + scan_keys = palloc(sizeof(ScanKeyData) * 2); + ScanKeyInit(&scan_keys[0], + Anum_pg_class_relnamespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectOid)); + ScanKeyInit(&scan_keys[1], + Anum_pg_class_relkind, + BTEqualStrategyNumber, F_CHAREQ, + 'r'); + num_keys = 2; + } + else + num_keys = 0; + + /* * Scan pg_class to build a list of the relations we need to reindex. * * We only consider plain relations and materialized views here (toast * rels will be processed indirectly by reindex_relation). */ relationRelation = heap_open(RelationRelationId, AccessShareLock); - scan = heap_beginscan_catalog(relationRelation, 0, NULL); + scan = heap_beginscan_catalog(relationRelation, num_keys, scan_keys); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple); @@ -1854,19 +1904,17 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) continue; /* Check user/system classification, and optionally skip */ - if (IsSystemClass(relid, classtuple)) - { - if (!do_system) - continue; - } - else - { - if (!do_user) - continue; - } + if (!IsSystemClass(relid, classtuple) && + objectKind == REINDEX_OBJECT_SYSTEM) + continue; + /* + * Already have it in the case of system catalogs being all + * reindexed, of a database or of a system catalog being reindexed + * as a schema. + */ if (HeapTupleGetOid(tuple) == RelationRelationId) - continue; /* got it already */ + continue; old = MemoryContextSwitchTo(private_context); relids = lappend_oid(relids, relid); @@ -1898,6 +1946,8 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) StartTransactionCommand(); MemoryContextDelete(private_context); + if (scan_keys) + pfree(scan_keys); - return MyDatabaseId; + return objectOid; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 7e48958ae85..4b5009b636d 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -404,7 +404,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <boolean> copy_from opt_program %type <ival> opt_column event cursor_options opt_hold opt_set_data -%type <objtype> reindex_type drop_type comment_type security_label_type +%type <objtype> drop_type comment_type security_label_type %type <node> fetch_args limit_clause select_limit_value offset_clause select_offset_value @@ -7198,41 +7198,48 @@ opt_if_exists: IF_P EXISTS { $$ = TRUE; } *****************************************************************************/ ReindexStmt: - REINDEX reindex_type qualified_name opt_force + REINDEX INDEX qualified_name opt_force { ReindexStmt *n = makeNode(ReindexStmt); - n->kind = $2; + n->kind = REINDEX_OBJECT_INDEX; n->relation = $3; n->name = NULL; $$ = (Node *)n; } + | REINDEX TABLE qualified_name opt_force + { + ReindexStmt *n = makeNode(ReindexStmt); + n->kind = REINDEX_OBJECT_TABLE; + n->relation = $3; + n->name = NULL; + $$ = (Node *)n; + } + | REINDEX SCHEMA name opt_force + { + ReindexStmt *n = makeNode(ReindexStmt); + n->kind = REINDEX_OBJECT_SCHEMA; + n->name = $3; + n->relation = NULL; + $$ = (Node *)n; + } | REINDEX SYSTEM_P name opt_force { ReindexStmt *n = makeNode(ReindexStmt); - n->kind = OBJECT_DATABASE; + n->kind = REINDEX_OBJECT_SYSTEM; n->name = $3; n->relation = NULL; - n->do_system = true; - n->do_user = false; $$ = (Node *)n; } | REINDEX DATABASE name opt_force { ReindexStmt *n = makeNode(ReindexStmt); - n->kind = OBJECT_DATABASE; + n->kind = REINDEX_OBJECT_DATABASE; n->name = $3; n->relation = NULL; - n->do_system = true; - n->do_user = true; $$ = (Node *)n; } ; -reindex_type: - INDEX { $$ = OBJECT_INDEX; } - | TABLE { $$ = OBJECT_TABLE; } - ; - opt_force: FORCE { $$ = TRUE; } | /* EMPTY */ { $$ = FALSE; } ; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 58f78ce50d5..aa8fe880d7e 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -749,14 +749,15 @@ standard_ProcessUtility(Node *parsetree, PreventCommandDuringRecovery("REINDEX"); switch (stmt->kind) { - case OBJECT_INDEX: + case REINDEX_OBJECT_INDEX: ReindexIndex(stmt->relation); break; - case OBJECT_TABLE: - case OBJECT_MATVIEW: + case REINDEX_OBJECT_TABLE: ReindexTable(stmt->relation); break; - case OBJECT_DATABASE: + case REINDEX_OBJECT_SCHEMA: + case REINDEX_OBJECT_SYSTEM: + case REINDEX_OBJECT_DATABASE: /* * This cannot run inside a user transaction block; if @@ -765,9 +766,9 @@ standard_ProcessUtility(Node *parsetree, * intended effect! */ PreventTransactionChain(isTopLevel, - "REINDEX DATABASE"); - ReindexDatabase(stmt->name, - stmt->do_system, stmt->do_user); + (stmt->kind == REINDEX_OBJECT_SCHEMA) ? + "REINDEX SCHEMA" : "REINDEX DATABASE"); + ReindexObject(stmt->name, stmt->kind); break; default: elog(ERROR, "unrecognized object type: %d", |