mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
REINDEX SCHEMA
Add new SCHEMA option to REINDEX and reindexdb. Sawada Masahiko Reviewed by Michael Paquier and Fabrízio de Royes Mello
This commit is contained in:
parent
8001fe67a3
commit
fe263d115a
@ -21,7 +21,7 @@ PostgreSQL documentation
|
|||||||
|
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">name</replaceable> [ FORCE ]
|
REINDEX { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } <replaceable class="PARAMETER">name</replaceable> [ FORCE ]
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
@ -100,6 +100,19 @@ REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">nam
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>SCHEMA</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Recreate all indexes of the specified schema. If a table of this
|
||||||
|
schema has a secondary <quote>TOAST</> table, that is reindexed as
|
||||||
|
well. Indexes on shared system catalogs are also processed.
|
||||||
|
This form of <command>REINDEX</command> cannot be executed inside a
|
||||||
|
transaction block.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>DATABASE</literal></term>
|
<term><literal>DATABASE</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -24,6 +24,16 @@ PostgreSQL documentation
|
|||||||
<command>reindexdb</command>
|
<command>reindexdb</command>
|
||||||
<arg rep="repeat"><replaceable>connection-option</replaceable></arg>
|
<arg rep="repeat"><replaceable>connection-option</replaceable></arg>
|
||||||
|
|
||||||
|
<arg choice="plain" rep="repeat">
|
||||||
|
<arg choice="opt">
|
||||||
|
<group choice="plain">
|
||||||
|
<arg choice="plain"><option>--schema</option></arg>
|
||||||
|
<arg choice="plain"><option>-S</option></arg>
|
||||||
|
</group>
|
||||||
|
<replaceable>table</replaceable>
|
||||||
|
</arg>
|
||||||
|
</arg>
|
||||||
|
|
||||||
<arg choice="plain" rep="repeat">
|
<arg choice="plain" rep="repeat">
|
||||||
<arg choice="opt">
|
<arg choice="opt">
|
||||||
<group choice="plain">
|
<group choice="plain">
|
||||||
@ -161,6 +171,18 @@ PostgreSQL documentation
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-S <replaceable class="parameter">schema</replaceable></></term>
|
||||||
|
<term><option>--schema=<replaceable class="parameter">schema</replaceable></></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Reindex <replaceable class="parameter">schema</replaceable> only.
|
||||||
|
Multiple schemas can be reindexed by writing multiple
|
||||||
|
<option>-S</> switches.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-t <replaceable class="parameter">table</replaceable></></term>
|
<term><option>-t <replaceable class="parameter">table</replaceable></></term>
|
||||||
<term><option>--table=<replaceable class="parameter">table</replaceable></></term>
|
<term><option>--table=<replaceable class="parameter">table</replaceable></></term>
|
||||||
|
@ -1777,34 +1777,58 @@ ReindexTable(RangeVar *relation)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ReindexDatabase
|
* ReindexObject
|
||||||
* Recreate indexes of a database.
|
* Recreate indexes of object whose type is defined by objectKind.
|
||||||
*
|
*
|
||||||
* To reduce the probability of deadlocks, each table is reindexed in a
|
* To reduce the probability of deadlocks, each table is reindexed in a
|
||||||
* separate transaction, so we can release the lock on it right away.
|
* separate transaction, so we can release the lock on it right away.
|
||||||
* That means this must not be called within a user transaction block!
|
* That means this must not be called within a user transaction block!
|
||||||
*/
|
*/
|
||||||
Oid
|
Oid
|
||||||
ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
|
ReindexObject(const char *objectName, ReindexObjectType objectKind)
|
||||||
{
|
{
|
||||||
|
Oid objectOid;
|
||||||
Relation relationRelation;
|
Relation relationRelation;
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
|
ScanKeyData *scan_keys = NULL;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
MemoryContext private_context;
|
MemoryContext private_context;
|
||||||
MemoryContext old;
|
MemoryContext old;
|
||||||
List *relids = NIL;
|
List *relids = NIL;
|
||||||
ListCell *l;
|
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,
|
* Get OID of object to reindex, being the database currently being
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
* used by session for a database or for system catalogs, or the schema
|
||||||
errmsg("can only reindex the currently open database")));
|
* 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()))
|
if (!pg_namespace_ownercheck(objectOid, GetUserId()))
|
||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
|
||||||
databaseName);
|
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
|
* Create a memory context that will survive forced transaction commits we
|
||||||
@ -1813,24 +1837,50 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
|
|||||||
* abort cleanup logic.
|
* abort cleanup logic.
|
||||||
*/
|
*/
|
||||||
private_context = AllocSetContextCreate(PortalContext,
|
private_context = AllocSetContextCreate(PortalContext,
|
||||||
"ReindexDatabase",
|
(objectKind == REINDEX_OBJECT_SCHEMA) ?
|
||||||
|
"ReindexSchema" : "ReindexDatabase",
|
||||||
ALLOCSET_DEFAULT_MINSIZE,
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We always want to reindex pg_class first. This ensures that if there
|
* We always want to reindex pg_class first when reindexing system
|
||||||
* is any corruption in pg_class' indexes, they will be fixed before we
|
* catalogs or a database. This ensures that if there is any corruption
|
||||||
* process any other tables. This is critical because reindexing itself
|
* in pg_class' indexes, they will be fixed before we process any other
|
||||||
* will try to update pg_class.
|
* 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);
|
old = MemoryContextSwitchTo(private_context);
|
||||||
relids = lappend_oid(relids, RelationRelationId);
|
relids = lappend_oid(relids, RelationRelationId);
|
||||||
MemoryContextSwitchTo(old);
|
MemoryContextSwitchTo(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
* Scan pg_class to build a list of the relations we need to reindex.
|
||||||
*
|
*
|
||||||
@ -1838,7 +1888,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
|
|||||||
* rels will be processed indirectly by reindex_relation).
|
* rels will be processed indirectly by reindex_relation).
|
||||||
*/
|
*/
|
||||||
relationRelation = heap_open(RelationRelationId, AccessShareLock);
|
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)
|
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
|
||||||
{
|
{
|
||||||
Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
|
Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);
|
||||||
@ -1854,19 +1904,17 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Check user/system classification, and optionally skip */
|
/* Check user/system classification, and optionally skip */
|
||||||
if (IsSystemClass(relid, classtuple))
|
if (!IsSystemClass(relid, classtuple) &&
|
||||||
{
|
objectKind == REINDEX_OBJECT_SYSTEM)
|
||||||
if (!do_system)
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!do_user)
|
|
||||||
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)
|
if (HeapTupleGetOid(tuple) == RelationRelationId)
|
||||||
continue; /* got it already */
|
continue;
|
||||||
|
|
||||||
old = MemoryContextSwitchTo(private_context);
|
old = MemoryContextSwitchTo(private_context);
|
||||||
relids = lappend_oid(relids, relid);
|
relids = lappend_oid(relids, relid);
|
||||||
@ -1898,6 +1946,8 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
|
|||||||
StartTransactionCommand();
|
StartTransactionCommand();
|
||||||
|
|
||||||
MemoryContextDelete(private_context);
|
MemoryContextDelete(private_context);
|
||||||
|
if (scan_keys)
|
||||||
|
pfree(scan_keys);
|
||||||
|
|
||||||
return MyDatabaseId;
|
return objectOid;
|
||||||
}
|
}
|
||||||
|
@ -404,7 +404,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
|||||||
%type <boolean> copy_from opt_program
|
%type <boolean> copy_from opt_program
|
||||||
|
|
||||||
%type <ival> opt_column event cursor_options opt_hold opt_set_data
|
%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
|
%type <node> fetch_args limit_clause select_limit_value
|
||||||
offset_clause select_offset_value
|
offset_clause select_offset_value
|
||||||
@ -7198,41 +7198,48 @@ opt_if_exists: IF_P EXISTS { $$ = TRUE; }
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
ReindexStmt:
|
ReindexStmt:
|
||||||
REINDEX reindex_type qualified_name opt_force
|
REINDEX INDEX qualified_name opt_force
|
||||||
{
|
{
|
||||||
ReindexStmt *n = makeNode(ReindexStmt);
|
ReindexStmt *n = makeNode(ReindexStmt);
|
||||||
n->kind = $2;
|
n->kind = REINDEX_OBJECT_INDEX;
|
||||||
n->relation = $3;
|
n->relation = $3;
|
||||||
n->name = NULL;
|
n->name = NULL;
|
||||||
$$ = (Node *)n;
|
$$ = (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
|
| REINDEX SYSTEM_P name opt_force
|
||||||
{
|
{
|
||||||
ReindexStmt *n = makeNode(ReindexStmt);
|
ReindexStmt *n = makeNode(ReindexStmt);
|
||||||
n->kind = OBJECT_DATABASE;
|
n->kind = REINDEX_OBJECT_SYSTEM;
|
||||||
n->name = $3;
|
n->name = $3;
|
||||||
n->relation = NULL;
|
n->relation = NULL;
|
||||||
n->do_system = true;
|
|
||||||
n->do_user = false;
|
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| REINDEX DATABASE name opt_force
|
| REINDEX DATABASE name opt_force
|
||||||
{
|
{
|
||||||
ReindexStmt *n = makeNode(ReindexStmt);
|
ReindexStmt *n = makeNode(ReindexStmt);
|
||||||
n->kind = OBJECT_DATABASE;
|
n->kind = REINDEX_OBJECT_DATABASE;
|
||||||
n->name = $3;
|
n->name = $3;
|
||||||
n->relation = NULL;
|
n->relation = NULL;
|
||||||
n->do_system = true;
|
|
||||||
n->do_user = true;
|
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
reindex_type:
|
|
||||||
INDEX { $$ = OBJECT_INDEX; }
|
|
||||||
| TABLE { $$ = OBJECT_TABLE; }
|
|
||||||
;
|
|
||||||
|
|
||||||
opt_force: FORCE { $$ = TRUE; }
|
opt_force: FORCE { $$ = TRUE; }
|
||||||
| /* EMPTY */ { $$ = FALSE; }
|
| /* EMPTY */ { $$ = FALSE; }
|
||||||
;
|
;
|
||||||
|
@ -749,14 +749,15 @@ standard_ProcessUtility(Node *parsetree,
|
|||||||
PreventCommandDuringRecovery("REINDEX");
|
PreventCommandDuringRecovery("REINDEX");
|
||||||
switch (stmt->kind)
|
switch (stmt->kind)
|
||||||
{
|
{
|
||||||
case OBJECT_INDEX:
|
case REINDEX_OBJECT_INDEX:
|
||||||
ReindexIndex(stmt->relation);
|
ReindexIndex(stmt->relation);
|
||||||
break;
|
break;
|
||||||
case OBJECT_TABLE:
|
case REINDEX_OBJECT_TABLE:
|
||||||
case OBJECT_MATVIEW:
|
|
||||||
ReindexTable(stmt->relation);
|
ReindexTable(stmt->relation);
|
||||||
break;
|
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
|
* This cannot run inside a user transaction block; if
|
||||||
@ -765,9 +766,9 @@ standard_ProcessUtility(Node *parsetree,
|
|||||||
* intended effect!
|
* intended effect!
|
||||||
*/
|
*/
|
||||||
PreventTransactionChain(isTopLevel,
|
PreventTransactionChain(isTopLevel,
|
||||||
"REINDEX DATABASE");
|
(stmt->kind == REINDEX_OBJECT_SCHEMA) ?
|
||||||
ReindexDatabase(stmt->name,
|
"REINDEX SCHEMA" : "REINDEX DATABASE");
|
||||||
stmt->do_system, stmt->do_user);
|
ReindexObject(stmt->name, stmt->kind);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "unrecognized object type: %d",
|
elog(ERROR, "unrecognized object type: %d",
|
||||||
|
@ -3331,7 +3331,7 @@ psql_completion(const char *text, int start, int end)
|
|||||||
else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
|
else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
|
||||||
{
|
{
|
||||||
static const char *const list_REINDEX[] =
|
static const char *const list_REINDEX[] =
|
||||||
{"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
|
{"TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE", NULL};
|
||||||
|
|
||||||
COMPLETE_WITH_LIST(list_REINDEX);
|
COMPLETE_WITH_LIST(list_REINDEX);
|
||||||
}
|
}
|
||||||
@ -3341,6 +3341,8 @@ psql_completion(const char *text, int start, int end)
|
|||||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
|
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, NULL);
|
||||||
else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
|
else if (pg_strcasecmp(prev_wd, "INDEX") == 0)
|
||||||
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
|
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
|
||||||
|
else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0 )
|
||||||
|
COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
|
||||||
else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
|
else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
|
||||||
pg_strcasecmp(prev_wd, "DATABASE") == 0)
|
pg_strcasecmp(prev_wd, "DATABASE") == 0)
|
||||||
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
|
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
|
||||||
|
@ -41,6 +41,7 @@ main(int argc, char *argv[])
|
|||||||
{"password", no_argument, NULL, 'W'},
|
{"password", no_argument, NULL, 'W'},
|
||||||
{"echo", no_argument, NULL, 'e'},
|
{"echo", no_argument, NULL, 'e'},
|
||||||
{"quiet", no_argument, NULL, 'q'},
|
{"quiet", no_argument, NULL, 'q'},
|
||||||
|
{"schema", required_argument, NULL, 'S'},
|
||||||
{"dbname", required_argument, NULL, 'd'},
|
{"dbname", required_argument, NULL, 'd'},
|
||||||
{"all", no_argument, NULL, 'a'},
|
{"all", no_argument, NULL, 'a'},
|
||||||
{"system", no_argument, NULL, 's'},
|
{"system", no_argument, NULL, 's'},
|
||||||
@ -66,6 +67,7 @@ main(int argc, char *argv[])
|
|||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
SimpleStringList indexes = {NULL, NULL};
|
SimpleStringList indexes = {NULL, NULL};
|
||||||
SimpleStringList tables = {NULL, NULL};
|
SimpleStringList tables = {NULL, NULL};
|
||||||
|
SimpleStringList schemas = {NULL, NULL};
|
||||||
|
|
||||||
progname = get_progname(argv[0]);
|
progname = get_progname(argv[0]);
|
||||||
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
|
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
|
||||||
@ -73,7 +75,7 @@ main(int argc, char *argv[])
|
|||||||
handle_help_version_opts(argc, argv, "reindexdb", help);
|
handle_help_version_opts(argc, argv, "reindexdb", help);
|
||||||
|
|
||||||
/* process command-line options */
|
/* process command-line options */
|
||||||
while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:ast:i:", long_options, &optindex)) != -1)
|
while ((c = getopt_long(argc, argv, "h:p:U:wWeqS:d:ast:i:", long_options, &optindex)) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
@ -98,6 +100,9 @@ main(int argc, char *argv[])
|
|||||||
case 'q':
|
case 'q':
|
||||||
quiet = true;
|
quiet = true;
|
||||||
break;
|
break;
|
||||||
|
case 'S':
|
||||||
|
simple_string_list_append(&schemas, optarg);
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
dbname = pg_strdup(optarg);
|
dbname = pg_strdup(optarg);
|
||||||
break;
|
break;
|
||||||
@ -154,6 +159,11 @@ main(int argc, char *argv[])
|
|||||||
fprintf(stderr, _("%s: cannot reindex all databases and system catalogs at the same time\n"), progname);
|
fprintf(stderr, _("%s: cannot reindex all databases and system catalogs at the same time\n"), progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
if (schemas.head != NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("%s: cannot reindex specific schema(s) in all databases\n"), progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (tables.head != NULL)
|
if (tables.head != NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: cannot reindex specific table(s) in all databases\n"), progname);
|
fprintf(stderr, _("%s: cannot reindex specific table(s) in all databases\n"), progname);
|
||||||
@ -170,6 +180,11 @@ main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
else if (syscatalog)
|
else if (syscatalog)
|
||||||
{
|
{
|
||||||
|
if (schemas.head != NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("%s: cannot reindex specific schema(s) and system catalogs at the same time\n"), progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (tables.head != NULL)
|
if (tables.head != NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: cannot reindex specific table(s) and system catalogs at the same time\n"), progname);
|
fprintf(stderr, _("%s: cannot reindex specific table(s) and system catalogs at the same time\n"), progname);
|
||||||
@ -206,6 +221,17 @@ main(int argc, char *argv[])
|
|||||||
dbname = get_user_name_or_exit(progname);
|
dbname = get_user_name_or_exit(progname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (schemas.head != NULL)
|
||||||
|
{
|
||||||
|
SimpleStringListCell *cell;
|
||||||
|
|
||||||
|
for (cell = schemas.head; cell; cell = cell->next)
|
||||||
|
{
|
||||||
|
reindex_one_database(cell->val, dbname, "SCHEMA", host, port,
|
||||||
|
username, prompt_password, progname, echo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (indexes.head != NULL)
|
if (indexes.head != NULL)
|
||||||
{
|
{
|
||||||
SimpleStringListCell *cell;
|
SimpleStringListCell *cell;
|
||||||
@ -226,8 +252,8 @@ main(int argc, char *argv[])
|
|||||||
username, prompt_password, progname, echo);
|
username, prompt_password, progname, echo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* reindex database only if neither index nor table is specified */
|
/* reindex database only if neither index nor table nor schema is specified */
|
||||||
if (indexes.head == NULL && tables.head == NULL)
|
if (indexes.head == NULL && tables.head == NULL && schemas.head == NULL)
|
||||||
reindex_one_database(dbname, dbname, "DATABASE", host, port,
|
reindex_one_database(dbname, dbname, "DATABASE", host, port,
|
||||||
username, prompt_password, progname, echo);
|
username, prompt_password, progname, echo);
|
||||||
}
|
}
|
||||||
@ -251,6 +277,8 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
|
|||||||
appendPQExpBuffer(&sql, " TABLE %s", name);
|
appendPQExpBuffer(&sql, " TABLE %s", name);
|
||||||
else if (strcmp(type, "INDEX") == 0)
|
else if (strcmp(type, "INDEX") == 0)
|
||||||
appendPQExpBuffer(&sql, " INDEX %s", name);
|
appendPQExpBuffer(&sql, " INDEX %s", name);
|
||||||
|
else if (strcmp(type, "SCHEMA") == 0)
|
||||||
|
appendPQExpBuffer(&sql, " SCHEMA %s", name);
|
||||||
else if (strcmp(type, "DATABASE") == 0)
|
else if (strcmp(type, "DATABASE") == 0)
|
||||||
appendPQExpBuffer(&sql, " DATABASE %s", fmtId(name));
|
appendPQExpBuffer(&sql, " DATABASE %s", fmtId(name));
|
||||||
appendPQExpBufferStr(&sql, ";");
|
appendPQExpBufferStr(&sql, ";");
|
||||||
@ -266,6 +294,9 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
|
|||||||
if (strcmp(type, "INDEX") == 0)
|
if (strcmp(type, "INDEX") == 0)
|
||||||
fprintf(stderr, _("%s: reindexing of index \"%s\" in database \"%s\" failed: %s"),
|
fprintf(stderr, _("%s: reindexing of index \"%s\" in database \"%s\" failed: %s"),
|
||||||
progname, name, dbname, PQerrorMessage(conn));
|
progname, name, dbname, PQerrorMessage(conn));
|
||||||
|
if (strcmp(type, "SCHEMA") == 0)
|
||||||
|
fprintf(stderr, _("%s: reindexing of schema \"%s\" in database \"%s\" failed: %s"),
|
||||||
|
progname, name, dbname, PQerrorMessage(conn));
|
||||||
else
|
else
|
||||||
fprintf(stderr, _("%s: reindexing of database \"%s\" failed: %s"),
|
fprintf(stderr, _("%s: reindexing of database \"%s\" failed: %s"),
|
||||||
progname, dbname, PQerrorMessage(conn));
|
progname, dbname, PQerrorMessage(conn));
|
||||||
@ -348,6 +379,7 @@ help(const char *progname)
|
|||||||
printf(_(" -i, --index=INDEX recreate specific index(es) only\n"));
|
printf(_(" -i, --index=INDEX recreate specific index(es) only\n"));
|
||||||
printf(_(" -q, --quiet don't write any messages\n"));
|
printf(_(" -q, --quiet don't write any messages\n"));
|
||||||
printf(_(" -s, --system reindex system catalogs\n"));
|
printf(_(" -s, --system reindex system catalogs\n"));
|
||||||
|
printf(_(" -S, --schema=SCHEMA recreate specific schema(s) only\n"));
|
||||||
printf(_(" -t, --table=TABLE reindex specific table(s) only\n"));
|
printf(_(" -t, --table=TABLE reindex specific table(s) only\n"));
|
||||||
printf(_(" -V, --version output version information, then exit\n"));
|
printf(_(" -V, --version output version information, then exit\n"));
|
||||||
printf(_(" -?, --help show this help, then exit\n"));
|
printf(_(" -?, --help show this help, then exit\n"));
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 16;
|
use Test::More tests => 17;
|
||||||
|
|
||||||
program_help_ok('reindexdb');
|
program_help_ok('reindexdb');
|
||||||
program_version_ok('reindexdb');
|
program_version_ok('reindexdb');
|
||||||
@ -27,7 +27,10 @@ issues_sql_like(
|
|||||||
[ 'reindexdb', 'postgres', '-i', 'test1x' ],
|
[ 'reindexdb', 'postgres', '-i', 'test1x' ],
|
||||||
qr/statement: REINDEX INDEX test1x;/,
|
qr/statement: REINDEX INDEX test1x;/,
|
||||||
'reindex specific index');
|
'reindex specific index');
|
||||||
|
issues_sql_like(
|
||||||
|
[ 'reindexdb', 'postgres', '-S', 'pg_catalog' ],
|
||||||
|
qr/statement: REINDEX SCHEMA pg_catalog;/,
|
||||||
|
'reindex specific schema');
|
||||||
issues_sql_like(
|
issues_sql_like(
|
||||||
[ 'reindexdb', 'postgres', '-s' ],
|
[ 'reindexdb', 'postgres', '-s' ],
|
||||||
qr/statement: REINDEX SYSTEM postgres;/,
|
qr/statement: REINDEX SYSTEM postgres;/,
|
||||||
|
@ -30,8 +30,7 @@ extern Oid DefineIndex(Oid relationId,
|
|||||||
bool quiet);
|
bool quiet);
|
||||||
extern Oid ReindexIndex(RangeVar *indexRelation);
|
extern Oid ReindexIndex(RangeVar *indexRelation);
|
||||||
extern Oid ReindexTable(RangeVar *relation);
|
extern Oid ReindexTable(RangeVar *relation);
|
||||||
extern Oid ReindexDatabase(const char *databaseName,
|
extern Oid ReindexObject(const char *databaseName, ReindexObjectType kind);
|
||||||
bool do_system, bool do_user);
|
|
||||||
extern char *makeObjectName(const char *name1, const char *name2,
|
extern char *makeObjectName(const char *name1, const char *name2,
|
||||||
const char *label);
|
const char *label);
|
||||||
extern char *ChooseRelationName(const char *name1, const char *name2,
|
extern char *ChooseRelationName(const char *name1, const char *name2,
|
||||||
|
@ -2721,10 +2721,19 @@ typedef struct ConstraintsSetStmt
|
|||||||
* REINDEX Statement
|
* REINDEX Statement
|
||||||
* ----------------------
|
* ----------------------
|
||||||
*/
|
*/
|
||||||
|
typedef enum ReindexObjectType
|
||||||
|
{
|
||||||
|
REINDEX_OBJECT_INDEX, /* index */
|
||||||
|
REINDEX_OBJECT_TABLE, /* table or materialized view */
|
||||||
|
REINDEX_OBJECT_SCHEMA, /* schema */
|
||||||
|
REINDEX_OBJECT_SYSTEM, /* system catalogs */
|
||||||
|
REINDEX_OBJECT_DATABASE /* database */
|
||||||
|
} ReindexObjectType;
|
||||||
|
|
||||||
typedef struct ReindexStmt
|
typedef struct ReindexStmt
|
||||||
{
|
{
|
||||||
NodeTag type;
|
NodeTag type;
|
||||||
ObjectType kind; /* OBJECT_INDEX, OBJECT_TABLE, etc. */
|
ReindexObjectType kind; /* REINDEX_OBJECT_INDEX, REINDEX_OBJECT_TABLE, etc. */
|
||||||
RangeVar *relation; /* Table or index to reindex */
|
RangeVar *relation; /* Table or index to reindex */
|
||||||
const char *name; /* name of database to reindex */
|
const char *name; /* name of database to reindex */
|
||||||
bool do_system; /* include system tables in database case */
|
bool do_system; /* include system tables in database case */
|
||||||
|
@ -2831,3 +2831,34 @@ explain (costs off)
|
|||||||
Index Cond: ((thousand = 1) AND (tenthous = 1001))
|
Index Cond: ((thousand = 1) AND (tenthous = 1001))
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- REINDEX SCHEMA
|
||||||
|
--
|
||||||
|
REINDEX SCHEMA schema_to_reindex; -- failure, schema does not exist
|
||||||
|
ERROR: schema "schema_to_reindex" does not exist
|
||||||
|
CREATE SCHEMA schema_to_reindex;
|
||||||
|
CREATE TABLE schema_to_reindex.table1(col1 SERIAL PRIMARY KEY);
|
||||||
|
CREATE TABLE schema_to_reindex.table2(col1 SERIAL PRIMARY KEY, col2 VARCHAR(100) NOT NULL);
|
||||||
|
CREATE INDEX ON schema_to_reindex.table2(col2);
|
||||||
|
REINDEX SCHEMA schema_to_reindex;
|
||||||
|
NOTICE: table "schema_to_reindex.table1" was reindexed
|
||||||
|
NOTICE: table "schema_to_reindex.table2" was reindexed
|
||||||
|
BEGIN;
|
||||||
|
REINDEX SCHEMA schema_to_reindex; -- failure, cannot run in a transaction
|
||||||
|
ERROR: REINDEX SCHEMA cannot run inside a transaction block
|
||||||
|
END;
|
||||||
|
-- Failure for unauthorized user
|
||||||
|
CREATE ROLE reindexuser login;
|
||||||
|
SET SESSION ROLE user_reindex;
|
||||||
|
ERROR: role "user_reindex" does not exist
|
||||||
|
REINDEX SCHEMA schema_to_reindex;
|
||||||
|
NOTICE: table "schema_to_reindex.table1" was reindexed
|
||||||
|
NOTICE: table "schema_to_reindex.table2" was reindexed
|
||||||
|
-- Clean up
|
||||||
|
RESET ROLE;
|
||||||
|
DROP ROLE user_reindex;
|
||||||
|
ERROR: role "user_reindex" does not exist
|
||||||
|
DROP SCHEMA schema_to_reindex CASCADE;
|
||||||
|
NOTICE: drop cascades to 2 other objects
|
||||||
|
DETAIL: drop cascades to table schema_to_reindex.table1
|
||||||
|
drop cascades to table schema_to_reindex.table2
|
||||||
|
@ -964,3 +964,26 @@ RESET enable_indexscan;
|
|||||||
|
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
select * from tenk1 where (thousand, tenthous) in ((1,1001), (null,null));
|
select * from tenk1 where (thousand, tenthous) in ((1,1001), (null,null));
|
||||||
|
|
||||||
|
--
|
||||||
|
-- REINDEX SCHEMA
|
||||||
|
--
|
||||||
|
REINDEX SCHEMA schema_to_reindex; -- failure, schema does not exist
|
||||||
|
CREATE SCHEMA schema_to_reindex;
|
||||||
|
CREATE TABLE schema_to_reindex.table1(col1 SERIAL PRIMARY KEY);
|
||||||
|
CREATE TABLE schema_to_reindex.table2(col1 SERIAL PRIMARY KEY, col2 VARCHAR(100) NOT NULL);
|
||||||
|
CREATE INDEX ON schema_to_reindex.table2(col2);
|
||||||
|
REINDEX SCHEMA schema_to_reindex;
|
||||||
|
BEGIN;
|
||||||
|
REINDEX SCHEMA schema_to_reindex; -- failure, cannot run in a transaction
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Failure for unauthorized user
|
||||||
|
CREATE ROLE reindexuser login;
|
||||||
|
SET SESSION ROLE user_reindex;
|
||||||
|
REINDEX SCHEMA schema_to_reindex;
|
||||||
|
|
||||||
|
-- Clean up
|
||||||
|
RESET ROLE;
|
||||||
|
DROP ROLE user_reindex;
|
||||||
|
DROP SCHEMA schema_to_reindex CASCADE;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user