Commit a3dc9260 authored by Michael Paquier's avatar Michael Paquier

Refactor option handling of CLUSTER, REINDEX and VACUUM

This continues the work done in b5913f61.  All the options of those
commands are changed to use hex values rather than enums to reduce the
risk of compatibility bugs when introducing new options.  Each option
set is moved into a new structure that can be extended with more
non-boolean options (this was already the case of VACUUM).  The code of
REINDEX is restructured so as manual REINDEX commands go through a
single routine from utility.c, like VACUUM, to ease the allocation
handling of option parameters when a command needs to go through
multiple transactions.

This can be used as a base infrastructure for future patches related to
those commands, including reindex filtering and tablespace support.

Per discussion with people mentioned below, as well as Alvaro Herrera
and Peter Eisentraut.

Author: Michael Paquier, Justin Pryzby
Reviewed-by: Alexey Kondratov, Justin Pryzby
Discussion: https://postgr.es/m/X8riynBLwxAD9uKk@paquier.xyz
parent 04eb75e7
...@@ -3594,7 +3594,7 @@ IndexGetRelation(Oid indexId, bool missing_ok) ...@@ -3594,7 +3594,7 @@ IndexGetRelation(Oid indexId, bool missing_ok)
*/ */
void void
reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
int options) ReindexParams *params)
{ {
Relation iRel, Relation iRel,
heapRelation; heapRelation;
...@@ -3602,7 +3602,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, ...@@ -3602,7 +3602,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
IndexInfo *indexInfo; IndexInfo *indexInfo;
volatile bool skipped_constraint = false; volatile bool skipped_constraint = false;
PGRUsage ru0; PGRUsage ru0;
bool progress = (options & REINDEXOPT_REPORT_PROGRESS) != 0; bool progress = ((params->options & REINDEXOPT_REPORT_PROGRESS) != 0);
pg_rusage_init(&ru0); pg_rusage_init(&ru0);
...@@ -3611,12 +3611,12 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, ...@@ -3611,12 +3611,12 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
* we only need to be sure no schema or data changes are going on. * we only need to be sure no schema or data changes are going on.
*/ */
heapId = IndexGetRelation(indexId, heapId = IndexGetRelation(indexId,
(options & REINDEXOPT_MISSING_OK) != 0); (params->options & REINDEXOPT_MISSING_OK) != 0);
/* if relation is missing, leave */ /* if relation is missing, leave */
if (!OidIsValid(heapId)) if (!OidIsValid(heapId))
return; return;
if ((options & REINDEXOPT_MISSING_OK) != 0) if ((params->options & REINDEXOPT_MISSING_OK) != 0)
heapRelation = try_table_open(heapId, ShareLock); heapRelation = try_table_open(heapId, ShareLock);
else else
heapRelation = table_open(heapId, ShareLock); heapRelation = table_open(heapId, ShareLock);
...@@ -3792,7 +3792,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, ...@@ -3792,7 +3792,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
} }
/* Log what we did */ /* Log what we did */
if (options & REINDEXOPT_VERBOSE) if ((params->options & REINDEXOPT_VERBOSE) != 0)
ereport(INFO, ereport(INFO,
(errmsg("index \"%s\" was reindexed", (errmsg("index \"%s\" was reindexed",
get_rel_name(indexId)), get_rel_name(indexId)),
...@@ -3846,7 +3846,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence, ...@@ -3846,7 +3846,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
* index rebuild. * index rebuild.
*/ */
bool bool
reindex_relation(Oid relid, int flags, int options) reindex_relation(Oid relid, int flags, ReindexParams *params)
{ {
Relation rel; Relation rel;
Oid toast_relid; Oid toast_relid;
...@@ -3861,7 +3861,7 @@ reindex_relation(Oid relid, int flags, int options) ...@@ -3861,7 +3861,7 @@ reindex_relation(Oid relid, int flags, int options)
* to prevent schema and data changes in it. The lock level used here * to prevent schema and data changes in it. The lock level used here
* should match ReindexTable(). * should match ReindexTable().
*/ */
if ((options & REINDEXOPT_MISSING_OK) != 0) if ((params->options & REINDEXOPT_MISSING_OK) != 0)
rel = try_table_open(relid, ShareLock); rel = try_table_open(relid, ShareLock);
else else
rel = table_open(relid, ShareLock); rel = table_open(relid, ShareLock);
...@@ -3935,7 +3935,7 @@ reindex_relation(Oid relid, int flags, int options) ...@@ -3935,7 +3935,7 @@ reindex_relation(Oid relid, int flags, int options)
} }
reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS), reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
persistence, options); persistence, params);
CommandCounterIncrement(); CommandCounterIncrement();
...@@ -3965,8 +3965,10 @@ reindex_relation(Oid relid, int flags, int options) ...@@ -3965,8 +3965,10 @@ reindex_relation(Oid relid, int flags, int options)
* Note that this should fail if the toast relation is missing, so * Note that this should fail if the toast relation is missing, so
* reset REINDEXOPT_MISSING_OK. * reset REINDEXOPT_MISSING_OK.
*/ */
result |= reindex_relation(toast_relid, flags, ReindexParams newparams = *params;
options & ~(REINDEXOPT_MISSING_OK));
newparams.options &= ~(REINDEXOPT_MISSING_OK);
result |= reindex_relation(toast_relid, flags, &newparams);
} }
return result; return result;
......
...@@ -103,7 +103,7 @@ void ...@@ -103,7 +103,7 @@ void
cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
{ {
ListCell *lc; ListCell *lc;
int options = 0; ClusterParams params = {0};
bool verbose = false; bool verbose = false;
/* Parse option list */ /* Parse option list */
...@@ -121,7 +121,7 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) ...@@ -121,7 +121,7 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
parser_errposition(pstate, opt->location))); parser_errposition(pstate, opt->location)));
} }
options = (verbose ? CLUOPT_VERBOSE : 0); params.options = (verbose ? CLUOPT_VERBOSE : 0);
if (stmt->relation != NULL) if (stmt->relation != NULL)
{ {
...@@ -192,7 +192,7 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) ...@@ -192,7 +192,7 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
table_close(rel, NoLock); table_close(rel, NoLock);
/* Do the job. */ /* Do the job. */
cluster_rel(tableOid, indexOid, options); cluster_rel(tableOid, indexOid, &params);
} }
else else
{ {
...@@ -234,14 +234,16 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) ...@@ -234,14 +234,16 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
foreach(rv, rvs) foreach(rv, rvs)
{ {
RelToCluster *rvtc = (RelToCluster *) lfirst(rv); RelToCluster *rvtc = (RelToCluster *) lfirst(rv);
ClusterParams cluster_params = params;
/* Start a new transaction for each relation. */ /* Start a new transaction for each relation. */
StartTransactionCommand(); StartTransactionCommand();
/* functions in indexes may want a snapshot set */ /* functions in indexes may want a snapshot set */
PushActiveSnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
/* Do the job. */ /* Do the job. */
cluster_params.options |= CLUOPT_RECHECK;
cluster_rel(rvtc->tableOid, rvtc->indexOid, cluster_rel(rvtc->tableOid, rvtc->indexOid,
options | CLUOPT_RECHECK); &cluster_params);
PopActiveSnapshot(); PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
} }
...@@ -272,11 +274,11 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel) ...@@ -272,11 +274,11 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
* and error messages should refer to the operation as VACUUM not CLUSTER. * and error messages should refer to the operation as VACUUM not CLUSTER.
*/ */
void void
cluster_rel(Oid tableOid, Oid indexOid, int options) cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params)
{ {
Relation OldHeap; Relation OldHeap;
bool verbose = ((options & CLUOPT_VERBOSE) != 0); bool verbose = ((params->options & CLUOPT_VERBOSE) != 0);
bool recheck = ((options & CLUOPT_RECHECK) != 0); bool recheck = ((params->options & CLUOPT_RECHECK) != 0);
/* Check for user-requested abort. */ /* Check for user-requested abort. */
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
...@@ -1355,6 +1357,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, ...@@ -1355,6 +1357,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
ObjectAddress object; ObjectAddress object;
Oid mapped_tables[4]; Oid mapped_tables[4];
int reindex_flags; int reindex_flags;
ReindexParams reindex_params = {0};
int i; int i;
/* Report that we are now swapping relation files */ /* Report that we are now swapping relation files */
...@@ -1412,7 +1415,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, ...@@ -1412,7 +1415,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE, pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
PROGRESS_CLUSTER_PHASE_REBUILD_INDEX); PROGRESS_CLUSTER_PHASE_REBUILD_INDEX);
reindex_relation(OIDOldHeap, reindex_flags, 0); reindex_relation(OIDOldHeap, reindex_flags, &reindex_params);
/* Report that we are now doing clean up */ /* Report that we are now doing clean up */
pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE, pgstat_progress_update_param(PROGRESS_CLUSTER_PHASE,
......
...@@ -86,12 +86,21 @@ static char *ChooseIndexName(const char *tabname, Oid namespaceId, ...@@ -86,12 +86,21 @@ static char *ChooseIndexName(const char *tabname, Oid namespaceId,
bool primary, bool isconstraint); bool primary, bool isconstraint);
static char *ChooseIndexNameAddition(List *colnames); static char *ChooseIndexNameAddition(List *colnames);
static List *ChooseIndexColumnNames(List *indexElems); static List *ChooseIndexColumnNames(List *indexElems);
static void ReindexIndex(RangeVar *indexRelation, ReindexParams *params,
bool isTopLevel);
static void RangeVarCallbackForReindexIndex(const RangeVar *relation, static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
Oid relId, Oid oldRelId, void *arg); Oid relId, Oid oldRelId, void *arg);
static Oid ReindexTable(RangeVar *relation, ReindexParams *params,
bool isTopLevel);
static void ReindexMultipleTables(const char *objectName,
ReindexObjectType objectKind, ReindexParams *params);
static void reindex_error_callback(void *args); static void reindex_error_callback(void *args);
static void ReindexPartitions(Oid relid, int options, bool isTopLevel); static void ReindexPartitions(Oid relid, ReindexParams *params,
static void ReindexMultipleInternal(List *relids, int options); bool isTopLevel);
static bool ReindexRelationConcurrently(Oid relationOid, int options); static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
static void update_relispartition(Oid relationId, bool newval); static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void); static inline void set_indexsafe_procflags(void);
...@@ -100,7 +109,7 @@ static inline void set_indexsafe_procflags(void); ...@@ -100,7 +109,7 @@ static inline void set_indexsafe_procflags(void);
*/ */
struct ReindexIndexCallbackState struct ReindexIndexCallbackState
{ {
int options; /* options from statement */ ReindexParams params; /* options from statement */
Oid locked_table_oid; /* tracks previously locked table */ Oid locked_table_oid; /* tracks previously locked table */
}; };
...@@ -2452,14 +2461,17 @@ ChooseIndexColumnNames(List *indexElems) ...@@ -2452,14 +2461,17 @@ ChooseIndexColumnNames(List *indexElems)
} }
/* /*
* ReindexParseOptions * ExecReindex
* Parse list of REINDEX options, returning a bitmask of ReindexOption. *
* Primary entry point for manual REINDEX commands. This is mainly a
* preparation wrapper for the real operations that will happen in
* each subroutine of REINDEX.
*/ */
int void
ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
{ {
ReindexParams params = {0};
ListCell *lc; ListCell *lc;
int options = 0;
bool concurrently = false; bool concurrently = false;
bool verbose = false; bool verbose = false;
...@@ -2480,19 +2492,51 @@ ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt) ...@@ -2480,19 +2492,51 @@ ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt)
parser_errposition(pstate, opt->location))); parser_errposition(pstate, opt->location)));
} }
options = if (concurrently)
PreventInTransactionBlock(isTopLevel,
"REINDEX CONCURRENTLY");
params.options =
(verbose ? REINDEXOPT_VERBOSE : 0) | (verbose ? REINDEXOPT_VERBOSE : 0) |
(concurrently ? REINDEXOPT_CONCURRENTLY : 0); (concurrently ? REINDEXOPT_CONCURRENTLY : 0);
return options; switch (stmt->kind)
{
case REINDEX_OBJECT_INDEX:
ReindexIndex(stmt->relation, &params, isTopLevel);
break;
case REINDEX_OBJECT_TABLE:
ReindexTable(stmt->relation, &params, isTopLevel);
break;
case REINDEX_OBJECT_SCHEMA:
case REINDEX_OBJECT_SYSTEM:
case REINDEX_OBJECT_DATABASE:
/*
* This cannot run inside a user transaction block; if we were
* inside a transaction, then its commit- and
* start-transaction-command calls would not have the intended
* effect!
*/
PreventInTransactionBlock(isTopLevel,
(stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
(stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
"REINDEX DATABASE");
ReindexMultipleTables(stmt->name, stmt->kind, &params);
break;
default:
elog(ERROR, "unrecognized object type: %d",
(int) stmt->kind);
break;
}
} }
/* /*
* ReindexIndex * ReindexIndex
* Recreate a specific index. * Recreate a specific index.
*/ */
void static void
ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel) ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
{ {
struct ReindexIndexCallbackState state; struct ReindexIndexCallbackState state;
Oid indOid; Oid indOid;
...@@ -2509,10 +2553,10 @@ ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel) ...@@ -2509,10 +2553,10 @@ ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel)
* upgrade the lock, but that's OK, because other sessions can't hold * upgrade the lock, but that's OK, because other sessions can't hold
* locks on our temporary table. * locks on our temporary table.
*/ */
state.options = options; state.params = *params;
state.locked_table_oid = InvalidOid; state.locked_table_oid = InvalidOid;
indOid = RangeVarGetRelidExtended(indexRelation, indOid = RangeVarGetRelidExtended(indexRelation,
(options & REINDEXOPT_CONCURRENTLY) != 0 ? (params->options & REINDEXOPT_CONCURRENTLY) != 0 ?
ShareUpdateExclusiveLock : AccessExclusiveLock, ShareUpdateExclusiveLock : AccessExclusiveLock,
0, 0,
RangeVarCallbackForReindexIndex, RangeVarCallbackForReindexIndex,
...@@ -2526,13 +2570,17 @@ ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel) ...@@ -2526,13 +2570,17 @@ ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel)
relkind = get_rel_relkind(indOid); relkind = get_rel_relkind(indOid);
if (relkind == RELKIND_PARTITIONED_INDEX) if (relkind == RELKIND_PARTITIONED_INDEX)
ReindexPartitions(indOid, options, isTopLevel); ReindexPartitions(indOid, params, isTopLevel);
else if ((options & REINDEXOPT_CONCURRENTLY) != 0 && else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP) persistence != RELPERSISTENCE_TEMP)
ReindexRelationConcurrently(indOid, options); ReindexRelationConcurrently(indOid, params);
else else
reindex_index(indOid, false, persistence, {
options | REINDEXOPT_REPORT_PROGRESS); ReindexParams newparams = *params;
newparams.options |= REINDEXOPT_REPORT_PROGRESS;
reindex_index(indOid, false, persistence, &newparams);
}
} }
/* /*
...@@ -2553,7 +2601,7 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation, ...@@ -2553,7 +2601,7 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
* non-concurrent case and table locks used by index_concurrently_*() for * non-concurrent case and table locks used by index_concurrently_*() for
* concurrent case. * concurrent case.
*/ */
table_lockmode = ((state->options & REINDEXOPT_CONCURRENTLY) != 0) ? table_lockmode = (state->params.options & REINDEXOPT_CONCURRENTLY) != 0 ?
ShareUpdateExclusiveLock : ShareLock; ShareUpdateExclusiveLock : ShareLock;
/* /*
...@@ -2610,8 +2658,8 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation, ...@@ -2610,8 +2658,8 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
* ReindexTable * ReindexTable
* Recreate all indexes of a table (and of its toast table, if any) * Recreate all indexes of a table (and of its toast table, if any)
*/ */
Oid static Oid
ReindexTable(RangeVar *relation, int options, bool isTopLevel) ReindexTable(RangeVar *relation, ReindexParams *params, bool isTopLevel)
{ {
Oid heapOid; Oid heapOid;
bool result; bool result;
...@@ -2625,17 +2673,17 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel) ...@@ -2625,17 +2673,17 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel)
* locks on our temporary table. * locks on our temporary table.
*/ */
heapOid = RangeVarGetRelidExtended(relation, heapOid = RangeVarGetRelidExtended(relation,
(options & REINDEXOPT_CONCURRENTLY) != 0 ? (params->options & REINDEXOPT_CONCURRENTLY) != 0 ?
ShareUpdateExclusiveLock : ShareLock, ShareUpdateExclusiveLock : ShareLock,
0, 0,
RangeVarCallbackOwnsTable, NULL); RangeVarCallbackOwnsTable, NULL);
if (get_rel_relkind(heapOid) == RELKIND_PARTITIONED_TABLE) if (get_rel_relkind(heapOid) == RELKIND_PARTITIONED_TABLE)
ReindexPartitions(heapOid, options, isTopLevel); ReindexPartitions(heapOid, params, isTopLevel);
else if ((options & REINDEXOPT_CONCURRENTLY) != 0 && else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
get_rel_persistence(heapOid) != RELPERSISTENCE_TEMP) get_rel_persistence(heapOid) != RELPERSISTENCE_TEMP)
{ {
result = ReindexRelationConcurrently(heapOid, options); result = ReindexRelationConcurrently(heapOid, params);
if (!result) if (!result)
ereport(NOTICE, ereport(NOTICE,
...@@ -2644,10 +2692,13 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel) ...@@ -2644,10 +2692,13 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel)
} }
else else
{ {
ReindexParams newparams = *params;
newparams.options |= REINDEXOPT_REPORT_PROGRESS;
result = reindex_relation(heapOid, result = reindex_relation(heapOid,
REINDEX_REL_PROCESS_TOAST | REINDEX_REL_PROCESS_TOAST |
REINDEX_REL_CHECK_CONSTRAINTS, REINDEX_REL_CHECK_CONSTRAINTS,
options | REINDEXOPT_REPORT_PROGRESS); &newparams);
if (!result) if (!result)
ereport(NOTICE, ereport(NOTICE,
(errmsg("table \"%s\" has no indexes to reindex", (errmsg("table \"%s\" has no indexes to reindex",
...@@ -2665,9 +2716,9 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel) ...@@ -2665,9 +2716,9 @@ ReindexTable(RangeVar *relation, int options, bool isTopLevel)
* 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!
*/ */
void static void
ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
int options) ReindexParams *params)
{ {
Oid objectOid; Oid objectOid;
Relation relationRelation; Relation relationRelation;
...@@ -2686,7 +2737,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, ...@@ -2686,7 +2737,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
objectKind == REINDEX_OBJECT_DATABASE); objectKind == REINDEX_OBJECT_DATABASE);
if (objectKind == REINDEX_OBJECT_SYSTEM && if (objectKind == REINDEX_OBJECT_SYSTEM &&
(options & REINDEXOPT_CONCURRENTLY) != 0) (params->options & REINDEXOPT_CONCURRENTLY) != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot reindex system catalogs concurrently"))); errmsg("cannot reindex system catalogs concurrently")));
...@@ -2794,7 +2845,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, ...@@ -2794,7 +2845,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
* Skip system tables, since index_create() would reject indexing them * Skip system tables, since index_create() would reject indexing them
* concurrently (and it would likely fail if we tried). * concurrently (and it would likely fail if we tried).
*/ */
if ((options & REINDEXOPT_CONCURRENTLY) != 0 && if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
IsCatalogRelationOid(relid)) IsCatalogRelationOid(relid))
{ {
if (!concurrent_warning) if (!concurrent_warning)
...@@ -2829,7 +2880,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, ...@@ -2829,7 +2880,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
* Process each relation listed in a separate transaction. Note that this * Process each relation listed in a separate transaction. Note that this
* commits and then starts a new transaction immediately. * commits and then starts a new transaction immediately.
*/ */
ReindexMultipleInternal(relids, options); ReindexMultipleInternal(relids, params);
MemoryContextDelete(private_context); MemoryContextDelete(private_context);
} }
...@@ -2860,7 +2911,7 @@ reindex_error_callback(void *arg) ...@@ -2860,7 +2911,7 @@ reindex_error_callback(void *arg)
* by the caller. * by the caller.
*/ */
static void static void
ReindexPartitions(Oid relid, int options, bool isTopLevel) ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{ {
List *partitions = NIL; List *partitions = NIL;
char relkind = get_rel_relkind(relid); char relkind = get_rel_relkind(relid);
...@@ -2937,7 +2988,7 @@ ReindexPartitions(Oid relid, int options, bool isTopLevel) ...@@ -2937,7 +2988,7 @@ ReindexPartitions(Oid relid, int options, bool isTopLevel)
* Process each partition listed in a separate transaction. Note that * Process each partition listed in a separate transaction. Note that
* this commits and then starts a new transaction immediately. * this commits and then starts a new transaction immediately.
*/ */
ReindexMultipleInternal(partitions, options); ReindexMultipleInternal(partitions, params);
/* /*
* Clean up working storage --- note we must do this after * Clean up working storage --- note we must do this after
...@@ -2955,7 +3006,7 @@ ReindexPartitions(Oid relid, int options, bool isTopLevel) ...@@ -2955,7 +3006,7 @@ ReindexPartitions(Oid relid, int options, bool isTopLevel)
* and starts a new transaction when finished. * and starts a new transaction when finished.
*/ */
static void static void
ReindexMultipleInternal(List *relids, int options) ReindexMultipleInternal(List *relids, ReindexParams *params)
{ {
ListCell *l; ListCell *l;
...@@ -2991,35 +3042,38 @@ ReindexMultipleInternal(List *relids, int options) ...@@ -2991,35 +3042,38 @@ ReindexMultipleInternal(List *relids, int options)
Assert(relkind != RELKIND_PARTITIONED_INDEX && Assert(relkind != RELKIND_PARTITIONED_INDEX &&
relkind != RELKIND_PARTITIONED_TABLE); relkind != RELKIND_PARTITIONED_TABLE);
if ((options & REINDEXOPT_CONCURRENTLY) != 0 && if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
relpersistence != RELPERSISTENCE_TEMP) relpersistence != RELPERSISTENCE_TEMP)
{ {
(void) ReindexRelationConcurrently(relid, ReindexParams newparams = *params;
options |
REINDEXOPT_MISSING_OK); newparams.options |= REINDEXOPT_MISSING_OK;
(void) ReindexRelationConcurrently(relid, &newparams);
/* ReindexRelationConcurrently() does the verbose output */ /* ReindexRelationConcurrently() does the verbose output */
} }
else if (relkind == RELKIND_INDEX) else if (relkind == RELKIND_INDEX)
{ {
reindex_index(relid, false, relpersistence, ReindexParams newparams = *params;
options |
REINDEXOPT_REPORT_PROGRESS | newparams.options |=
REINDEXOPT_MISSING_OK); REINDEXOPT_REPORT_PROGRESS | REINDEXOPT_MISSING_OK;
reindex_index(relid, false, relpersistence, &newparams);
PopActiveSnapshot(); PopActiveSnapshot();
/* reindex_index() does the verbose output */ /* reindex_index() does the verbose output */
} }
else else
{ {
bool result; bool result;
ReindexParams newparams = *params;
newparams.options |=
REINDEXOPT_REPORT_PROGRESS | REINDEXOPT_MISSING_OK;
result = reindex_relation(relid, result = reindex_relation(relid,
REINDEX_REL_PROCESS_TOAST | REINDEX_REL_PROCESS_TOAST |
REINDEX_REL_CHECK_CONSTRAINTS, REINDEX_REL_CHECK_CONSTRAINTS,
options | &newparams);
REINDEXOPT_REPORT_PROGRESS |
REINDEXOPT_MISSING_OK);
if (result && (options & REINDEXOPT_VERBOSE)) if (result && (params->options & REINDEXOPT_VERBOSE) != 0)
ereport(INFO, ereport(INFO,
(errmsg("table \"%s.%s\" was reindexed", (errmsg("table \"%s.%s\" was reindexed",
get_namespace_name(get_rel_namespace(relid)), get_namespace_name(get_rel_namespace(relid)),
...@@ -3059,7 +3113,7 @@ ReindexMultipleInternal(List *relids, int options) ...@@ -3059,7 +3113,7 @@ ReindexMultipleInternal(List *relids, int options)
* anyway, and a non-concurrent reindex is more efficient. * anyway, and a non-concurrent reindex is more efficient.
*/ */
static bool static bool
ReindexRelationConcurrently(Oid relationOid, int options) ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{ {
typedef struct ReindexIndexInfo typedef struct ReindexIndexInfo
{ {
...@@ -3099,7 +3153,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) ...@@ -3099,7 +3153,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
"ReindexConcurrent", "ReindexConcurrent",
ALLOCSET_SMALL_SIZES); ALLOCSET_SMALL_SIZES);
if (options & REINDEXOPT_VERBOSE) if ((params->options & REINDEXOPT_VERBOSE) != 0)
{ {
/* Save data needed by REINDEX VERBOSE in private context */ /* Save data needed by REINDEX VERBOSE in private context */
oldcontext = MemoryContextSwitchTo(private_context); oldcontext = MemoryContextSwitchTo(private_context);
...@@ -3144,7 +3198,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) ...@@ -3144,7 +3198,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
errmsg("cannot reindex system catalogs concurrently"))); errmsg("cannot reindex system catalogs concurrently")));
/* Open relation to get its indexes */ /* Open relation to get its indexes */
if ((options & REINDEXOPT_MISSING_OK) != 0) if ((params->options & REINDEXOPT_MISSING_OK) != 0)
{ {
heapRelation = try_table_open(relationOid, heapRelation = try_table_open(relationOid,
ShareUpdateExclusiveLock); ShareUpdateExclusiveLock);
...@@ -3251,7 +3305,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) ...@@ -3251,7 +3305,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
case RELKIND_INDEX: case RELKIND_INDEX:
{ {
Oid heapId = IndexGetRelation(relationOid, Oid heapId = IndexGetRelation(relationOid,
(options & REINDEXOPT_MISSING_OK) != 0); (params->options & REINDEXOPT_MISSING_OK) != 0);
Relation heapRelation; Relation heapRelation;
ReindexIndexInfo *idx; ReindexIndexInfo *idx;
...@@ -3281,7 +3335,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) ...@@ -3281,7 +3335,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
* to rebuild is not complete yet, and REINDEXOPT_MISSING_OK * to rebuild is not complete yet, and REINDEXOPT_MISSING_OK
* should not be used once all the session locks are taken. * should not be used once all the session locks are taken.
*/ */
if ((options & REINDEXOPT_MISSING_OK) != 0) if ((params->options & REINDEXOPT_MISSING_OK) != 0)
{ {
heapRelation = try_table_open(heapId, heapRelation = try_table_open(heapId,
ShareUpdateExclusiveLock); ShareUpdateExclusiveLock);
...@@ -3803,7 +3857,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) ...@@ -3803,7 +3857,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
StartTransactionCommand(); StartTransactionCommand();
/* Log what we did */ /* Log what we did */
if (options & REINDEXOPT_VERBOSE) if ((params->options & REINDEXOPT_VERBOSE) != 0)
{ {
if (relkind == RELKIND_INDEX) if (relkind == RELKIND_INDEX)
ereport(INFO, ereport(INFO,
......
...@@ -1854,6 +1854,7 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, ...@@ -1854,6 +1854,7 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
{ {
Oid heap_relid; Oid heap_relid;
Oid toast_relid; Oid toast_relid;
ReindexParams reindex_params = {0};
/* /*
* This effectively deletes all rows in the table, and may be done * This effectively deletes all rows in the table, and may be done
...@@ -1891,7 +1892,8 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged, ...@@ -1891,7 +1892,8 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
/* /*
* Reconstruct the indexes to match, and we're done. * Reconstruct the indexes to match, and we're done.
*/ */
reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST, 0); reindex_relation(heap_relid, REINDEX_REL_PROCESS_TOAST,
&reindex_params);
} }
pgstat_count_truncate(rel); pgstat_count_truncate(rel);
......
...@@ -530,7 +530,7 @@ vacuum(List *relations, VacuumParams *params, ...@@ -530,7 +530,7 @@ vacuum(List *relations, VacuumParams *params,
* ANALYZE. * ANALYZE.
*/ */
bool bool
vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, bits32 options)
{ {
char *relname; char *relname;
...@@ -604,7 +604,7 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) ...@@ -604,7 +604,7 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options)
* or locked, a log is emitted if possible. * or locked, a log is emitted if possible.
*/ */
Relation Relation
vacuum_open_relation(Oid relid, RangeVar *relation, int options, vacuum_open_relation(Oid relid, RangeVar *relation, bits32 options,
bool verbose, LOCKMODE lmode) bool verbose, LOCKMODE lmode)
{ {
Relation onerel; Relation onerel;
...@@ -1916,17 +1916,17 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params) ...@@ -1916,17 +1916,17 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
*/ */
if (params->options & VACOPT_FULL) if (params->options & VACOPT_FULL)
{ {
int cluster_options = 0; ClusterParams cluster_params = {0};
/* close relation before vacuuming, but hold lock until commit */ /* close relation before vacuuming, but hold lock until commit */
relation_close(onerel, NoLock); relation_close(onerel, NoLock);
onerel = NULL; onerel = NULL;
if ((params->options & VACOPT_VERBOSE) != 0) if ((params->options & VACOPT_VERBOSE) != 0)
cluster_options |= CLUOPT_VERBOSE; cluster_params.options |= CLUOPT_VERBOSE;
/* VACUUM FULL is now a variant of CLUSTER; see cluster.c */ /* VACUUM FULL is now a variant of CLUSTER; see cluster.c */
cluster_rel(relid, InvalidOid, cluster_options); cluster_rel(relid, InvalidOid, &cluster_params);
} }
else else
table_relation_vacuum(onerel, params, vac_strategy); table_relation_vacuum(onerel, params, vac_strategy);
......
...@@ -917,45 +917,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, ...@@ -917,45 +917,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
break; break;
case T_ReindexStmt: case T_ReindexStmt:
{ ExecReindex(pstate, (ReindexStmt *) parsetree, isTopLevel);
ReindexStmt *stmt = (ReindexStmt *) parsetree;
int options;
options = ReindexParseOptions(pstate, stmt);
if ((options & REINDEXOPT_CONCURRENTLY) != 0)
PreventInTransactionBlock(isTopLevel,
"REINDEX CONCURRENTLY");
switch (stmt->kind)
{
case REINDEX_OBJECT_INDEX:
ReindexIndex(stmt->relation, options, isTopLevel);
break;
case REINDEX_OBJECT_TABLE:
ReindexTable(stmt->relation, options, isTopLevel);
break;
case REINDEX_OBJECT_SCHEMA:
case REINDEX_OBJECT_SYSTEM:
case REINDEX_OBJECT_DATABASE:
/*
* This cannot run inside a user transaction block; if
* we were inside a transaction, then its commit- and
* start-transaction-command calls would not have the
* intended effect!
*/
PreventInTransactionBlock(isTopLevel,
(stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
(stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
"REINDEX DATABASE");
ReindexMultipleTables(stmt->name, stmt->kind, options);
break;
default:
elog(ERROR, "unrecognized object type: %d",
(int) stmt->kind);
break;
}
}
break; break;
/* /*
......
...@@ -30,13 +30,16 @@ typedef enum ...@@ -30,13 +30,16 @@ typedef enum
} IndexStateFlagsAction; } IndexStateFlagsAction;
/* options for REINDEX */ /* options for REINDEX */
typedef enum ReindexOption typedef struct ReindexParams
{ {
REINDEXOPT_VERBOSE = 1 << 0, /* print progress info */ bits32 options; /* bitmask of REINDEXOPT_* */
REINDEXOPT_REPORT_PROGRESS = 1 << 1, /* report pgstat progress */ } ReindexParams;
REINDEXOPT_MISSING_OK = 1 << 2, /* skip missing relations */
REINDEXOPT_CONCURRENTLY = 1 << 3 /* concurrent mode */ /* flag bits for ReindexParams->flags */
} ReindexOption; #define REINDEXOPT_VERBOSE 0x01 /* print progress info */
#define REINDEXOPT_REPORT_PROGRESS 0x02 /* report pgstat progress */
#define REINDEXOPT_MISSING_OK 0x04 /* skip missing relations */
#define REINDEXOPT_CONCURRENTLY 0x08 /* concurrent mode */
/* state info for validate_index bulkdelete callback */ /* state info for validate_index bulkdelete callback */
typedef struct ValidateIndexState typedef struct ValidateIndexState
...@@ -146,7 +149,7 @@ extern void index_set_state_flags(Oid indexId, IndexStateFlagsAction action); ...@@ -146,7 +149,7 @@ extern void index_set_state_flags(Oid indexId, IndexStateFlagsAction action);
extern Oid IndexGetRelation(Oid indexId, bool missing_ok); extern Oid IndexGetRelation(Oid indexId, bool missing_ok);
extern void reindex_index(Oid indexId, bool skip_constraint_checks, extern void reindex_index(Oid indexId, bool skip_constraint_checks,
char relpersistence, int options); char relpersistence, ReindexParams *params);
/* Flag bits for reindex_relation(): */ /* Flag bits for reindex_relation(): */
#define REINDEX_REL_PROCESS_TOAST 0x01 #define REINDEX_REL_PROCESS_TOAST 0x01
...@@ -155,7 +158,7 @@ extern void reindex_index(Oid indexId, bool skip_constraint_checks, ...@@ -155,7 +158,7 @@ extern void reindex_index(Oid indexId, bool skip_constraint_checks,
#define REINDEX_REL_FORCE_INDEXES_UNLOGGED 0x08 #define REINDEX_REL_FORCE_INDEXES_UNLOGGED 0x08
#define REINDEX_REL_FORCE_INDEXES_PERMANENT 0x10 #define REINDEX_REL_FORCE_INDEXES_PERMANENT 0x10
extern bool reindex_relation(Oid relid, int flags, int options); extern bool reindex_relation(Oid relid, int flags, ReindexParams *params);
extern bool ReindexIsProcessingHeap(Oid heapOid); extern bool ReindexIsProcessingHeap(Oid heapOid);
extern bool ReindexIsProcessingIndex(Oid indexOid); extern bool ReindexIsProcessingIndex(Oid indexOid);
......
...@@ -19,15 +19,18 @@ ...@@ -19,15 +19,18 @@
#include "utils/relcache.h" #include "utils/relcache.h"
/* flag bits for ClusterParams->flags */
#define CLUOPT_RECHECK 0x01 /* recheck relation state */
#define CLUOPT_VERBOSE 0x02 /* print progress info */
/* options for CLUSTER */ /* options for CLUSTER */
typedef enum ClusterOption typedef struct ClusterParams
{ {
CLUOPT_RECHECK = 1 << 0, /* recheck relation state */ bits32 options; /* bitmask of CLUOPT_* */
CLUOPT_VERBOSE = 1 << 1 /* print progress info */ } ClusterParams;
} ClusterOption;
extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel); extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel);
extern void cluster_rel(Oid tableOid, Oid indexOid, int options); extern void cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params);
extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid, extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
bool recheck, LOCKMODE lockmode); bool recheck, LOCKMODE lockmode);
extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal); extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
......
...@@ -34,11 +34,7 @@ extern ObjectAddress DefineIndex(Oid relationId, ...@@ -34,11 +34,7 @@ extern ObjectAddress DefineIndex(Oid relationId,
bool check_not_in_use, bool check_not_in_use,
bool skip_build, bool skip_build,
bool quiet); bool quiet);
extern int ReindexParseOptions(ParseState *pstate, ReindexStmt *stmt); extern void ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel);
extern void ReindexIndex(RangeVar *indexRelation, int options, bool isTopLevel);
extern Oid ReindexTable(RangeVar *relation, int options, bool isTopLevel);
extern void ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
int options);
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,
......
...@@ -174,17 +174,15 @@ typedef struct VacAttrStats ...@@ -174,17 +174,15 @@ typedef struct VacAttrStats
int rowstride; int rowstride;
} VacAttrStats; } VacAttrStats;
typedef enum VacuumOption /* flag bits for VacuumParams->options */
{ #define VACOPT_VACUUM 0x01 /* do VACUUM */
VACOPT_VACUUM = 1 << 0, /* do VACUUM */ #define VACOPT_ANALYZE 0x02 /* do ANALYZE */
VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */ #define VACOPT_VERBOSE 0x04 /* print progress info */
VACOPT_VERBOSE = 1 << 2, /* print progress info */ #define VACOPT_FREEZE 0x08 /* FREEZE option */
VACOPT_FREEZE = 1 << 3, /* FREEZE option */ #define VACOPT_FULL 0x10 /* FULL (non-concurrent) vacuum */
VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */ #define VACOPT_SKIP_LOCKED 0x20 /* skip if cannot get lock */
VACOPT_SKIP_LOCKED = 1 << 5, /* skip if cannot get lock */ #define VACOPT_SKIPTOAST 0x40 /* don't process the TOAST table, if any */
VACOPT_SKIPTOAST = 1 << 6, /* don't process the TOAST table, if any */ #define VACOPT_DISABLE_PAGE_SKIPPING 0x80 /* don't skip any pages */
VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */
} VacuumOption;
/* /*
* A ternary value used by vacuum parameters. * A ternary value used by vacuum parameters.
...@@ -207,7 +205,7 @@ typedef enum VacOptTernaryValue ...@@ -207,7 +205,7 @@ typedef enum VacOptTernaryValue
*/ */
typedef struct VacuumParams typedef struct VacuumParams
{ {
int options; /* bitmask of VacuumOption */ bits32 options; /* bitmask of VACOPT_* */
int freeze_min_age; /* min freeze age, -1 to use default */ int freeze_min_age; /* min freeze age, -1 to use default */
int freeze_table_age; /* age at which to scan whole table */ int freeze_table_age; /* age at which to scan whole table */
int multixact_freeze_min_age; /* min multixact freeze age, -1 to int multixact_freeze_min_age; /* min multixact freeze age, -1 to
...@@ -275,9 +273,10 @@ extern void vacuum_set_xid_limits(Relation rel, ...@@ -275,9 +273,10 @@ extern void vacuum_set_xid_limits(Relation rel,
extern void vac_update_datfrozenxid(void); extern void vac_update_datfrozenxid(void);
extern void vacuum_delay_point(void); extern void vacuum_delay_point(void);
extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple,
int options); bits32 options);
extern Relation vacuum_open_relation(Oid relid, RangeVar *relation, extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
int options, bool verbose, LOCKMODE lmode); bits32 options, bool verbose,
LOCKMODE lmode);
/* in commands/analyze.c */ /* in commands/analyze.c */
extern void analyze_rel(Oid relid, RangeVar *relation, extern void analyze_rel(Oid relid, RangeVar *relation,
......
...@@ -347,6 +347,7 @@ ClosePortalStmt ...@@ -347,6 +347,7 @@ ClosePortalStmt
ClosePtrType ClosePtrType
Clump Clump
ClusterInfo ClusterInfo
ClusterParams
ClusterStmt ClusterStmt
CmdType CmdType
CoalesceExpr CoalesceExpr
...@@ -2063,6 +2064,7 @@ RegisteredBgWorker ...@@ -2063,6 +2064,7 @@ RegisteredBgWorker
ReindexErrorInfo ReindexErrorInfo
ReindexIndexInfo ReindexIndexInfo
ReindexObjectType ReindexObjectType
ReindexParams
ReindexStmt ReindexStmt
ReindexType ReindexType
RelFileNode RelFileNode
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment