From 07370615c524c629a5c46957420c122567b2e0eb Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Mon, 4 Mar 2019 15:15:13 +0900 Subject: [PATCH v16 1/3] Make vacuum options a Node. Adds new Node VacuumOptions for follow up commit. VacuumOptions is passed down to vacuum path but not to the analyze path. --- src/backend/access/heap/vacuumlazy.c | 14 +++--- src/backend/commands/vacuum.c | 90 ++++++++++++++++++------------------ src/backend/nodes/copyfuncs.c | 15 +++++- src/backend/nodes/equalfuncs.c | 13 +++++- src/backend/parser/gram.y | 58 +++++++++++++++-------- src/backend/postmaster/autovacuum.c | 14 +++--- src/backend/tcop/utility.c | 4 +- src/include/access/heapam.h | 3 +- src/include/commands/vacuum.h | 6 +-- src/include/nodes/nodes.h | 1 + src/include/nodes/parsenodes.h | 16 +++++-- 11 files changed, 144 insertions(+), 90 deletions(-) diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 9416c31..2c33bf6 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -150,7 +150,7 @@ static BufferAccessStrategy vac_strategy; /* non-export function prototypes */ -static void lazy_scan_heap(Relation onerel, int options, +static void lazy_scan_heap(Relation onerel, VacuumOptions *options, LVRelStats *vacrelstats, Relation *Irel, int nindexes, bool aggressive); static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats, BlockNumber nblocks); @@ -186,7 +186,7 @@ static bool heap_page_is_all_visible(Relation rel, Buffer buf, * and locked the relation. */ void -heap_vacuum_rel(Relation onerel, int options, VacuumParams *params, +heap_vacuum_rel(Relation onerel, VacuumOptions *options, VacuumParams *params, BufferAccessStrategy bstrategy) { LVRelStats *vacrelstats; @@ -217,7 +217,7 @@ heap_vacuum_rel(Relation onerel, int options, VacuumParams *params, starttime = GetCurrentTimestamp(); } - if (options & VACOPT_VERBOSE) + if (options->flags & VACOPT_VERBOSE) elevel = INFO; else elevel = DEBUG2; @@ -245,7 +245,7 @@ heap_vacuum_rel(Relation onerel, int options, VacuumParams *params, xidFullScanLimit); aggressive |= MultiXactIdPrecedesOrEquals(onerel->rd_rel->relminmxid, mxactFullScanLimit); - if (options & VACOPT_DISABLE_PAGE_SKIPPING) + if (options->flags & VACOPT_DISABLE_PAGE_SKIPPING) aggressive = true; vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats)); @@ -469,7 +469,7 @@ vacuum_log_cleanup_info(Relation rel, LVRelStats *vacrelstats) * reference them have been killed. */ static void -lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats, +lazy_scan_heap(Relation onerel, VacuumOptions *options, LVRelStats *vacrelstats, Relation *Irel, int nindexes, bool aggressive) { BlockNumber nblocks, @@ -583,7 +583,7 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats, * be replayed on any hot standby, where it can be disruptive. */ next_unskippable_block = 0; - if ((options & VACOPT_DISABLE_PAGE_SKIPPING) == 0) + if ((options->flags & VACOPT_DISABLE_PAGE_SKIPPING) == 0) { while (next_unskippable_block < nblocks) { @@ -638,7 +638,7 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats, { /* Time to advance next_unskippable_block */ next_unskippable_block++; - if ((options & VACOPT_DISABLE_PAGE_SKIPPING) == 0) + if ((options->flags & VACOPT_DISABLE_PAGE_SKIPPING) == 0) { while (next_unskippable_block < nblocks) { diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index e91df21..843f626 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -67,13 +67,13 @@ static BufferAccessStrategy vac_strategy; /* non-export function prototypes */ -static List *expand_vacuum_rel(VacuumRelation *vrel, int options); -static List *get_all_vacuum_rels(int options); +static List *expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options); +static List *get_all_vacuum_rels(VacuumOptions *options); static void vac_truncate_clog(TransactionId frozenXID, MultiXactId minMulti, TransactionId lastSaneFrozenXid, MultiXactId lastSaneMinMulti); -static bool vacuum_rel(Oid relid, RangeVar *relation, int options, +static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumOptions *options, VacuumParams *params); /* @@ -88,15 +88,15 @@ 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_SKIPTOAST)); + Assert(vacstmt->options->flags & (VACOPT_VACUUM | VACOPT_ANALYZE)); + Assert((vacstmt->options->flags & VACOPT_VACUUM) || + !(vacstmt->options->flags & (VACOPT_FULL | VACOPT_FREEZE))); + Assert(!(vacstmt->options->flags & VACOPT_SKIPTOAST)); /* * Make sure VACOPT_ANALYZE is specified if any column lists are present. */ - if (!(vacstmt->options & VACOPT_ANALYZE)) + if (!(vacstmt->options->flags & VACOPT_ANALYZE)) { ListCell *lc; @@ -115,7 +115,7 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel) * 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) + if (vacstmt->options->flags & VACOPT_FREEZE) { params.freeze_min_age = 0; params.freeze_table_age = 0; @@ -143,7 +143,7 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel) /* * Internal entry point for VACUUM and ANALYZE commands. * - * options is a bitmask of VacuumOption flags, indicating what to do. + * options is a VacuumOptions, indicating what to do. * * relations, if not NIL, is a list of VacuumRelation to process; otherwise, * we process all relevant tables in the database. For each VacuumRelation, @@ -162,7 +162,7 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel) * memory context that will not disappear at transaction commit. */ void -vacuum(int options, List *relations, VacuumParams *params, +vacuum(VacuumOptions *options, List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel) { static bool in_vacuum = false; @@ -173,7 +173,7 @@ vacuum(int options, List *relations, VacuumParams *params, Assert(params != NULL); - stmttype = (options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE"; + stmttype = (options->flags & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE"; /* * We cannot run VACUUM inside a user transaction block; if we were inside @@ -183,7 +183,7 @@ vacuum(int options, List *relations, VacuumParams *params, * * ANALYZE (without VACUUM) can run either way. */ - if (options & VACOPT_VACUUM) + if (options->flags & VACOPT_VACUUM) { PreventInTransactionBlock(isTopLevel, stmttype); in_outer_xact = false; @@ -205,8 +205,8 @@ vacuum(int options, List *relations, VacuumParams *params, /* * Sanity check DISABLE_PAGE_SKIPPING option. */ - if ((options & VACOPT_FULL) != 0 && - (options & VACOPT_DISABLE_PAGE_SKIPPING) != 0) + if ((options->flags & VACOPT_FULL) != 0 && + (options->flags & VACOPT_DISABLE_PAGE_SKIPPING) != 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("VACUUM option DISABLE_PAGE_SKIPPING cannot be used with FULL"))); @@ -215,7 +215,7 @@ vacuum(int options, List *relations, VacuumParams *params, * Send info about dead objects to the statistics collector, unless we are * in autovacuum --- autovacuum.c does this for itself. */ - if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) + if ((options->flags & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) pgstat_vacuum_stat(); /* @@ -280,11 +280,11 @@ vacuum(int options, List *relations, VacuumParams *params, * transaction block, and also in an autovacuum worker, use own * transactions so we can release locks sooner. */ - if (options & VACOPT_VACUUM) + if (options->flags & VACOPT_VACUUM) use_own_xacts = true; else { - Assert(options & VACOPT_ANALYZE); + Assert(options->flags & VACOPT_ANALYZE); if (IsAutoVacuumWorkerProcess()) use_own_xacts = true; else if (in_outer_xact) @@ -334,13 +334,13 @@ vacuum(int options, List *relations, VacuumParams *params, { VacuumRelation *vrel = lfirst_node(VacuumRelation, cur); - if (options & VACOPT_VACUUM) + if (options->flags & VACOPT_VACUUM) { if (!vacuum_rel(vrel->oid, vrel->relation, options, params)) continue; } - if (options & VACOPT_ANALYZE) + if (options->flags & VACOPT_ANALYZE) { /* * If using separate xacts, start one for analyze. Otherwise, @@ -353,7 +353,7 @@ vacuum(int options, List *relations, VacuumParams *params, PushActiveSnapshot(GetTransactionSnapshot()); } - analyze_rel(vrel->oid, vrel->relation, options, params, + analyze_rel(vrel->oid, vrel->relation, options->flags, params, vrel->va_cols, in_outer_xact, vac_strategy); if (use_own_xacts) @@ -389,7 +389,7 @@ vacuum(int options, List *relations, VacuumParams *params, StartTransactionCommand(); } - if ((options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) + if ((options->flags & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) { /* * Update pg_database.datfrozenxid, and truncate pg_xact if possible. @@ -415,11 +415,11 @@ vacuum(int options, List *relations, VacuumParams *params, * ANALYZE. */ bool -vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) +vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int flags) { char *relname; - Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0); + Assert((flags & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0); /* * Check permissions. @@ -438,7 +438,7 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) relname = NameStr(reltuple->relname); - if ((options & VACOPT_VACUUM) != 0) + if ((flags & VACOPT_VACUUM) != 0) { if (reltuple->relisshared) ereport(WARNING, @@ -461,7 +461,7 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) return false; } - if ((options & VACOPT_ANALYZE) != 0) + if ((flags & VACOPT_ANALYZE) != 0) { if (reltuple->relisshared) ereport(WARNING, @@ -490,14 +490,14 @@ vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, int options) */ Relation vacuum_open_relation(Oid relid, RangeVar *relation, VacuumParams *params, - int options, LOCKMODE lmode) + int flags, LOCKMODE lmode) { Relation onerel; bool rel_lock = true; int elevel; Assert(params != NULL); - Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0); + Assert((flags & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0); /* * Open the relation and get the appropriate lock on it. @@ -508,7 +508,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, VacuumParams *params, * 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 (!(options & VACOPT_SKIP_LOCKED)) + if (!(flags & VACOPT_SKIP_LOCKED)) onerel = try_relation_open(relid, lmode); else if (ConditionalLockRelationOid(relid, lmode)) onerel = try_relation_open(relid, NoLock); @@ -548,7 +548,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, VacuumParams *params, else return NULL; - if ((options & VACOPT_VACUUM) != 0) + if ((flags & VACOPT_VACUUM) != 0) { if (!rel_lock) ereport(elevel, @@ -569,7 +569,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, VacuumParams *params, return NULL; } - if ((options & VACOPT_ANALYZE) != 0) + if ((flags & VACOPT_ANALYZE) != 0) { if (!rel_lock) ereport(elevel, @@ -602,7 +602,7 @@ vacuum_open_relation(Oid relid, RangeVar *relation, VacuumParams *params, * are made in vac_context. */ static List * -expand_vacuum_rel(VacuumRelation *vrel, int options) +expand_vacuum_rel(VacuumRelation *vrel, VacuumOptions *options) { List *vacrels = NIL; MemoryContext oldcontext; @@ -634,7 +634,7 @@ expand_vacuum_rel(VacuumRelation *vrel, int options) * below, as well as find_all_inheritors's expectation that the caller * holds some lock on the starting relation. */ - rvr_opts = (options & VACOPT_SKIP_LOCKED) ? RVR_SKIP_LOCKED : 0; + rvr_opts = (options->flags & VACOPT_SKIP_LOCKED) ? RVR_SKIP_LOCKED : 0; relid = RangeVarGetRelidExtended(vrel->relation, AccessShareLock, rvr_opts, @@ -646,7 +646,7 @@ expand_vacuum_rel(VacuumRelation *vrel, int options) */ if (!OidIsValid(relid)) { - if (options & VACOPT_VACUUM) + if (options->flags & VACOPT_VACUUM) ereport(WARNING, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("skipping vacuum of \"%s\" --- lock not available", @@ -672,7 +672,7 @@ expand_vacuum_rel(VacuumRelation *vrel, int options) * Make a returnable VacuumRelation for this rel if user is a proper * owner. */ - if (vacuum_is_relation_owner(relid, classForm, options)) + if (vacuum_is_relation_owner(relid, classForm, options->flags)) { oldcontext = MemoryContextSwitchTo(vac_context); vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation, @@ -741,7 +741,7 @@ expand_vacuum_rel(VacuumRelation *vrel, int options) * the current database. The list is built in vac_context. */ static List * -get_all_vacuum_rels(int options) +get_all_vacuum_rels(VacuumOptions *options) { List *vacrels = NIL; Relation pgclass; @@ -759,7 +759,7 @@ get_all_vacuum_rels(int options) Oid relid = classForm->oid; /* check permissions of relation */ - if (!vacuum_is_relation_owner(relid, classForm, options)) + if (!vacuum_is_relation_owner(relid, classForm, options->flags)) continue; /* @@ -1520,7 +1520,7 @@ vac_truncate_clog(TransactionId frozenXID, * At entry and exit, we are not inside a transaction. */ static bool -vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) +vacuum_rel(Oid relid, RangeVar *relation, VacuumOptions *options, VacuumParams *params) { LOCKMODE lmode; Relation onerel; @@ -1541,7 +1541,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) */ PushActiveSnapshot(GetTransactionSnapshot()); - if (!(options & VACOPT_FULL)) + if (!(options->flags & VACOPT_FULL)) { /* * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets @@ -1581,10 +1581,10 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either * way, we can be sure that no other backend is vacuuming the same table. */ - lmode = (options & VACOPT_FULL) ? AccessExclusiveLock : ShareUpdateExclusiveLock; + lmode = (options->flags & VACOPT_FULL) ? AccessExclusiveLock : ShareUpdateExclusiveLock; /* open the relation and get the appropriate lock on it */ - onerel = vacuum_open_relation(relid, relation, params, options, lmode); + onerel = vacuum_open_relation(relid, relation, params, options->flags, lmode); /* leave if relation could not be opened or locked */ if (!onerel) @@ -1604,7 +1604,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) */ if (!vacuum_is_relation_owner(RelationGetRelid(onerel), onerel->rd_rel, - options & VACOPT_VACUUM)) + options->flags & VACOPT_VACUUM)) { relation_close(onerel, lmode); PopActiveSnapshot(); @@ -1676,7 +1676,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) * 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 (!(options & VACOPT_SKIPTOAST) && !(options & VACOPT_FULL)) + if (!(options->flags & VACOPT_SKIPTOAST) && !(options->flags & VACOPT_FULL)) toast_relid = onerel->rd_rel->reltoastrelid; else toast_relid = InvalidOid; @@ -1695,7 +1695,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) /* * Do the actual work --- either FULL or "lazy" vacuum */ - if (options & VACOPT_FULL) + if (options->flags & VACOPT_FULL) { int cluster_options = 0; @@ -1703,7 +1703,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) relation_close(onerel, NoLock); onerel = NULL; - if ((options & VACOPT_VERBOSE) != 0) + if ((options->flags & VACOPT_VERBOSE) != 0) cluster_options |= CLUOPT_VERBOSE; /* VACUUM FULL is now a variant of CLUSTER; see cluster.c */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index e15724b..7f937c9 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3843,12 +3843,22 @@ _copyDropdbStmt(const DropdbStmt *from) return newnode; } +static VacuumOptions * +_copyVacuumOptions(const VacuumOptions *from) +{ + VacuumOptions *newnode = makeNode(VacuumOptions); + + COPY_SCALAR_FIELD(flags); + + return newnode; +} + static VacuumStmt * _copyVacuumStmt(const VacuumStmt *from) { VacuumStmt *newnode = makeNode(VacuumStmt); - COPY_SCALAR_FIELD(options); + COPY_NODE_FIELD(options); COPY_NODE_FIELD(rels); return newnode; @@ -5321,6 +5331,9 @@ copyObjectImpl(const void *from) case T_DropdbStmt: retval = _copyDropdbStmt(from); break; + case T_VacuumOptions: + retval = _copyVacuumOptions(from); + break; case T_VacuumStmt: retval = _copyVacuumStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 31499eb..3dbbff4 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1666,9 +1666,17 @@ _equalDropdbStmt(const DropdbStmt *a, const DropdbStmt *b) } static bool +_equalVacuumOptions(const VacuumOptions *a, const VacuumOptions *b) +{ + COMPARE_SCALAR_FIELD(flags); + + return true; +} + +static bool _equalVacuumStmt(const VacuumStmt *a, const VacuumStmt *b) { - COMPARE_SCALAR_FIELD(options); + COMPARE_NODE_FIELD(options); COMPARE_NODE_FIELD(rels); return true; @@ -3386,6 +3394,9 @@ equal(const void *a, const void *b) case T_DropdbStmt: retval = _equalDropdbStmt(a, b); break; + case T_VacuumOptions: + retval = _equalVacuumOptions(a, b); + break; case T_VacuumStmt: retval = _equalVacuumStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0279013..e7601da 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -187,6 +187,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType, bool *deferrable, bool *initdeferred, bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); +static VacuumOptions *makeVacOpt(VacuumFlag flags); %} @@ -237,6 +238,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); struct ImportQual *importqual; InsertStmt *istmt; VariableSetStmt *vsetstmt; + VacuumOptions *vacopt; PartitionElem *partelem; PartitionSpec *partspec; PartitionBoundSpec *partboundspec; @@ -305,8 +307,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); create_extension_opt_item alter_extension_opt_item %type opt_lock lock_type cast_context -%type vacuum_option_list vacuum_option_elem - analyze_option_list analyze_option_elem +%type vacuum_option_list vacuum_option_elem +%type analyze_option_list analyze_option_elem %type opt_or_replace opt_grant_grant_option opt_grant_admin_option opt_nowait opt_if_exists opt_with_data @@ -10436,22 +10438,24 @@ cluster_index_specification: VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_vacuum_relation_list { VacuumStmt *n = makeNode(VacuumStmt); - n->options = VACOPT_VACUUM; + VacuumOptions *opt = makeVacOpt(VACOPT_VACUUM); if ($2) - n->options |= VACOPT_FULL; + opt->flags |= VACOPT_FULL; if ($3) - n->options |= VACOPT_FREEZE; + opt->flags |= VACOPT_FREEZE; if ($4) - n->options |= VACOPT_VERBOSE; + opt->flags |= VACOPT_VERBOSE; if ($5) - n->options |= VACOPT_ANALYZE; + opt->flags |= VACOPT_ANALYZE; + n->options = opt; n->rels = $6; $$ = (Node *)n; } | VACUUM '(' vacuum_option_list ')' opt_vacuum_relation_list { VacuumStmt *n = makeNode(VacuumStmt); - n->options = VACOPT_VACUUM | $3; + n->options = $3; + n->options->flags |= VACOPT_VACUUM; n->rels = $5; $$ = (Node *) n; } @@ -10459,20 +10463,25 @@ VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_vacuum_relati vacuum_option_list: vacuum_option_elem { $$ = $1; } - | vacuum_option_list ',' vacuum_option_elem { $$ = $1 | $3; } + | vacuum_option_list ',' vacuum_option_elem + { + $1->flags |= $3->flags; + pfree($3); + $$ = $1; + } ; vacuum_option_elem: - analyze_keyword { $$ = VACOPT_ANALYZE; } - | VERBOSE { $$ = VACOPT_VERBOSE; } - | FREEZE { $$ = VACOPT_FREEZE; } - | FULL { $$ = VACOPT_FULL; } + analyze_keyword { $$ = makeVacOpt(VACOPT_ANALYZE); } + | VERBOSE { $$ = makeVacOpt(VACOPT_VERBOSE); } + | FREEZE { $$ = makeVacOpt(VACOPT_FREEZE); } + | FULL { $$ = makeVacOpt(VACOPT_FULL); } | IDENT { if (strcmp($1, "disable_page_skipping") == 0) - $$ = VACOPT_DISABLE_PAGE_SKIPPING; + $$ = makeVacOpt(VACOPT_DISABLE_PAGE_SKIPPING); else if (strcmp($1, "skip_locked") == 0) - $$ = VACOPT_SKIP_LOCKED; + $$ = makeVacOpt(VACOPT_SKIP_LOCKED); else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -10484,16 +10493,17 @@ vacuum_option_elem: AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list { VacuumStmt *n = makeNode(VacuumStmt); - n->options = VACOPT_ANALYZE; + VacuumOptions *opt = makeVacOpt(VACOPT_ANALYZE); if ($2) - n->options |= VACOPT_VERBOSE; + opt->flags |= VACOPT_VERBOSE; + n->options = opt; n->rels = $3; $$ = (Node *)n; } | analyze_keyword '(' analyze_option_list ')' opt_vacuum_relation_list { VacuumStmt *n = makeNode(VacuumStmt); - n->options = VACOPT_ANALYZE | $3; + n->options = makeVacOpt(VACOPT_ANALYZE | $3); n->rels = $5; $$ = (Node *) n; } @@ -16018,6 +16028,18 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, } /* + * Create a VacuumOptions with the given flags. + */ +static VacuumOptions * +makeVacOpt(const VacuumFlag flags) +{ + VacuumOptions *opt = makeNode(VacuumOptions); + + opt->flags = flags; + return opt; +} + +/* * Merge the input and output parameters of a table function. */ static List * diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 347f91e..525a33b 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -187,8 +187,8 @@ typedef struct av_relation typedef struct autovac_table { Oid at_relid; - int at_vacoptions; /* bitmask of VacuumOption */ - VacuumParams at_params; + VacuumOptions at_vacoptions; + VacuumParams at_params; int at_vacuum_cost_delay; int at_vacuum_cost_limit; bool at_dobalance; @@ -2481,7 +2481,7 @@ do_autovacuum(void) * next table in our list. */ HOLD_INTERRUPTS(); - if (tab->at_vacoptions & VACOPT_VACUUM) + if (tab->at_vacoptions.flags & VACOPT_VACUUM) errcontext("automatic vacuum of table \"%s.%s.%s\"", tab->at_datname, tab->at_nspname, tab->at_relname); else @@ -2882,7 +2882,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, tab = palloc(sizeof(autovac_table)); tab->at_relid = relid; tab->at_sharedrel = classForm->relisshared; - tab->at_vacoptions = VACOPT_SKIPTOAST | + tab->at_vacoptions.flags = VACOPT_SKIPTOAST | (dovacuum ? VACOPT_VACUUM : 0) | (doanalyze ? VACOPT_ANALYZE : 0) | (!wraparound ? VACOPT_SKIP_LOCKED : 0); @@ -3109,7 +3109,7 @@ autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy) rel = makeVacuumRelation(rangevar, tab->at_relid, NIL); rel_list = list_make1(rel); - vacuum(tab->at_vacoptions, rel_list, &tab->at_params, bstrategy, true); + vacuum(&tab->at_vacoptions, rel_list, &tab->at_params, bstrategy, true); } /* @@ -3131,10 +3131,10 @@ autovac_report_activity(autovac_table *tab) int len; /* Report the command and possible options */ - if (tab->at_vacoptions & VACOPT_VACUUM) + if (tab->at_vacoptions.flags & VACOPT_VACUUM) snprintf(activity, MAX_AUTOVAC_ACTIV_LEN, "autovacuum: VACUUM%s", - tab->at_vacoptions & VACOPT_ANALYZE ? " ANALYZE" : ""); + tab->at_vacoptions.flags & VACOPT_ANALYZE ? " ANALYZE" : ""); else snprintf(activity, MAX_AUTOVAC_ACTIV_LEN, "autovacuum: ANALYZE"); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 6ec795f..a735ff9 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -664,7 +664,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, VacuumStmt *stmt = (VacuumStmt *) parsetree; /* we choose to allow this during "read only" transactions */ - PreventCommandDuringRecovery((stmt->options & VACOPT_VACUUM) ? + PreventCommandDuringRecovery((stmt->options->flags & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE"); /* forbidden in parallel mode due to CommandIsReadOnly */ ExecVacuum(stmt, isTopLevel); @@ -2570,7 +2570,7 @@ CreateCommandTag(Node *parsetree) break; case T_VacuumStmt: - if (((VacuumStmt *) parsetree)->options & VACOPT_VACUUM) + if (((VacuumStmt *) parsetree)->options->flags & VACOPT_VACUUM) tag = "VACUUM"; else tag = "ANALYZE"; diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index ab08791..1c8525f 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -18,6 +18,7 @@ #include "access/sdir.h" #include "access/skey.h" #include "access/table.h" /* for backward compatibility */ +#include "nodes/parsenodes.h" #include "nodes/lockoptions.h" #include "nodes/primnodes.h" #include "storage/bufpage.h" @@ -185,7 +186,7 @@ extern Size SyncScanShmemSize(void); /* in heap/vacuumlazy.c */ struct VacuumParams; -extern void heap_vacuum_rel(Relation onerel, int options, +extern void heap_vacuum_rel(Relation onerel, VacuumOptions *options, struct VacuumParams *params, BufferAccessStrategy bstrategy); /* in heap/heapam_visibility.c */ diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 0a051ec..cfc6771 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -163,7 +163,7 @@ extern int vacuum_multixact_freeze_table_age; /* in commands/vacuum.c */ extern void ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel); -extern void vacuum(int options, List *relations, VacuumParams *params, +extern void vacuum(VacuumOptions *options, List *relations, VacuumParams *params, BufferAccessStrategy bstrategy, bool isTopLevel); extern void vac_open_indexes(Relation relation, LOCKMODE lockmode, int *nindexes, Relation **Irel); @@ -192,9 +192,9 @@ extern void vacuum_set_xid_limits(Relation rel, extern void vac_update_datfrozenxid(void); extern void vacuum_delay_point(void); extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, - int options); + int flags); extern Relation vacuum_open_relation(Oid relid, RangeVar *relation, - VacuumParams *params, int options, LOCKMODE lmode); + VacuumParams *params, int flags, LOCKMODE lmode); /* in commands/analyze.c */ extern void analyze_rel(Oid relid, RangeVar *relation, int options, diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index f938925..3bbafcd 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -476,6 +476,7 @@ typedef enum NodeTag T_PartitionRangeDatum, T_PartitionCmd, T_VacuumRelation, + T_VacuumOptions, /* * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index a7e859d..278e5d1 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3154,7 +3154,7 @@ typedef struct ClusterStmt * and VACOPT_ANALYZE must be set in options. * ---------------------- */ -typedef enum VacuumOption +typedef enum VacuumFlag { VACOPT_VACUUM = 1 << 0, /* do VACUUM */ VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */ @@ -3164,7 +3164,13 @@ typedef enum VacuumOption VACOPT_SKIP_LOCKED = 1 << 5, /* skip if cannot get lock */ VACOPT_SKIPTOAST = 1 << 6, /* don't process the TOAST table, if any */ VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */ -} VacuumOption; +} VacuumFlag; + +typedef struct VacuumOptions +{ + NodeTag type; + int flags; /* OR of VacuumFlag */ +} VacuumOptions; /* * Info about a single target table of VACUUM/ANALYZE. @@ -3183,9 +3189,9 @@ typedef struct VacuumRelation typedef struct VacuumStmt { - NodeTag type; - int options; /* OR of VacuumOption flags */ - List *rels; /* list of VacuumRelation, or NIL for all */ + NodeTag type; + VacuumOptions *options; + List *rels; /* list of VacuumRelation, or NIL for all */ } VacuumStmt; /* ---------------------- -- 2.10.5