diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index d2856a379e..75b45f7cd5 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -85,7 +85,7 @@ static MemoryContext anl_context = NULL; static BufferAccessStrategy vac_strategy; -static void do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, +static void do_analyze_rel(Relation onerel, int options, List *va_cols, AcquireSampleRowsFunc acquirefunc, BlockNumber relpages, bool inh, bool in_outer_xact, int elevel); static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, @@ -115,7 +115,7 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull); * analyze_rel() -- analyze one relation */ void -analyze_rel(Oid relid, VacuumStmt *vacstmt, +analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols, bool in_outer_xact, BufferAccessStrategy bstrategy) { Relation onerel; @@ -124,7 +124,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BlockNumber relpages = 0; /* Select logging level */ - if (vacstmt->options & VACOPT_VERBOSE) + if (options & VACOPT_VERBOSE) elevel = INFO; else elevel = DEBUG2; @@ -144,7 +144,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, * matter if we ever try to accumulate stats on dead tuples.) If the rel * has been dropped since we last saw it, we don't need to process it. */ - if (!(vacstmt->options & VACOPT_NOWAIT)) + if (!(options & VACOPT_NOWAIT)) onerel = try_relation_open(relid, ShareUpdateExclusiveLock); else if (ConditionalLockRelationOid(relid, ShareUpdateExclusiveLock)) onerel = try_relation_open(relid, NoLock); @@ -155,7 +155,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, ereport(LOG, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("skipping analyze of \"%s\" --- lock not available", - vacstmt->relation->relname))); + relation->relname))); } if (!onerel) return; @@ -167,7 +167,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared))) { /* No need for a WARNING if we already complained during VACUUM */ - if (!(vacstmt->options & VACOPT_VACUUM)) + if (!(options & VACOPT_VACUUM)) { if (onerel->rd_rel->relisshared) ereport(WARNING, @@ -248,7 +248,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, else { /* No need for a WARNING if we already complained during VACUUM */ - if (!(vacstmt->options & VACOPT_VACUUM)) + if (!(options & VACOPT_VACUUM)) ereport(WARNING, (errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables", RelationGetRelationName(onerel)))); @@ -266,14 +266,14 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, /* * Do the normal non-recursive ANALYZE. */ - do_analyze_rel(onerel, vacstmt, acquirefunc, relpages, + do_analyze_rel(onerel, options, va_cols, acquirefunc, relpages, false, in_outer_xact, elevel); /* * If there are child tables, do recursive ANALYZE. */ if (onerel->rd_rel->relhassubclass) - do_analyze_rel(onerel, vacstmt, acquirefunc, relpages, + do_analyze_rel(onerel, options, va_cols, acquirefunc, relpages, true, in_outer_xact, elevel); /* @@ -302,7 +302,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, * acquirefunc for each child table. */ static void -do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, +do_analyze_rel(Relation onerel, int options, List *va_cols, AcquireSampleRowsFunc acquirefunc, BlockNumber relpages, bool inh, bool in_outer_xact, int elevel) { @@ -372,14 +372,14 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, * * Note that system attributes are never analyzed. */ - if (vacstmt->va_cols != NIL) + if (va_cols != NIL) { ListCell *le; - vacattrstats = (VacAttrStats **) palloc(list_length(vacstmt->va_cols) * + vacattrstats = (VacAttrStats **) palloc(list_length(va_cols) * sizeof(VacAttrStats *)); tcnt = 0; - foreach(le, vacstmt->va_cols) + foreach(le, va_cols) { char *col = strVal(lfirst(le)); @@ -436,7 +436,7 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, thisdata->indexInfo = indexInfo = BuildIndexInfo(Irel[ind]); thisdata->tupleFract = 1.0; /* fix later if partial */ - if (indexInfo->ii_Expressions != NIL && vacstmt->va_cols == NIL) + if (indexInfo->ii_Expressions != NIL && va_cols == NIL) { ListCell *indexpr_item = list_head(indexInfo->ii_Expressions); @@ -595,7 +595,7 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, * VACUUM ANALYZE, don't overwrite the accurate count already inserted by * VACUUM. */ - if (!inh && !(vacstmt->options & VACOPT_VACUUM)) + if (!inh && !(options & VACOPT_VACUUM)) { for (ind = 0; ind < nindexes; ind++) { @@ -623,7 +623,7 @@ do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, pgstat_report_analyze(onerel, totalrows, totaldeadrows); /* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup */ - if (!(vacstmt->options & VACOPT_VACUUM)) + if (!(options & VACOPT_VACUUM)) { for (ind = 0; ind < nindexes; ind++) { diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 74475684fc..bd57b683d8 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -71,35 +71,79 @@ static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, MultiXactId lastSaneMinMulti); -static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, - bool for_wraparound); +static bool vacuum_rel(Oid relid, RangeVar *relation, int options, + VacuumParams *params); +/* + * Primary entry point for manual VACUUM and ANALYZE commands + * + * This is mainly a preparation wrapper for the real operations that will + * happen in vacuum(). + */ +void +ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel) +{ + VacuumParams params; + + /* sanity checks on options */ + Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE)); + Assert((vacstmt->options & VACOPT_VACUUM) || + !(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE))); + Assert((vacstmt->options & VACOPT_ANALYZE) || vacstmt->va_cols == NIL); + Assert(!(vacstmt->options & VACOPT_SKIPTOAST)); + + /* + * All freeze ages are zero if the FREEZE option is given; otherwise pass + * them as -1 which means to use the default values. + */ + if (vacstmt->options & VACOPT_FREEZE) + { + params.freeze_min_age = 0; + params.freeze_table_age = 0; + params.multixact_freeze_min_age = 0; + params.multixact_freeze_table_age = 0; + } + else + { + params.freeze_min_age = -1; + params.freeze_table_age = -1; + params.multixact_freeze_min_age = -1; + params.multixact_freeze_table_age = -1; + } + + /* user-invoked vacuum is never "for wraparound" */ + params.is_wraparound = false; + + /* Now go through the common routine */ + vacuum(vacstmt->options, vacstmt->relation, InvalidOid, ¶ms, + vacstmt->va_cols, NULL, isTopLevel); +} /* * Primary entry point for VACUUM and ANALYZE commands. * - * relid is normally InvalidOid; if it is not, then it provides the relation - * OID to be processed, and vacstmt->relation is ignored. (The non-invalid - * case is currently only used by autovacuum.) + * options is a bitmask of VacuumOption flags, indicating what to do. * - * do_toast is passed as FALSE by autovacuum, because it processes TOAST - * tables separately. + * relid, if not InvalidOid, indicate the relation to process; otherwise, + * the RangeVar is used. (The latter must always be passed, because it's + * used for error messages.) * - * for_wraparound is used by autovacuum to let us know when it's forcing - * a vacuum for wraparound, which should not be auto-canceled. + * params contains a set of parameters that can be used to customize the + * behavior. + * + * va_cols is a list of columns to analyze, or NIL to process them all. * * bstrategy is normally given as NULL, but in autovacuum it can be passed * in to use the same buffer strategy object across multiple vacuum() calls. * * isTopLevel should be passed down from ProcessUtility. * - * It is the caller's responsibility that vacstmt and bstrategy - * (if given) be allocated in a memory context that won't disappear - * at transaction commit. + * It is the caller's responsibility that all parameters are allocated in a + * memory context that will not disappear at transaction commit. */ void -vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, - BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel) +vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params, + List *va_cols, BufferAccessStrategy bstrategy, bool isTopLevel) { const char *stmttype; volatile bool in_outer_xact, @@ -107,13 +151,9 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, List *relations; static bool in_vacuum = false; - /* sanity checks on options */ - Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE)); - Assert((vacstmt->options & VACOPT_VACUUM) || - !(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE))); - Assert((vacstmt->options & VACOPT_ANALYZE) || vacstmt->va_cols == NIL); + Assert(params != NULL); - stmttype = (vacstmt->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE"; + stmttype = (options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE"; /* * We cannot run VACUUM inside a user transaction block; if we were inside @@ -123,7 +163,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, * * ANALYZE (without VACUUM) can run either way. */ - if (vacstmt->options & VACOPT_VACUUM) + if (options & VACOPT_VACUUM) { PreventTransactionChain(isTopLevel, stmttype); in_outer_xact = false; @@ -143,7 +183,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, * Send info about dead objects to the statistics collector, unless we are * in autovacuum --- autovacuum.c does this for itself. */ - if ((vacstmt->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) + if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) pgstat_vacuum_stat(); /* @@ -175,7 +215,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, * Build list of relations to process, unless caller gave us one. (If we * build one, we put it in vac_context for safekeeping.) */ - relations = get_rel_oids(relid, vacstmt->relation); + relations = get_rel_oids(relid, relation); /* * Decide whether we need to start/commit our own transactions. @@ -191,11 +231,11 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, * transaction block, and also in an autovacuum worker, use own * transactions so we can release locks sooner. */ - if (vacstmt->options & VACOPT_VACUUM) + if (options & VACOPT_VACUUM) use_own_xacts = true; else { - Assert(vacstmt->options & VACOPT_ANALYZE); + Assert(options & VACOPT_ANALYZE); if (IsAutoVacuumWorkerProcess()) use_own_xacts = true; else if (in_outer_xact) @@ -245,13 +285,13 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, { Oid relid = lfirst_oid(cur); - if (vacstmt->options & VACOPT_VACUUM) + if (options & VACOPT_VACUUM) { - if (!vacuum_rel(relid, vacstmt, do_toast, for_wraparound)) + if (!vacuum_rel(relid, relation, options, params)) continue; } - if (vacstmt->options & VACOPT_ANALYZE) + if (options & VACOPT_ANALYZE) { /* * If using separate xacts, start one for analyze. Otherwise, @@ -264,7 +304,8 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, PushActiveSnapshot(GetTransactionSnapshot()); } - analyze_rel(relid, vacstmt, in_outer_xact, vac_strategy); + analyze_rel(relid, relation, options, + va_cols, in_outer_xact, vac_strategy); if (use_own_xacts) { @@ -299,7 +340,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, StartTransactionCommand(); } - if ((vacstmt->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) + if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) { /* * Update pg_database.datfrozenxid, and truncate pg_clog if possible. @@ -1113,7 +1154,7 @@ vac_truncate_clog(TransactionId frozenXID, * At entry and exit, we are not inside a transaction. */ static bool -vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) +vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) { LOCKMODE lmode; Relation onerel; @@ -1123,6 +1164,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) int save_sec_context; int save_nestlevel; + Assert(params != NULL); + /* Begin a transaction for vacuuming this relation */ StartTransactionCommand(); @@ -1132,7 +1175,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) */ PushActiveSnapshot(GetTransactionSnapshot()); - if (!(vacstmt->options & VACOPT_FULL)) + if (!(options & VACOPT_FULL)) { /* * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets @@ -1156,7 +1199,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); MyPgXact->vacuumFlags |= PROC_IN_VACUUM; - if (for_wraparound) + if (params->is_wraparound) MyPgXact->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND; LWLockRelease(ProcArrayLock); } @@ -1172,7 +1215,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either * way, we can be sure that no other backend is vacuuming the same table. */ - lmode = (vacstmt->options & VACOPT_FULL) ? AccessExclusiveLock : ShareUpdateExclusiveLock; + lmode = (options & VACOPT_FULL) ? AccessExclusiveLock : ShareUpdateExclusiveLock; /* * Open the relation and get the appropriate lock on it. @@ -1183,7 +1226,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) * If we've been asked not to wait for the relation lock, acquire it first * in non-blocking mode, before calling try_relation_open(). */ - if (!(vacstmt->options & VACOPT_NOWAIT)) + if (!(options & VACOPT_NOWAIT)) onerel = try_relation_open(relid, lmode); else if (ConditionalLockRelationOid(relid, lmode)) onerel = try_relation_open(relid, NoLock); @@ -1194,7 +1237,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) ereport(LOG, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("skipping vacuum of \"%s\" --- lock not available", - vacstmt->relation->relname))); + relation->relname))); } if (!onerel) @@ -1286,7 +1329,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) * us to process it. In VACUUM FULL, though, the toast table is * automatically rebuilt by cluster_rel so we shouldn't recurse to it. */ - if (do_toast && !(vacstmt->options & VACOPT_FULL)) + if (!(options & VACOPT_SKIPTOAST) && !(options & VACOPT_FULL)) toast_relid = onerel->rd_rel->reltoastrelid; else toast_relid = InvalidOid; @@ -1305,7 +1348,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) /* * Do the actual work --- either FULL or "lazy" vacuum */ - if (vacstmt->options & VACOPT_FULL) + if (options & VACOPT_FULL) { /* close relation before vacuuming, but hold lock until commit */ relation_close(onerel, NoLock); @@ -1313,10 +1356,10 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) /* VACUUM FULL is now a variant of CLUSTER; see cluster.c */ cluster_rel(relid, InvalidOid, false, - (vacstmt->options & VACOPT_VERBOSE) != 0); + (options & VACOPT_VERBOSE) != 0); } else - lazy_vacuum_rel(onerel, vacstmt, vac_strategy); + lazy_vacuum_rel(onerel, options, params, vac_strategy); /* Roll back any GUC changes executed by index functions */ AtEOXact_GUC(false, save_nestlevel); @@ -1342,7 +1385,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound) * totally unimportant for toast relations. */ if (toast_relid != InvalidOid) - vacuum_rel(toast_relid, vacstmt, false, for_wraparound); + vacuum_rel(toast_relid, relation, options, params); /* * Now release the session-level lock on the master table. diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 7d9e49eb33..cd5ca4c2f9 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -169,7 +169,7 @@ static bool heap_page_is_all_visible(Relation rel, Buffer buf, * and locked the relation. */ void -lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, +lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, BufferAccessStrategy bstrategy) { LVRelStats *vacrelstats; @@ -193,6 +193,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, TransactionId new_frozen_xid; MultiXactId new_min_multi; + Assert(params != NULL); + /* measure elapsed time iff autovacuum logging requires it */ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) { @@ -200,7 +202,7 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, starttime = GetCurrentTimestamp(); } - if (vacstmt->options & VACOPT_VERBOSE) + if (options & VACOPT_VERBOSE) elevel = INFO; else elevel = DEBUG2; @@ -208,9 +210,10 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, vac_strategy = bstrategy; vacuum_set_xid_limits(onerel, - vacstmt->freeze_min_age, vacstmt->freeze_table_age, - vacstmt->multixact_freeze_min_age, - vacstmt->multixact_freeze_table_age, + params->freeze_min_age, + params->freeze_table_age, + params->multixact_freeze_min_age, + params->multixact_freeze_table_age, &OldestXmin, &FreezeLimit, &xidFullScanLimit, &MultiXactCutoff, &mxactFullScanLimit); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 3c6a964a65..029761e74f 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3300,10 +3300,6 @@ _copyVacuumStmt(const VacuumStmt *from) VacuumStmt *newnode = makeNode(VacuumStmt); COPY_SCALAR_FIELD(options); - COPY_SCALAR_FIELD(freeze_min_age); - COPY_SCALAR_FIELD(freeze_table_age); - COPY_SCALAR_FIELD(multixact_freeze_min_age); - COPY_SCALAR_FIELD(multixact_freeze_table_age); COPY_NODE_FIELD(relation); COPY_NODE_FIELD(va_cols); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index fcd58ada3d..190e50ab8c 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1503,10 +1503,6 @@ static bool _equalVacuumStmt(const VacuumStmt *a, const VacuumStmt *b) { COMPARE_SCALAR_FIELD(options); - COMPARE_SCALAR_FIELD(freeze_min_age); - COMPARE_SCALAR_FIELD(freeze_table_age); - COMPARE_SCALAR_FIELD(multixact_freeze_min_age); - COMPARE_SCALAR_FIELD(multixact_freeze_table_age); COMPARE_NODE_FIELD(relation); COMPARE_NODE_FIELD(va_cols); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 149962035d..82405b9d26 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -9034,12 +9034,10 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose n->options = VACOPT_VACUUM; if ($2) n->options |= VACOPT_FULL; + if ($3) + n->options |= VACOPT_FREEZE; if ($4) n->options |= VACOPT_VERBOSE; - n->freeze_min_age = $3 ? 0 : -1; - n->freeze_table_age = $3 ? 0 : -1; - n->multixact_freeze_min_age = $3 ? 0 : -1; - n->multixact_freeze_table_age = $3 ? 0 : -1; n->relation = NULL; n->va_cols = NIL; $$ = (Node *)n; @@ -9050,12 +9048,10 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose n->options = VACOPT_VACUUM; if ($2) n->options |= VACOPT_FULL; + if ($3) + n->options |= VACOPT_FREEZE; if ($4) n->options |= VACOPT_VERBOSE; - n->freeze_min_age = $3 ? 0 : -1; - n->freeze_table_age = $3 ? 0 : -1; - n->multixact_freeze_min_age = $3 ? 0 : -1; - n->multixact_freeze_table_age = $3 ? 0 : -1; n->relation = $5; n->va_cols = NIL; $$ = (Node *)n; @@ -9066,30 +9062,16 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose n->options |= VACOPT_VACUUM; if ($2) n->options |= VACOPT_FULL; + if ($3) + n->options |= VACOPT_FREEZE; if ($4) n->options |= VACOPT_VERBOSE; - n->freeze_min_age = $3 ? 0 : -1; - n->freeze_table_age = $3 ? 0 : -1; - n->multixact_freeze_min_age = $3 ? 0 : -1; - n->multixact_freeze_table_age = $3 ? 0 : -1; $$ = (Node *)n; } | VACUUM '(' vacuum_option_list ')' { VacuumStmt *n = makeNode(VacuumStmt); n->options = VACOPT_VACUUM | $3; - if (n->options & VACOPT_FREEZE) - { - n->freeze_min_age = n->freeze_table_age = 0; - n->multixact_freeze_min_age = 0; - n->multixact_freeze_table_age = 0; - } - else - { - n->freeze_min_age = n->freeze_table_age = -1; - n->multixact_freeze_min_age = -1; - n->multixact_freeze_table_age = -1; - } n->relation = NULL; n->va_cols = NIL; $$ = (Node *) n; @@ -9098,18 +9080,6 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose { VacuumStmt *n = makeNode(VacuumStmt); n->options = VACOPT_VACUUM | $3; - if (n->options & VACOPT_FREEZE) - { - n->freeze_min_age = n->freeze_table_age = 0; - n->multixact_freeze_min_age = 0; - n->multixact_freeze_table_age = 0; - } - else - { - n->freeze_min_age = n->freeze_table_age = -1; - n->multixact_freeze_min_age = -1; - n->multixact_freeze_table_age = -1; - } n->relation = $5; n->va_cols = $6; if (n->va_cols != NIL) /* implies analyze */ @@ -9137,10 +9107,6 @@ AnalyzeStmt: n->options = VACOPT_ANALYZE; if ($2) n->options |= VACOPT_VERBOSE; - n->freeze_min_age = -1; - n->freeze_table_age = -1; - n->multixact_freeze_min_age = -1; - n->multixact_freeze_table_age = -1; n->relation = NULL; n->va_cols = NIL; $$ = (Node *)n; @@ -9151,10 +9117,6 @@ AnalyzeStmt: n->options = VACOPT_ANALYZE; if ($2) n->options |= VACOPT_VERBOSE; - n->freeze_min_age = -1; - n->freeze_table_age = -1; - n->multixact_freeze_min_age = -1; - n->multixact_freeze_table_age = -1; n->relation = $3; n->va_cols = $4; $$ = (Node *)n; diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index ee556f3600..5ccae24b25 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -184,16 +184,11 @@ typedef struct av_relation typedef struct autovac_table { Oid at_relid; - bool at_dovacuum; - bool at_doanalyze; - int at_freeze_min_age; - int at_freeze_table_age; - int at_multixact_freeze_min_age; - int at_multixact_freeze_table_age; + int at_vacoptions; /* bitmask of VacuumOption */ + VacuumParams at_params; int at_vacuum_cost_delay; int at_vacuum_cost_limit; bool at_dobalance; - bool at_wraparound; char *at_relname; char *at_nspname; char *at_datname; @@ -2301,7 +2296,7 @@ do_autovacuum(void) * next table in our list. */ HOLD_INTERRUPTS(); - if (tab->at_dovacuum) + if (tab->at_vacoptions & VACOPT_VACUUM) errcontext("automatic vacuum of table \"%s.%s.%s\"", tab->at_datname, tab->at_nspname, tab->at_relname); else @@ -2528,15 +2523,17 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, tab = palloc(sizeof(autovac_table)); tab->at_relid = relid; - tab->at_dovacuum = dovacuum; - tab->at_doanalyze = doanalyze; - tab->at_freeze_min_age = freeze_min_age; - tab->at_freeze_table_age = freeze_table_age; - tab->at_multixact_freeze_min_age = multixact_freeze_min_age; - tab->at_multixact_freeze_table_age = multixact_freeze_table_age; + tab->at_vacoptions = VACOPT_SKIPTOAST | + (dovacuum ? VACOPT_VACUUM : 0) | + (doanalyze ? VACOPT_ANALYZE : 0) | + (wraparound ? VACOPT_NOWAIT : 0); + tab->at_params.freeze_min_age = freeze_min_age; + tab->at_params.freeze_table_age = freeze_table_age; + tab->at_params.multixact_freeze_min_age = multixact_freeze_min_age; + tab->at_params.multixact_freeze_table_age = multixact_freeze_table_age; + tab->at_params.is_wraparound = wraparound; tab->at_vacuum_cost_limit = vac_cost_limit; tab->at_vacuum_cost_delay = vac_cost_delay; - tab->at_wraparound = wraparound; tab->at_relname = NULL; tab->at_nspname = NULL; tab->at_datname = NULL; @@ -2737,39 +2734,22 @@ relation_needs_vacanalyze(Oid relid, * Vacuum and/or analyze the specified table */ static void -autovacuum_do_vac_analyze(autovac_table *tab, - BufferAccessStrategy bstrategy) +autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy) { - VacuumStmt vacstmt; - RangeVar rangevar; + RangeVar rangevar; /* Set up command parameters --- use local variables instead of palloc */ - MemSet(&vacstmt, 0, sizeof(vacstmt)); MemSet(&rangevar, 0, sizeof(rangevar)); rangevar.schemaname = tab->at_nspname; rangevar.relname = tab->at_relname; rangevar.location = -1; - vacstmt.type = T_VacuumStmt; - if (!tab->at_wraparound) - vacstmt.options = VACOPT_NOWAIT; - if (tab->at_dovacuum) - vacstmt.options |= VACOPT_VACUUM; - if (tab->at_doanalyze) - vacstmt.options |= VACOPT_ANALYZE; - vacstmt.freeze_min_age = tab->at_freeze_min_age; - vacstmt.freeze_table_age = tab->at_freeze_table_age; - vacstmt.multixact_freeze_min_age = tab->at_multixact_freeze_min_age; - vacstmt.multixact_freeze_table_age = tab->at_multixact_freeze_table_age; - /* we pass the OID, but might need this anyway for an error message */ - vacstmt.relation = &rangevar; - vacstmt.va_cols = NIL; - /* Let pgstat know what we're doing */ autovac_report_activity(tab); - vacuum(&vacstmt, tab->at_relid, false, bstrategy, tab->at_wraparound, true); + vacuum(tab->at_vacoptions, &rangevar, tab->at_relid, &tab->at_params, NIL, + bstrategy, true); } /* @@ -2791,10 +2771,10 @@ autovac_report_activity(autovac_table *tab) int len; /* Report the command and possible options */ - if (tab->at_dovacuum) + if (tab->at_vacoptions & VACOPT_VACUUM) snprintf(activity, MAX_AUTOVAC_ACTIV_LEN, "autovacuum: VACUUM%s", - tab->at_doanalyze ? " ANALYZE" : ""); + tab->at_vacoptions & VACOPT_ANALYZE ? " ANALYZE" : ""); else snprintf(activity, MAX_AUTOVAC_ACTIV_LEN, "autovacuum: ANALYZE"); @@ -2806,7 +2786,7 @@ autovac_report_activity(autovac_table *tab) snprintf(activity + len, MAX_AUTOVAC_ACTIV_LEN - len, " %s.%s%s", tab->at_nspname, tab->at_relname, - tab->at_wraparound ? " (to prevent wraparound)" : ""); + tab->at_params.is_wraparound ? " (to prevent wraparound)" : ""); /* Set statement_timestamp() to current time for pg_stat_activity */ SetCurrentStatementStartTimestamp(); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 065475dda2..d9443b1496 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -627,7 +627,7 @@ standard_ProcessUtility(Node *parsetree, /* we choose to allow this during "read only" transactions */ PreventCommandDuringRecovery((stmt->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE"); - vacuum(stmt, InvalidOid, true, NULL, false, isTopLevel); + ExecVacuum(stmt, isTopLevel); } break; diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 4275484349..9fd2516923 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -130,6 +130,19 @@ typedef struct VacAttrStats int rowstride; } VacAttrStats; +/* + * Parameters customizing behavior of VACUUM and ANALYZE. + */ +typedef struct VacuumParams +{ + int freeze_min_age; /* min freeze age, -1 to use default */ + int freeze_table_age; /* age at which to scan whole table */ + int multixact_freeze_min_age; /* min multixact freeze age, + * -1 to use default */ + int multixact_freeze_table_age; /* multixact age at which to + * scan whole table */ + bool is_wraparound; /* force a for-wraparound vacuum */ +} VacuumParams; /* GUC parameters */ extern PGDLLIMPORT int default_statistics_target; /* PGDLLIMPORT for @@ -141,8 +154,10 @@ extern int vacuum_multixact_freeze_table_age; /* in commands/vacuum.c */ -extern void vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, - BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel); +extern void ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel); +extern void vacuum(int options, RangeVar *relation, Oid relid, + VacuumParams *params, List *va_cols, + BufferAccessStrategy bstrategy, bool isTopLevel); extern void vac_open_indexes(Relation relation, LOCKMODE lockmode, int *nindexes, Relation **Irel); extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode); @@ -171,12 +186,13 @@ extern void vac_update_datfrozenxid(void); extern void vacuum_delay_point(void); /* in commands/vacuumlazy.c */ -extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, - BufferAccessStrategy bstrategy); +extern void lazy_vacuum_rel(Relation onerel, int options, + VacuumParams *params, BufferAccessStrategy bstrategy); /* in commands/analyze.c */ -extern void analyze_rel(Oid relid, VacuumStmt *vacstmt, - bool in_outer_xact, BufferAccessStrategy bstrategy); +extern void analyze_rel(Oid relid, RangeVar *relation, int options, + List *va_cols, bool in_outer_xact, + BufferAccessStrategy bstrategy); extern bool std_typanalyze(VacAttrStats *stats); extern double anl_random_fract(void); extern double anl_init_selection_state(int n); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index a5753539a3..ec0d0eaa4a 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2608,9 +2608,7 @@ typedef struct ClusterStmt * * Even though these are nominally two statements, it's convenient to use * just one node type for both. Note that at least one of VACOPT_VACUUM - * and VACOPT_ANALYZE must be set in options. VACOPT_FREEZE is an internal - * convenience for the grammar and is not examined at runtime --- the - * freeze_min_age and freeze_table_age fields are what matter. + * and VACOPT_ANALYZE must be set in options. * ---------------------- */ typedef enum VacuumOption @@ -2620,19 +2618,14 @@ typedef enum VacuumOption VACOPT_VERBOSE = 1 << 2, /* print progress info */ VACOPT_FREEZE = 1 << 3, /* FREEZE option */ VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */ - VACOPT_NOWAIT = 1 << 5 /* don't wait to get lock (autovacuum only) */ + VACOPT_NOWAIT = 1 << 5, /* don't wait to get lock (autovacuum only) */ + VACOPT_SKIPTOAST = 1 << 6 /* don't process the TOAST table, if any */ } VacuumOption; typedef struct VacuumStmt { NodeTag type; int options; /* OR of VacuumOption flags */ - int freeze_min_age; /* min freeze age, or -1 to use default */ - int freeze_table_age; /* age at which to scan whole table */ - int multixact_freeze_min_age; /* min multixact freeze age, - * or -1 to use default */ - int multixact_freeze_table_age; /* multixact age at which to - * scan whole table */ RangeVar *relation; /* single table to process, or NULL */ List *va_cols; /* list of column names, or NIL for all */ } VacuumStmt;