Commit 6776142a authored by Robert Haas's avatar Robert Haas

Revise parse tree representation for VACUUM and ANALYZE.

Like commit f41551f6, this aims
to make it easier to add non-Boolean options to VACUUM (or, in
this case, to ANALYZE).  Instead of building up a bitmap of
options directly in the parser, build up a list of DefElem
objects and let ExecVacuum() sort it out; right now, we make
no use of the fact that a DefElem can carry an associated value,
but it will be easy to make that change in the future.

Masahiko Sawada

Discussion: http://postgr.es/m/CAD21AoATE4sn0jFFH3NcfUZXkU2BMbjBWB_kDj-XWYA-LXDcQA@mail.gmail.com
parent f41551f6
...@@ -83,20 +83,55 @@ static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params); ...@@ -83,20 +83,55 @@ static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params);
* happen in vacuum(). * happen in vacuum().
*/ */
void void
ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel) ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
{ {
VacuumParams params; VacuumParams params;
ListCell *lc;
params.options = vacstmt->is_vacuumcmd ? VACOPT_VACUUM : VACOPT_ANALYZE;
/* Parse options list */
foreach(lc, vacstmt->options)
{
DefElem *opt = (DefElem *) lfirst(lc);
/* Parse common options for VACUUM and ANALYZE */
if (strcmp(opt->defname, "verbose") == 0)
params.options |= VACOPT_VERBOSE;
else if (strcmp(opt->defname, "skip_locked") == 0)
params.options |= VACOPT_SKIP_LOCKED;
else if (!vacstmt->is_vacuumcmd)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unrecognized ANALYZE option \"%s\"", opt->defname),
parser_errposition(pstate, opt->location)));
/* Parse options available on VACUUM */
else if (strcmp(opt->defname, "analyze") == 0)
params.options |= VACOPT_ANALYZE;
else if (strcmp(opt->defname, "freeze") == 0)
params.options |= VACOPT_FREEZE;
else if (strcmp(opt->defname, "full") == 0)
params.options |= VACOPT_FULL;
else if (strcmp(opt->defname, "disable_page_skipping") == 0)
params.options |= VACOPT_DISABLE_PAGE_SKIPPING;
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unrecognized VACUUM option \"%s\"", opt->defname),
parser_errposition(pstate, opt->location)));
}
/* sanity checks on options */ /* sanity checks on options */
Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE)); Assert(params.options & (VACOPT_VACUUM | VACOPT_ANALYZE));
Assert((vacstmt->options & VACOPT_VACUUM) || Assert((params.options & VACOPT_VACUUM) ||
!(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE))); !(params.options & (VACOPT_FULL | VACOPT_FREEZE)));
Assert(!(vacstmt->options & VACOPT_SKIPTOAST)); Assert(!(params.options & VACOPT_SKIPTOAST));
/* /*
* Make sure VACOPT_ANALYZE is specified if any column lists are present. * Make sure VACOPT_ANALYZE is specified if any column lists are present.
*/ */
if (!(vacstmt->options & VACOPT_ANALYZE)) if (!(params.options & VACOPT_ANALYZE))
{ {
ListCell *lc; ListCell *lc;
...@@ -111,14 +146,11 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel) ...@@ -111,14 +146,11 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel)
} }
} }
/* copy options from parse tree */
params.options = vacstmt->options;
/* /*
* All freeze ages are zero if the FREEZE option is given; otherwise pass * All freeze ages are zero if the FREEZE option is given; otherwise pass
* them as -1 which means to use the default values. * them as -1 which means to use the default values.
*/ */
if (vacstmt->options & VACOPT_FREEZE) if (params.options & VACOPT_FREEZE)
{ {
params.freeze_min_age = 0; params.freeze_min_age = 0;
params.freeze_table_age = 0; params.freeze_table_age = 0;
......
...@@ -306,8 +306,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ...@@ -306,8 +306,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
create_extension_opt_item alter_extension_opt_item create_extension_opt_item alter_extension_opt_item
%type <ival> opt_lock lock_type cast_context %type <ival> opt_lock lock_type cast_context
%type <ival> vacuum_option_list vacuum_option_elem %type <str> vac_analyze_option_name
analyze_option_list analyze_option_elem %type <defelt> vac_analyze_option_elem
%type <list> vac_analyze_option_list
%type <boolean> opt_or_replace %type <boolean> opt_or_replace
opt_grant_grant_option opt_grant_admin_option opt_grant_grant_option opt_grant_admin_option
opt_nowait opt_if_exists opt_with_data opt_nowait opt_if_exists opt_with_data
...@@ -10460,85 +10461,62 @@ cluster_index_specification: ...@@ -10460,85 +10461,62 @@ cluster_index_specification:
VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_vacuum_relation_list VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_vacuum_relation_list
{ {
VacuumStmt *n = makeNode(VacuumStmt); VacuumStmt *n = makeNode(VacuumStmt);
n->options = VACOPT_VACUUM; n->options = NIL;
if ($2) if ($2)
n->options |= VACOPT_FULL; n->options = lappend(n->options,
makeDefElem("full", NULL, @2));
if ($3) if ($3)
n->options |= VACOPT_FREEZE; n->options = lappend(n->options,
makeDefElem("freeze", NULL, @3));
if ($4) if ($4)
n->options |= VACOPT_VERBOSE; n->options = lappend(n->options,
makeDefElem("verbose", NULL, @4));
if ($5) if ($5)
n->options |= VACOPT_ANALYZE; n->options = lappend(n->options,
makeDefElem("analyze", NULL, @5));
n->rels = $6; n->rels = $6;
n->is_vacuumcmd = true;
$$ = (Node *)n; $$ = (Node *)n;
} }
| VACUUM '(' vacuum_option_list ')' opt_vacuum_relation_list | VACUUM '(' vac_analyze_option_list ')' opt_vacuum_relation_list
{ {
VacuumStmt *n = makeNode(VacuumStmt); VacuumStmt *n = makeNode(VacuumStmt);
n->options = VACOPT_VACUUM | $3; n->options = $3;
n->rels = $5; n->rels = $5;
n->is_vacuumcmd = true;
$$ = (Node *) n; $$ = (Node *) n;
} }
; ;
vacuum_option_list:
vacuum_option_elem { $$ = $1; }
| vacuum_option_list ',' vacuum_option_elem { $$ = $1 | $3; }
;
vacuum_option_elem:
analyze_keyword { $$ = VACOPT_ANALYZE; }
| VERBOSE { $$ = VACOPT_VERBOSE; }
| FREEZE { $$ = VACOPT_FREEZE; }
| FULL { $$ = VACOPT_FULL; }
| IDENT
{
if (strcmp($1, "disable_page_skipping") == 0)
$$ = VACOPT_DISABLE_PAGE_SKIPPING;
else if (strcmp($1, "skip_locked") == 0)
$$ = VACOPT_SKIP_LOCKED;
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unrecognized VACUUM option \"%s\"", $1),
parser_errposition(@1)));
}
;
AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list
{ {
VacuumStmt *n = makeNode(VacuumStmt); VacuumStmt *n = makeNode(VacuumStmt);
n->options = VACOPT_ANALYZE; n->options = NIL;
if ($2) if ($2)
n->options |= VACOPT_VERBOSE; n->options = lappend(n->options,
makeDefElem("verbose", NULL, @2));
n->rels = $3; n->rels = $3;
n->is_vacuumcmd = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| analyze_keyword '(' analyze_option_list ')' opt_vacuum_relation_list | analyze_keyword '(' vac_analyze_option_list ')' opt_vacuum_relation_list
{ {
VacuumStmt *n = makeNode(VacuumStmt); VacuumStmt *n = makeNode(VacuumStmt);
n->options = VACOPT_ANALYZE | $3; n->options = $3;
n->rels = $5; n->rels = $5;
n->is_vacuumcmd = false;
$$ = (Node *) n; $$ = (Node *) n;
} }
; ;
analyze_option_list: vac_analyze_option_list:
analyze_option_elem { $$ = $1; } vac_analyze_option_elem
| analyze_option_list ',' analyze_option_elem { $$ = $1 | $3; }
;
analyze_option_elem:
VERBOSE { $$ = VACOPT_VERBOSE; }
| IDENT
{ {
if (strcmp($1, "skip_locked") == 0) $$ = list_make1($1);
$$ = VACOPT_SKIP_LOCKED; }
else | vac_analyze_option_list ',' vac_analyze_option_elem
ereport(ERROR, {
(errcode(ERRCODE_SYNTAX_ERROR), $$ = lappend($1, $3);
errmsg("unrecognized ANALYZE option \"%s\"", $1),
parser_errposition(@1)));
} }
; ;
...@@ -10547,6 +10525,18 @@ analyze_keyword: ...@@ -10547,6 +10525,18 @@ analyze_keyword:
| ANALYSE /* British */ {} | ANALYSE /* British */ {}
; ;
vac_analyze_option_elem:
vac_analyze_option_name
{
$$ = makeDefElem($1, NULL, @1);
}
;
vac_analyze_option_name:
NonReservedWord { $$ = $1; }
| analyze_keyword { $$ = "analyze"; }
;
opt_analyze: opt_analyze:
analyze_keyword { $$ = true; } analyze_keyword { $$ = true; }
| /*EMPTY*/ { $$ = false; } | /*EMPTY*/ { $$ = false; }
......
...@@ -664,10 +664,10 @@ standard_ProcessUtility(PlannedStmt *pstmt, ...@@ -664,10 +664,10 @@ standard_ProcessUtility(PlannedStmt *pstmt,
VacuumStmt *stmt = (VacuumStmt *) parsetree; VacuumStmt *stmt = (VacuumStmt *) parsetree;
/* we choose to allow this during "read only" transactions */ /* we choose to allow this during "read only" transactions */
PreventCommandDuringRecovery((stmt->options & VACOPT_VACUUM) ? PreventCommandDuringRecovery(stmt->is_vacuumcmd ?
"VACUUM" : "ANALYZE"); "VACUUM" : "ANALYZE");
/* forbidden in parallel mode due to CommandIsReadOnly */ /* forbidden in parallel mode due to CommandIsReadOnly */
ExecVacuum(stmt, isTopLevel); ExecVacuum(pstate, stmt, isTopLevel);
} }
break; break;
...@@ -2570,7 +2570,7 @@ CreateCommandTag(Node *parsetree) ...@@ -2570,7 +2570,7 @@ CreateCommandTag(Node *parsetree)
break; break;
case T_VacuumStmt: case T_VacuumStmt:
if (((VacuumStmt *) parsetree)->options & VACOPT_VACUUM) if (((VacuumStmt *) parsetree)->is_vacuumcmd)
tag = "VACUUM"; tag = "VACUUM";
else else
tag = "ANALYZE"; tag = "ANALYZE";
......
...@@ -136,8 +136,23 @@ typedef struct VacAttrStats ...@@ -136,8 +136,23 @@ typedef struct VacAttrStats
int rowstride; int rowstride;
} VacAttrStats; } VacAttrStats;
typedef enum VacuumOption
{
VACOPT_VACUUM = 1 << 0, /* do VACUUM */
VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */
VACOPT_VERBOSE = 1 << 2, /* print progress info */
VACOPT_FREEZE = 1 << 3, /* FREEZE option */
VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */
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;
/* /*
* Parameters customizing behavior of VACUUM and ANALYZE. * Parameters customizing behavior of VACUUM and ANALYZE.
*
* Note that at least one of VACOPT_VACUUM and VACOPT_ANALYZE must be set
* in options.
*/ */
typedef struct VacuumParams typedef struct VacuumParams
{ {
...@@ -163,7 +178,7 @@ extern int vacuum_multixact_freeze_table_age; ...@@ -163,7 +178,7 @@ extern int vacuum_multixact_freeze_table_age;
/* in commands/vacuum.c */ /* in commands/vacuum.c */
extern void ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel); extern void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel);
extern void vacuum(List *relations, VacuumParams *params, extern void vacuum(List *relations, VacuumParams *params,
BufferAccessStrategy bstrategy, bool isTopLevel); BufferAccessStrategy bstrategy, bool isTopLevel);
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode, extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
......
...@@ -3151,21 +3151,16 @@ typedef struct ClusterStmt ...@@ -3151,21 +3151,16 @@ typedef struct ClusterStmt
* Vacuum and Analyze Statements * Vacuum and Analyze Statements
* *
* Even though these are nominally two statements, it's convenient to use * 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 * just one node type for both.
* and VACOPT_ANALYZE must be set in options.
* ---------------------- * ----------------------
*/ */
typedef enum VacuumOption typedef struct VacuumStmt
{ {
VACOPT_VACUUM = 1 << 0, /* do VACUUM */ NodeTag type;
VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */ List *options; /* list of DefElem nodes */
VACOPT_VERBOSE = 1 << 2, /* print progress info */ List *rels; /* list of VacuumRelation, or NIL for all */
VACOPT_FREEZE = 1 << 3, /* FREEZE option */ bool is_vacuumcmd; /* true for VACUUM, false for ANALYZE */
VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */ } VacuumStmt;
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;
/* /*
* Info about a single target table of VACUUM/ANALYZE. * Info about a single target table of VACUUM/ANALYZE.
...@@ -3182,13 +3177,6 @@ typedef struct VacuumRelation ...@@ -3182,13 +3177,6 @@ typedef struct VacuumRelation
List *va_cols; /* list of column names, or NIL for all */ List *va_cols; /* list of column names, or NIL for all */
} VacuumRelation; } VacuumRelation;
typedef struct VacuumStmt
{
NodeTag type;
int options; /* OR of VacuumOption flags */
List *rels; /* list of VacuumRelation, or NIL for all */
} VacuumStmt;
/* ---------------------- /* ----------------------
* Explain Statement * Explain Statement
* *
......
...@@ -116,9 +116,13 @@ ERROR: column "does_not_exist" of relation "vacparted" does not exist ...@@ -116,9 +116,13 @@ ERROR: column "does_not_exist" of relation "vacparted" does not exist
ANALYZE (VERBOSE) does_not_exist; ANALYZE (VERBOSE) does_not_exist;
ERROR: relation "does_not_exist" does not exist ERROR: relation "does_not_exist" does not exist
ANALYZE (nonexistent-arg) does_not_exist; ANALYZE (nonexistent-arg) does_not_exist;
ERROR: unrecognized ANALYZE option "nonexistent" ERROR: syntax error at or near "-"
LINE 1: ANALYZE (nonexistent-arg) does_not_exist; LINE 1: ANALYZE (nonexistent-arg) does_not_exist;
^ ^
ANALYZE (nonexistentarg) does_not_exit;
ERROR: unrecognized ANALYZE option "nonexistentarg"
LINE 1: ANALYZE (nonexistentarg) does_not_exit;
^
-- ensure argument order independence, and that SKIP_LOCKED on non-existing -- ensure argument order independence, and that SKIP_LOCKED on non-existing
-- relation still errors out. -- relation still errors out.
ANALYZE (SKIP_LOCKED, VERBOSE) does_not_exist; ANALYZE (SKIP_LOCKED, VERBOSE) does_not_exist;
......
...@@ -92,6 +92,7 @@ ANALYZE vactst (i), vacparted (does_not_exist); ...@@ -92,6 +92,7 @@ ANALYZE vactst (i), vacparted (does_not_exist);
-- parenthesized syntax for ANALYZE -- parenthesized syntax for ANALYZE
ANALYZE (VERBOSE) does_not_exist; ANALYZE (VERBOSE) does_not_exist;
ANALYZE (nonexistent-arg) does_not_exist; ANALYZE (nonexistent-arg) does_not_exist;
ANALYZE (nonexistentarg) does_not_exit;
-- ensure argument order independence, and that SKIP_LOCKED on non-existing -- ensure argument order independence, and that SKIP_LOCKED on non-existing
-- relation still errors out. -- relation still errors out.
......
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