Skip to content

Commit 6776142

Browse files
committed
Revise parse tree representation for VACUUM and ANALYZE.
Like commit f41551f, 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
1 parent f41551f commit 6776142

File tree

7 files changed

+116
-86
lines changed

7 files changed

+116
-86
lines changed

src/backend/commands/vacuum.c

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,55 @@ static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params);
8383
* happen in vacuum().
8484
*/
8585
void
86-
ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel)
86+
ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
8787
{
8888
VacuumParams params;
89+
ListCell *lc;
90+
91+
params.options = vacstmt->is_vacuumcmd ? VACOPT_VACUUM : VACOPT_ANALYZE;
92+
93+
/* Parse options list */
94+
foreach(lc, vacstmt->options)
95+
{
96+
DefElem *opt = (DefElem *) lfirst(lc);
97+
98+
/* Parse common options for VACUUM and ANALYZE */
99+
if (strcmp(opt->defname, "verbose") == 0)
100+
params.options |= VACOPT_VERBOSE;
101+
else if (strcmp(opt->defname, "skip_locked") == 0)
102+
params.options |= VACOPT_SKIP_LOCKED;
103+
else if (!vacstmt->is_vacuumcmd)
104+
ereport(ERROR,
105+
(errcode(ERRCODE_SYNTAX_ERROR),
106+
errmsg("unrecognized ANALYZE option \"%s\"", opt->defname),
107+
parser_errposition(pstate, opt->location)));
108+
109+
/* Parse options available on VACUUM */
110+
else if (strcmp(opt->defname, "analyze") == 0)
111+
params.options |= VACOPT_ANALYZE;
112+
else if (strcmp(opt->defname, "freeze") == 0)
113+
params.options |= VACOPT_FREEZE;
114+
else if (strcmp(opt->defname, "full") == 0)
115+
params.options |= VACOPT_FULL;
116+
else if (strcmp(opt->defname, "disable_page_skipping") == 0)
117+
params.options |= VACOPT_DISABLE_PAGE_SKIPPING;
118+
else
119+
ereport(ERROR,
120+
(errcode(ERRCODE_SYNTAX_ERROR),
121+
errmsg("unrecognized VACUUM option \"%s\"", opt->defname),
122+
parser_errposition(pstate, opt->location)));
123+
}
89124

90125
/* sanity checks on options */
91-
Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE));
92-
Assert((vacstmt->options & VACOPT_VACUUM) ||
93-
!(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE)));
94-
Assert(!(vacstmt->options & VACOPT_SKIPTOAST));
126+
Assert(params.options & (VACOPT_VACUUM | VACOPT_ANALYZE));
127+
Assert((params.options & VACOPT_VACUUM) ||
128+
!(params.options & (VACOPT_FULL | VACOPT_FREEZE)));
129+
Assert(!(params.options & VACOPT_SKIPTOAST));
95130

96131
/*
97132
* Make sure VACOPT_ANALYZE is specified if any column lists are present.
98133
*/
99-
if (!(vacstmt->options & VACOPT_ANALYZE))
134+
if (!(params.options & VACOPT_ANALYZE))
100135
{
101136
ListCell *lc;
102137

@@ -111,14 +146,11 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel)
111146
}
112147
}
113148

114-
/* copy options from parse tree */
115-
params.options = vacstmt->options;
116-
117149
/*
118150
* All freeze ages are zero if the FREEZE option is given; otherwise pass
119151
* them as -1 which means to use the default values.
120152
*/
121-
if (vacstmt->options & VACOPT_FREEZE)
153+
if (params.options & VACOPT_FREEZE)
122154
{
123155
params.freeze_min_age = 0;
124156
params.freeze_table_age = 0;

src/backend/parser/gram.y

Lines changed: 42 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
306306
create_extension_opt_item alter_extension_opt_item
307307

308308
%type <ival> opt_lock lock_type cast_context
309-
%type <ival> vacuum_option_list vacuum_option_elem
310-
analyze_option_list analyze_option_elem
309+
%type <str> vac_analyze_option_name
310+
%type <defelt> vac_analyze_option_elem
311+
%type <list> vac_analyze_option_list
311312
%type <boolean> opt_or_replace
312313
opt_grant_grant_option opt_grant_admin_option
313314
opt_nowait opt_if_exists opt_with_data
@@ -10460,85 +10461,62 @@ cluster_index_specification:
1046010461
VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_vacuum_relation_list
1046110462
{
1046210463
VacuumStmt *n = makeNode(VacuumStmt);
10463-
n->options = VACOPT_VACUUM;
10464+
n->options = NIL;
1046410465
if ($2)
10465-
n->options |= VACOPT_FULL;
10466+
n->options = lappend(n->options,
10467+
makeDefElem("full", NULL, @2));
1046610468
if ($3)
10467-
n->options |= VACOPT_FREEZE;
10469+
n->options = lappend(n->options,
10470+
makeDefElem("freeze", NULL, @3));
1046810471
if ($4)
10469-
n->options |= VACOPT_VERBOSE;
10472+
n->options = lappend(n->options,
10473+
makeDefElem("verbose", NULL, @4));
1047010474
if ($5)
10471-
n->options |= VACOPT_ANALYZE;
10475+
n->options = lappend(n->options,
10476+
makeDefElem("analyze", NULL, @5));
1047210477
n->rels = $6;
10478+
n->is_vacuumcmd = true;
1047310479
$$ = (Node *)n;
1047410480
}
10475-
| VACUUM '(' vacuum_option_list ')' opt_vacuum_relation_list
10481+
| VACUUM '(' vac_analyze_option_list ')' opt_vacuum_relation_list
1047610482
{
1047710483
VacuumStmt *n = makeNode(VacuumStmt);
10478-
n->options = VACOPT_VACUUM | $3;
10484+
n->options = $3;
1047910485
n->rels = $5;
10486+
n->is_vacuumcmd = true;
1048010487
$$ = (Node *) n;
1048110488
}
1048210489
;
1048310490

10484-
vacuum_option_list:
10485-
vacuum_option_elem { $$ = $1; }
10486-
| vacuum_option_list ',' vacuum_option_elem { $$ = $1 | $3; }
10487-
;
10488-
10489-
vacuum_option_elem:
10490-
analyze_keyword { $$ = VACOPT_ANALYZE; }
10491-
| VERBOSE { $$ = VACOPT_VERBOSE; }
10492-
| FREEZE { $$ = VACOPT_FREEZE; }
10493-
| FULL { $$ = VACOPT_FULL; }
10494-
| IDENT
10495-
{
10496-
if (strcmp($1, "disable_page_skipping") == 0)
10497-
$$ = VACOPT_DISABLE_PAGE_SKIPPING;
10498-
else if (strcmp($1, "skip_locked") == 0)
10499-
$$ = VACOPT_SKIP_LOCKED;
10500-
else
10501-
ereport(ERROR,
10502-
(errcode(ERRCODE_SYNTAX_ERROR),
10503-
errmsg("unrecognized VACUUM option \"%s\"", $1),
10504-
parser_errposition(@1)));
10505-
}
10506-
;
10507-
1050810491
AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list
1050910492
{
1051010493
VacuumStmt *n = makeNode(VacuumStmt);
10511-
n->options = VACOPT_ANALYZE;
10494+
n->options = NIL;
1051210495
if ($2)
10513-
n->options |= VACOPT_VERBOSE;
10496+
n->options = lappend(n->options,
10497+
makeDefElem("verbose", NULL, @2));
1051410498
n->rels = $3;
10499+
n->is_vacuumcmd = false;
1051510500
$$ = (Node *)n;
1051610501
}
10517-
| analyze_keyword '(' analyze_option_list ')' opt_vacuum_relation_list
10502+
| analyze_keyword '(' vac_analyze_option_list ')' opt_vacuum_relation_list
1051810503
{
1051910504
VacuumStmt *n = makeNode(VacuumStmt);
10520-
n->options = VACOPT_ANALYZE | $3;
10505+
n->options = $3;
1052110506
n->rels = $5;
10507+
n->is_vacuumcmd = false;
1052210508
$$ = (Node *) n;
1052310509
}
1052410510
;
1052510511

10526-
analyze_option_list:
10527-
analyze_option_elem { $$ = $1; }
10528-
| analyze_option_list ',' analyze_option_elem { $$ = $1 | $3; }
10529-
;
10530-
10531-
analyze_option_elem:
10532-
VERBOSE { $$ = VACOPT_VERBOSE; }
10533-
| IDENT
10512+
vac_analyze_option_list:
10513+
vac_analyze_option_elem
1053410514
{
10535-
if (strcmp($1, "skip_locked") == 0)
10536-
$$ = VACOPT_SKIP_LOCKED;
10537-
else
10538-
ereport(ERROR,
10539-
(errcode(ERRCODE_SYNTAX_ERROR),
10540-
errmsg("unrecognized ANALYZE option \"%s\"", $1),
10541-
parser_errposition(@1)));
10515+
$$ = list_make1($1);
10516+
}
10517+
| vac_analyze_option_list ',' vac_analyze_option_elem
10518+
{
10519+
$$ = lappend($1, $3);
1054210520
}
1054310521
;
1054410522

@@ -10547,6 +10525,18 @@ analyze_keyword:
1054710525
| ANALYSE /* British */ {}
1054810526
;
1054910527

10528+
vac_analyze_option_elem:
10529+
vac_analyze_option_name
10530+
{
10531+
$$ = makeDefElem($1, NULL, @1);
10532+
}
10533+
;
10534+
10535+
vac_analyze_option_name:
10536+
NonReservedWord { $$ = $1; }
10537+
| analyze_keyword { $$ = "analyze"; }
10538+
;
10539+
1055010540
opt_analyze:
1055110541
analyze_keyword { $$ = true; }
1055210542
| /*EMPTY*/ { $$ = false; }

src/backend/tcop/utility.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -664,10 +664,10 @@ standard_ProcessUtility(PlannedStmt *pstmt,
664664
VacuumStmt *stmt = (VacuumStmt *) parsetree;
665665

666666
/* we choose to allow this during "read only" transactions */
667-
PreventCommandDuringRecovery((stmt->options & VACOPT_VACUUM) ?
667+
PreventCommandDuringRecovery(stmt->is_vacuumcmd ?
668668
"VACUUM" : "ANALYZE");
669669
/* forbidden in parallel mode due to CommandIsReadOnly */
670-
ExecVacuum(stmt, isTopLevel);
670+
ExecVacuum(pstate, stmt, isTopLevel);
671671
}
672672
break;
673673

@@ -2570,7 +2570,7 @@ CreateCommandTag(Node *parsetree)
25702570
break;
25712571

25722572
case T_VacuumStmt:
2573-
if (((VacuumStmt *) parsetree)->options & VACOPT_VACUUM)
2573+
if (((VacuumStmt *) parsetree)->is_vacuumcmd)
25742574
tag = "VACUUM";
25752575
else
25762576
tag = "ANALYZE";

src/include/commands/vacuum.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,23 @@ typedef struct VacAttrStats
136136
int rowstride;
137137
} VacAttrStats;
138138

139+
typedef enum VacuumOption
140+
{
141+
VACOPT_VACUUM = 1 << 0, /* do VACUUM */
142+
VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */
143+
VACOPT_VERBOSE = 1 << 2, /* print progress info */
144+
VACOPT_FREEZE = 1 << 3, /* FREEZE option */
145+
VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */
146+
VACOPT_SKIP_LOCKED = 1 << 5, /* skip if cannot get lock */
147+
VACOPT_SKIPTOAST = 1 << 6, /* don't process the TOAST table, if any */
148+
VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */
149+
} VacuumOption;
150+
139151
/*
140152
* Parameters customizing behavior of VACUUM and ANALYZE.
153+
*
154+
* Note that at least one of VACOPT_VACUUM and VACOPT_ANALYZE must be set
155+
* in options.
141156
*/
142157
typedef struct VacuumParams
143158
{
@@ -163,7 +178,7 @@ extern int vacuum_multixact_freeze_table_age;
163178

164179

165180
/* in commands/vacuum.c */
166-
extern void ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel);
181+
extern void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel);
167182
extern void vacuum(List *relations, VacuumParams *params,
168183
BufferAccessStrategy bstrategy, bool isTopLevel);
169184
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,

src/include/nodes/parsenodes.h

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3151,21 +3151,16 @@ typedef struct ClusterStmt
31513151
* Vacuum and Analyze Statements
31523152
*
31533153
* Even though these are nominally two statements, it's convenient to use
3154-
* just one node type for both. Note that at least one of VACOPT_VACUUM
3155-
* and VACOPT_ANALYZE must be set in options.
3154+
* just one node type for both.
31563155
* ----------------------
31573156
*/
3158-
typedef enum VacuumOption
3157+
typedef struct VacuumStmt
31593158
{
3160-
VACOPT_VACUUM = 1 << 0, /* do VACUUM */
3161-
VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */
3162-
VACOPT_VERBOSE = 1 << 2, /* print progress info */
3163-
VACOPT_FREEZE = 1 << 3, /* FREEZE option */
3164-
VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */
3165-
VACOPT_SKIP_LOCKED = 1 << 5, /* skip if cannot get lock */
3166-
VACOPT_SKIPTOAST = 1 << 6, /* don't process the TOAST table, if any */
3167-
VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */
3168-
} VacuumOption;
3159+
NodeTag type;
3160+
List *options; /* list of DefElem nodes */
3161+
List *rels; /* list of VacuumRelation, or NIL for all */
3162+
bool is_vacuumcmd; /* true for VACUUM, false for ANALYZE */
3163+
} VacuumStmt;
31693164

31703165
/*
31713166
* Info about a single target table of VACUUM/ANALYZE.
@@ -3182,13 +3177,6 @@ typedef struct VacuumRelation
31823177
List *va_cols; /* list of column names, or NIL for all */
31833178
} VacuumRelation;
31843179

3185-
typedef struct VacuumStmt
3186-
{
3187-
NodeTag type;
3188-
int options; /* OR of VacuumOption flags */
3189-
List *rels; /* list of VacuumRelation, or NIL for all */
3190-
} VacuumStmt;
3191-
31923180
/* ----------------------
31933181
* Explain Statement
31943182
*

src/test/regress/expected/vacuum.out

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,12 @@ ERROR: column "does_not_exist" of relation "vacparted" does not exist
116116
ANALYZE (VERBOSE) does_not_exist;
117117
ERROR: relation "does_not_exist" does not exist
118118
ANALYZE (nonexistent-arg) does_not_exist;
119-
ERROR: unrecognized ANALYZE option "nonexistent"
119+
ERROR: syntax error at or near "-"
120120
LINE 1: ANALYZE (nonexistent-arg) does_not_exist;
121+
^
122+
ANALYZE (nonexistentarg) does_not_exit;
123+
ERROR: unrecognized ANALYZE option "nonexistentarg"
124+
LINE 1: ANALYZE (nonexistentarg) does_not_exit;
121125
^
122126
-- ensure argument order independence, and that SKIP_LOCKED on non-existing
123127
-- relation still errors out.

src/test/regress/sql/vacuum.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ ANALYZE vactst (i), vacparted (does_not_exist);
9292
-- parenthesized syntax for ANALYZE
9393
ANALYZE (VERBOSE) does_not_exist;
9494
ANALYZE (nonexistent-arg) does_not_exist;
95+
ANALYZE (nonexistentarg) does_not_exit;
9596

9697
-- ensure argument order independence, and that SKIP_LOCKED on non-existing
9798
-- relation still errors out.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy