diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml index cabae19..e47604c 100644 --- a/doc/src/sgml/ref/reindex.sgml +++ b/doc/src/sgml/ref/reindex.sgml @@ -21,7 +21,7 @@ PostgreSQL documentation -REINDEX { INDEX | TABLE | DATABASE | SYSTEM } name [ FORCE ] +REINDEX { INDEX | TABLE | ALL IN SCHEMA | DATABASE | SYSTEM } name [ FORCE ] @@ -101,6 +101,19 @@ REINDEX { INDEX | TABLE | DATABASE | SYSTEM } nam + ALL IN SCHEMA + + + Recreate all indexes of the specified schema. If the table has a + secondary TOAST table, that is reindexed as well. + Indexes on shared system catalogs are also processed. + This form of REINDEX cannot be executed inside a + transaction block. + + + + + DATABASE diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 8a1cb4b..bd7e183 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1770,34 +1770,52 @@ ReindexTable(RangeVar *relation) } /* - * ReindexDatabase - * Recreate indexes of a database. + * ReindexDatabaseOrSchema + * Recreate indexes of a database or schema. * + * kind means the type of object, database or schema. * 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) +ReindexDatabaseOrSchema(const char *objectName, bool do_system, bool do_user, ObjectType kind) { + Oid objectOid; Relation relationRelation; HeapScanDesc scan; + ScanKeyData *key = NULL; HeapTuple tuple; MemoryContext private_context; MemoryContext old; List *relids = NIL; ListCell *l; + bool do_database = (kind == OBJECT_DATABASE); + int nkeys; - AssertArg(databaseName); + AssertArg(objectName); + Assert(kind == OBJECT_DATABASE || kind == OBJECT_SCHEMA); - if (strcmp(databaseName, get_database_name(MyDatabaseId)) != 0) + /* Get OID of object for result */ + if (do_database) + objectOid = MyDatabaseId; + else + objectOid = get_namespace_oid(objectName, false); + + if (!do_database) + { + do_system = IsSystemNamespace(objectOid); + do_user = !do_system; + } + + if (do_database && 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())) + if (do_database && !pg_database_ownercheck(MyDatabaseId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - databaseName); + objectName); /* * Create a memory context that will survive forced transaction commits we @@ -1806,7 +1824,8 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) * abort cleanup logic. */ private_context = AllocSetContextCreate(PortalContext, - "ReindexDatabase", + (do_database) ? + "ReindexDatabase" : "ReindexSchema", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); @@ -1824,6 +1843,23 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) MemoryContextSwitchTo(old); } + /* For schema, we search target relations by relnamespce and relkind */ + if (!do_database) + { + key = palloc(sizeof(ScanKeyData) * 2); + ScanKeyInit(&key[0], + Anum_pg_class_relnamespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectOid)); + ScanKeyInit(&key[1], + Anum_pg_class_relkind, + BTEqualStrategyNumber, F_CHAREQ, + 'r'); + nkeys = 2; + } + else + nkeys = 0; + /* * Scan pg_class to build a list of the relations we need to reindex. * @@ -1831,7 +1867,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) * 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, nkeys, key); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple); @@ -1892,5 +1928,5 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) MemoryContextDelete(private_context); - return MyDatabaseId; + return objectOid; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index c98c27a..6dfd10e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -7197,6 +7197,14 @@ ReindexStmt: n->do_user = false; $$ = (Node *)n; } + | REINDEX ALL IN_P SCHEMA name opt_force + { + ReindexStmt *n = makeNode(ReindexStmt); + n->kind = OBJECT_SCHEMA; + n->name = $5; + n->relation = NULL; + $$ = (Node *)n; + } | REINDEX DATABASE name opt_force { ReindexStmt *n = makeNode(ReindexStmt); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 4a2a339..b5bda55 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -755,6 +755,7 @@ standard_ProcessUtility(Node *parsetree, case OBJECT_MATVIEW: ReindexTable(stmt->relation); break; + case OBJECT_SCHEMA: case OBJECT_DATABASE: /* @@ -764,9 +765,10 @@ standard_ProcessUtility(Node *parsetree, * intended effect! */ PreventTransactionChain(isTopLevel, - "REINDEX DATABASE"); - ReindexDatabase(stmt->name, - stmt->do_system, stmt->do_user); + (stmt->kind == OBJECT_SCHEMA) ? + "REINDEX ALL IN SCHEMA" : "REINDEX DATABASE"); + ReindexDatabaseOrSchema(stmt->name, + stmt->do_system, stmt->do_user, stmt->kind); break; default: elog(ERROR, "unrecognized object type: %d", diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 886188c..106ec8a 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -3330,7 +3330,7 @@ psql_completion(const char *text, int start, int end) else if (pg_strcasecmp(prev_wd, "REINDEX") == 0) { static const char *const list_REINDEX[] = - {"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL}; + {"TABLE", "INDEX", "SYSTEM", "ALL IN SCHEMA", "DATABASE", NULL}; COMPLETE_WITH_LIST(list_REINDEX); } @@ -3340,6 +3340,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL); else if (pg_strcasecmp(prev_wd, "INDEX") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL); + else if (pg_strcasecmp(prev_wd, "ALL IN SCHEMA") == 0 ) + COMPLETE_WITH_QUERY(Query_for_list_of_schemas); else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 || pg_strcasecmp(prev_wd, "DATABASE") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_databases); diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 0ebdbc1..330d05c 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -30,8 +30,8 @@ extern Oid DefineIndex(Oid relationId, bool quiet); extern Oid ReindexIndex(RangeVar *indexRelation); extern Oid ReindexTable(RangeVar *relation); -extern Oid ReindexDatabase(const char *databaseName, - bool do_system, bool do_user); +extern Oid ReindexDatabaseOrSchema(const char *databaseName, + bool do_system, bool do_user, ObjectType kind); extern char *makeObjectName(const char *name1, const char *name2, const char *label); extern char *ChooseRelationName(const char *name1, const char *name2, diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index a2bef7a..f2763fd 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -2354,6 +2354,63 @@ Indexes: "concur_index5" btree (f2) WHERE f1 = 'x'::text "std_index" btree (f2) +REINDEX ALL IN SCHEMA pg_catalog; +NOTICE: table "pg_catalog.pg_class" was reindexed +NOTICE: table "pg_catalog.pg_statistic" was reindexed +NOTICE: table "pg_catalog.pg_type" was reindexed +NOTICE: table "pg_catalog.pg_authid" was reindexed +NOTICE: table "pg_catalog.pg_largeobject" was reindexed +NOTICE: table "pg_catalog.pg_user_mapping" was reindexed +NOTICE: table "pg_catalog.pg_attribute" was reindexed +NOTICE: table "pg_catalog.pg_proc" was reindexed +NOTICE: table "pg_catalog.pg_attrdef" was reindexed +NOTICE: table "pg_catalog.pg_constraint" was reindexed +NOTICE: table "pg_catalog.pg_inherits" was reindexed +NOTICE: table "pg_catalog.pg_index" was reindexed +NOTICE: table "pg_catalog.pg_opfamily" was reindexed +NOTICE: table "pg_catalog.pg_opclass" was reindexed +NOTICE: table "pg_catalog.pg_am" was reindexed +NOTICE: table "pg_catalog.pg_amop" was reindexed +NOTICE: table "pg_catalog.pg_amproc" was reindexed +NOTICE: table "pg_catalog.pg_language" was reindexed +NOTICE: table "pg_catalog.pg_largeobject_metadata" was reindexed +NOTICE: table "pg_catalog.pg_aggregate" was reindexed +NOTICE: table "pg_catalog.pg_rewrite" was reindexed +NOTICE: table "pg_catalog.pg_trigger" was reindexed +NOTICE: table "pg_catalog.pg_event_trigger" was reindexed +NOTICE: table "pg_catalog.pg_description" was reindexed +NOTICE: table "pg_catalog.pg_cast" was reindexed +NOTICE: table "pg_catalog.pg_namespace" was reindexed +NOTICE: table "pg_catalog.pg_conversion" was reindexed +NOTICE: table "pg_catalog.pg_database" was reindexed +NOTICE: table "pg_catalog.pg_db_role_setting" was reindexed +NOTICE: table "pg_catalog.pg_tablespace" was reindexed +NOTICE: table "pg_catalog.pg_pltemplate" was reindexed +NOTICE: table "pg_catalog.pg_auth_members" was reindexed +NOTICE: table "pg_catalog.pg_shdepend" was reindexed +NOTICE: table "pg_catalog.pg_shdescription" was reindexed +NOTICE: table "pg_catalog.pg_ts_config" was reindexed +NOTICE: table "pg_catalog.pg_ts_config_map" was reindexed +NOTICE: table "pg_catalog.pg_ts_dict" was reindexed +NOTICE: table "pg_catalog.pg_ts_parser" was reindexed +NOTICE: table "pg_catalog.pg_ts_template" was reindexed +NOTICE: table "pg_catalog.pg_extension" was reindexed +NOTICE: table "pg_catalog.pg_foreign_data_wrapper" was reindexed +NOTICE: table "pg_catalog.pg_foreign_server" was reindexed +NOTICE: table "pg_catalog.pg_foreign_table" was reindexed +NOTICE: table "pg_catalog.pg_rowsecurity" was reindexed +NOTICE: table "pg_catalog.pg_default_acl" was reindexed +NOTICE: table "pg_catalog.pg_seclabel" was reindexed +NOTICE: table "pg_catalog.pg_shseclabel" was reindexed +NOTICE: table "pg_catalog.pg_collation" was reindexed +NOTICE: table "pg_catalog.pg_range" was reindexed +NOTICE: table "pg_catalog.pg_operator" was reindexed +NOTICE: table "pg_catalog.pg_enum" was reindexed +NOTICE: table "pg_catalog.pg_depend" was reindexed +BEGIN; +REINDEX ALL IN SCHEMA pg_catalog; +ERROR: REINDEX ALL IN SCHEMA cannot run inside a transaction block +END; -- -- Try some concurrent index drops -- diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index d4d24ef..a3aa914 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -743,6 +743,10 @@ VACUUM FULL concur_heap; \d concur_heap REINDEX TABLE concur_heap; \d concur_heap +REINDEX ALL IN SCHEMA pg_catalog; +BEGIN; +REINDEX ALL IN SCHEMA pg_catalog; +END; -- -- Try some concurrent index drops