aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/indexcmds.c110
-rw-r--r--src/backend/parser/gram.y35
-rw-r--r--src/backend/tcop/utility.c15
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",