-ANALYZE [ VERBOSE ] [ table_name [ ( column_name [, ...] ) ] ]
+ANALYZE [ VERBOSE ] [ table_and_columns [, ...] ]
+
+
where table_and_columns is:
+
+ table_name [ ( column_name [, ...] ) ]
- With no parameter, ANALYZE examines every table in the
- current database. With a parameter, ANALYZE examines
- only that table. It is further possible to give a list of column names,
+ Without a table_and_columns
+ list, ANALYZE processes every table and materialized view
+ in the current database that the current user has permission to analyze.
+ With a list, ANALYZE processes only those table(s).
+ It is further possible to give a list of column names for a table,
in which case only the statistics for those columns are collected.
-VACUUM [ ( { FULL | FREEZE | VERBOSE | ANALYZE | DISABLE_PAGE_SKIPPING } [, ...] ) ] [ table_name [ (column_name [, ...] ) ] ]
-VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ table_name ]
-VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ table_name [ (column_name [, ...] ) ] ]
+VACUUM [ ( option [, ...] ) ] [ table_and_columns [, ...] ]
+VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ table_and_columns [, ...] ]
+
+
where option can be one of:
+
+ FULL
+ FREEZE
+ VERBOSE
+ ANALYZE
+ DISABLE_PAGE_SKIPPING
+
+
and table_and_columns is:
+
+ table_name [ ( column_name [, ...] ) ]
- With no parameter, VACUUM processes every table in the
- current database that the current user has permission to vacuum.
- With a parameter, VACUUM processes only that table.
+ Without a table_and_columns
+ list, VACUUM processes every table and materialized view
+ in the current database that the current user has permission to vacuum.
+ With a list, VACUUM processes only those table(s).
except when performing an aggressive vacuum, some pages may be skipped
in order to avoid waiting for other sessions to finish using them.
This option disables all page-skipping behavior, and is intended to
- be used only the contents of the visibility map are thought to
- be suspect, which should happen only if there is a hardware or software
+ be used only when the contents of the visibility map are
+ suspect, which should happen only if there is a hardware or software
issue causing database corruption.
table_name
- The name (optionally schema-qualified) of a specific table to
- vacuum. If omitted, all regular tables and materialized views in the
- current database are vacuumed. If the specified table is a partitioned
+ The name (optionally schema-qualified) of a specific table or
+ materialized view to vacuum. If the specified table is a partitioned
table, all of its leaf partitions are vacuumed.
The name of a specific column to analyze. Defaults to all columns.
- If a column list is specified, ANALYZE> is implied.
+ If a column list is specified, ANALYZE> must also be
+ specified.
#include "commands/cluster.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
+#include "nodes/makefuncs.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/bufmgr.h"
/* non-export function prototypes */
-static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
+static List *expand_vacuum_rel(VacuumRelation *vrel);
+static List *get_all_vacuum_rels(void);
static void vac_truncate_clog(TransactionId frozenXID,
MultiXactId minMulti,
TransactionId lastSaneFrozenXid,
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));
+ /*
+ * Make sure VACOPT_ANALYZE is specified if any column lists are present.
+ */
+ if (!(vacstmt->options & VACOPT_ANALYZE))
+ {
+ ListCell *lc;
+
+ foreach(lc, vacstmt->rels)
+ {
+ VacuumRelation *vrel = lfirst_node(VacuumRelation, lc);
+
+ if (vrel->va_cols != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("ANALYZE option must be specified when a column list is provided")));
+ }
+ }
+
/*
* All freeze ages are zero if the FREEZE option is given; otherwise pass
* them as -1 which means to use the default values.
params.log_min_duration = -1;
/* Now go through the common routine */
- vacuum(vacstmt->options, vacstmt->relation, InvalidOid, ¶ms,
- vacstmt->va_cols, NULL, isTopLevel);
+ vacuum(vacstmt->options, vacstmt->rels, ¶ms, NULL, isTopLevel);
}
/*
- * Primary entry point for VACUUM and ANALYZE commands.
+ * Internal entry point for VACUUM and ANALYZE commands.
*
* options is a bitmask of VacuumOption flags, indicating what to do.
*
- * relid, if not InvalidOid, indicates the relation to process; otherwise,
- * if a RangeVar is supplied, that's what to process; otherwise, we process
- * all relevant tables in the database. (If both relid and a RangeVar are
- * supplied, the relid is what is processed, but we use the RangeVar's name
- * to report any open/lock failure.)
+ * relations, if not NIL, is a list of VacuumRelation to process; otherwise,
+ * we process all relevant tables in the database. For each VacuumRelation,
+ * if a valid OID is supplied, the table with that OID is what to process;
+ * otherwise, the VacuumRelation's RangeVar indicates what to process.
*
* 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.
*
* memory context that will not disappear at transaction commit.
*/
void
-vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
- List *va_cols, BufferAccessStrategy bstrategy, bool isTopLevel)
+vacuum(int options, List *relations, VacuumParams *params,
+ BufferAccessStrategy bstrategy, bool isTopLevel)
{
+ static bool in_vacuum = false;
+
const char *stmttype;
volatile bool in_outer_xact,
use_own_xacts;
- List *relations;
- static bool in_vacuum = false;
Assert(params != NULL);
vac_strategy = bstrategy;
/*
- * Build list of relation OID(s) to process, putting it in vac_context for
- * safekeeping.
+ * Build list of relation(s) to process, putting any new data in
+ * vac_context for safekeeping.
*/
- relations = get_rel_oids(relid, relation);
+ if (relations != NIL)
+ {
+ List *newrels = NIL;
+ ListCell *lc;
+
+ foreach(lc, relations)
+ {
+ VacuumRelation *vrel = lfirst_node(VacuumRelation, lc);
+ List *sublist;
+ MemoryContext old_context;
+
+ sublist = expand_vacuum_rel(vrel);
+ old_context = MemoryContextSwitchTo(vac_context);
+ newrels = list_concat(newrels, sublist);
+ MemoryContextSwitchTo(old_context);
+ }
+ relations = newrels;
+ }
+ else
+ relations = get_all_vacuum_rels();
/*
* Decide whether we need to start/commit our own transactions.
CommitTransactionCommand();
}
- /* Turn vacuum cost accounting on or off */
+ /* Turn vacuum cost accounting on or off, and set/clear in_vacuum */
PG_TRY();
{
ListCell *cur;
*/
foreach(cur, relations)
{
- Oid relid = lfirst_oid(cur);
+ VacuumRelation *vrel = lfirst_node(VacuumRelation, cur);
if (options & VACOPT_VACUUM)
{
- if (!vacuum_rel(relid, relation, options, params))
+ if (!vacuum_rel(vrel->oid, vrel->relation, options, params))
continue;
}
PushActiveSnapshot(GetTransactionSnapshot());
}
- analyze_rel(relid, relation, options, params,
- va_cols, in_outer_xact, vac_strategy);
+ analyze_rel(vrel->oid, vrel->relation, options, params,
+ vrel->va_cols, in_outer_xact, vac_strategy);
if (use_own_xacts)
{
}
/*
- * Build a list of Oids for each relation to be processed
+ * Given a VacuumRelation, fill in the table OID if it wasn't specified,
+ * and optionally add VacuumRelations for partitions of the table.
+ *
+ * If a VacuumRelation does not have an OID supplied and is a partitioned
+ * table, an extra entry will be added to the output for each partition.
+ * Presently, only autovacuum supplies OIDs when calling vacuum(), and
+ * it does not want us to expand partitioned tables.
*
- * The list is built in vac_context so that it will survive across our
- * per-relation transactions.
+ * We take care not to modify the input data structure, but instead build
+ * new VacuumRelation(s) to return. (But note that they will reference
+ * unmodified parts of the input, eg column lists.) New data structures
+ * are made in vac_context.
*/
static List *
-get_rel_oids(Oid relid, const RangeVar *vacrel)
+expand_vacuum_rel(VacuumRelation *vrel)
{
- List *oid_list = NIL;
+ List *vacrels = NIL;
MemoryContext oldcontext;
- /* OID supplied by VACUUM's caller? */
- if (OidIsValid(relid))
+ /* If caller supplied OID, there's nothing we need do here. */
+ if (OidIsValid(vrel->oid))
{
oldcontext = MemoryContextSwitchTo(vac_context);
- oid_list = lappend_oid(oid_list, relid);
+ vacrels = lappend(vacrels, vrel);
MemoryContextSwitchTo(oldcontext);
}
- else if (vacrel)
+ else
{
/* Process a specific relation, and possibly partitions thereof */
Oid relid;
* below, as well as find_all_inheritors's expectation that the caller
* holds some lock on the starting relation.
*/
- relid = RangeVarGetRelid(vacrel, AccessShareLock, false);
+ relid = RangeVarGetRelid(vrel->relation, AccessShareLock, false);
+
+ /*
+ * Make a returnable VacuumRelation for this rel.
+ */
+ oldcontext = MemoryContextSwitchTo(vac_context);
+ vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
+ relid,
+ vrel->va_cols));
+ MemoryContextSwitchTo(oldcontext);
/*
* To check whether the relation is a partitioned table, fetch its
ReleaseSysCache(tuple);
/*
- * Make relation list entries for this rel and its partitions, if any.
- * Note that the list returned by find_all_inheritors() includes the
- * passed-in OID at its head. There's no point in taking locks on the
- * individual partitions yet, and doing so would just add unnecessary
- * deadlock risk.
+ * If it is, make relation list entries for its partitions. Note that
+ * the list returned by find_all_inheritors() includes the passed-in
+ * OID, so we have to skip that. There's no point in taking locks on
+ * the individual partitions yet, and doing so would just add
+ * unnecessary deadlock risk.
*/
- oldcontext = MemoryContextSwitchTo(vac_context);
if (include_parts)
- oid_list = list_concat(oid_list,
- find_all_inheritors(relid, NoLock, NULL));
- else
- oid_list = lappend_oid(oid_list, relid);
- MemoryContextSwitchTo(oldcontext);
+ {
+ List *part_oids = find_all_inheritors(relid, NoLock, NULL);
+ ListCell *part_lc;
+
+ foreach(part_lc, part_oids)
+ {
+ Oid part_oid = lfirst_oid(part_lc);
+
+ if (part_oid == relid)
+ continue; /* ignore original table */
+
+ /*
+ * We omit a RangeVar since it wouldn't be appropriate to
+ * complain about failure to open one of these relations
+ * later.
+ */
+ oldcontext = MemoryContextSwitchTo(vac_context);
+ vacrels = lappend(vacrels, makeVacuumRelation(NULL,
+ part_oid,
+ vrel->va_cols));
+ MemoryContextSwitchTo(oldcontext);
+ }
+ }
/*
* Release lock again. This means that by the time we actually try to
*/
UnlockRelationOid(relid, AccessShareLock);
}
- else
- {
- /*
- * Process all plain relations and materialized views listed in
- * pg_class
- */
- Relation pgclass;
- HeapScanDesc scan;
- HeapTuple tuple;
- pgclass = heap_open(RelationRelationId, AccessShareLock);
+ return vacrels;
+}
- scan = heap_beginscan_catalog(pgclass, 0, NULL);
+/*
+ * Construct a list of VacuumRelations for all vacuumable rels in
+ * the current database. The list is built in vac_context.
+ */
+static List *
+get_all_vacuum_rels(void)
+{
+ List *vacrels = NIL;
+ Relation pgclass;
+ HeapScanDesc scan;
+ HeapTuple tuple;
- while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
- {
- Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
-
- /*
- * We include partitioned tables here; depending on which
- * operation is to be performed, caller will decide whether to
- * process or ignore them.
- */
- if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW &&
- classForm->relkind != RELKIND_PARTITIONED_TABLE)
- continue;
-
- /* Make a relation list entry for this rel */
- oldcontext = MemoryContextSwitchTo(vac_context);
- oid_list = lappend_oid(oid_list, HeapTupleGetOid(tuple));
- MemoryContextSwitchTo(oldcontext);
- }
+ pgclass = heap_open(RelationRelationId, AccessShareLock);
+
+ scan = heap_beginscan_catalog(pgclass, 0, NULL);
+
+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+ {
+ Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
+ MemoryContext oldcontext;
- heap_endscan(scan);
- heap_close(pgclass, AccessShareLock);
+ /*
+ * We include partitioned tables here; depending on which operation is
+ * to be performed, caller will decide whether to process or ignore
+ * them.
+ */
+ if (classForm->relkind != RELKIND_RELATION &&
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
+ continue;
+
+ /*
+ * Build VacuumRelation(s) specifying the table OIDs to be processed.
+ * We omit a RangeVar since it wouldn't be appropriate to complain
+ * about failure to open one of these relations later.
+ */
+ oldcontext = MemoryContextSwitchTo(vac_context);
+ vacrels = lappend(vacrels, makeVacuumRelation(NULL,
+ HeapTupleGetOid(tuple),
+ NIL));
+ MemoryContextSwitchTo(oldcontext);
}
- return oid_list;
+ heap_endscan(scan);
+ heap_close(pgclass, AccessShareLock);
+
+ return vacrels;
}
/*
VacuumStmt *newnode = makeNode(VacuumStmt);
COPY_SCALAR_FIELD(options);
+ COPY_NODE_FIELD(rels);
+
+ return newnode;
+}
+
+static VacuumRelation *
+_copyVacuumRelation(const VacuumRelation *from)
+{
+ VacuumRelation *newnode = makeNode(VacuumRelation);
+
COPY_NODE_FIELD(relation);
+ COPY_SCALAR_FIELD(oid);
COPY_NODE_FIELD(va_cols);
return newnode;
case T_VacuumStmt:
retval = _copyVacuumStmt(from);
break;
+ case T_VacuumRelation:
+ retval = _copyVacuumRelation(from);
+ break;
case T_ExplainStmt:
retval = _copyExplainStmt(from);
break;
_equalVacuumStmt(const VacuumStmt *a, const VacuumStmt *b)
{
COMPARE_SCALAR_FIELD(options);
+ COMPARE_NODE_FIELD(rels);
+
+ return true;
+}
+
+static bool
+_equalVacuumRelation(const VacuumRelation *a, const VacuumRelation *b)
+{
COMPARE_NODE_FIELD(relation);
+ COMPARE_SCALAR_FIELD(oid);
COMPARE_NODE_FIELD(va_cols);
return true;
case T_VacuumStmt:
retval = _equalVacuumStmt(a, b);
break;
+ case T_VacuumRelation:
+ retval = _equalVacuumRelation(a, b);
+ break;
case T_ExplainStmt:
retval = _equalExplainStmt(a, b);
break;
n->location = location;
return n;
}
+
+/*
+ * makeVacuumRelation -
+ * create a VacuumRelation node
+ */
+VacuumRelation *
+makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols)
+{
+ VacuumRelation *v = makeNode(VacuumRelation);
+
+ v->relation = relation;
+ v->oid = oid;
+ v->va_cols = va_cols;
+ return v;
+}
%type DefACLOptionList
%type import_qualification_type
%type import_qualification
+%type vacuum_relation
%type stmtblock stmtmulti
OptTableElementList TableElementList OptInherit definition
transform_element_list transform_type_list
TriggerTransitions TriggerReferencing
publication_name_list
+ vacuum_relation_list opt_vacuum_relation_list
%type group_by_list
%type group_by_item empty_grouping_set rollup_clause cube_clause
*
*****************************************************************************/
-VacuumStmt: VACUUM opt_full opt_freeze opt_verbose
+VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_vacuum_relation_list
{
VacuumStmt *n = makeNode(VacuumStmt);
n->options = VACOPT_VACUUM;
n->options |= VACOPT_FREEZE;
if ($4)
n->options |= VACOPT_VERBOSE;
- n->relation = NULL;
- n->va_cols = NIL;
- $$ = (Node *)n;
- }
- | VACUUM opt_full opt_freeze opt_verbose qualified_name
- {
- VacuumStmt *n = makeNode(VacuumStmt);
- n->options = VACOPT_VACUUM;
- if ($2)
- n->options |= VACOPT_FULL;
- if ($3)
- n->options |= VACOPT_FREEZE;
- if ($4)
- n->options |= VACOPT_VERBOSE;
- n->relation = $5;
- n->va_cols = NIL;
+ n->rels = $5;
$$ = (Node *)n;
}
| VACUUM opt_full opt_freeze opt_verbose AnalyzeStmt
n->options |= VACOPT_VERBOSE;
$$ = (Node *)n;
}
- | VACUUM '(' vacuum_option_list ')'
- {
- VacuumStmt *n = makeNode(VacuumStmt);
- n->options = VACOPT_VACUUM | $3;
- n->relation = NULL;
- n->va_cols = NIL;
- $$ = (Node *) n;
- }
- | VACUUM '(' vacuum_option_list ')' qualified_name opt_name_list
+ | VACUUM '(' vacuum_option_list ')' opt_vacuum_relation_list
{
VacuumStmt *n = makeNode(VacuumStmt);
n->options = VACOPT_VACUUM | $3;
- n->relation = $5;
- n->va_cols = $6;
- if (n->va_cols != NIL) /* implies analyze */
- n->options |= VACOPT_ANALYZE;
+ n->rels = $5;
$$ = (Node *) n;
}
;
}
;
-AnalyzeStmt:
- analyze_keyword opt_verbose
+AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list
{
VacuumStmt *n = makeNode(VacuumStmt);
n->options = VACOPT_ANALYZE;
if ($2)
n->options |= VACOPT_VERBOSE;
- n->relation = NULL;
- n->va_cols = NIL;
- $$ = (Node *)n;
- }
- | analyze_keyword opt_verbose qualified_name opt_name_list
- {
- VacuumStmt *n = makeNode(VacuumStmt);
- n->options = VACOPT_ANALYZE;
- if ($2)
- n->options |= VACOPT_VERBOSE;
- n->relation = $3;
- n->va_cols = $4;
+ n->rels = $3;
$$ = (Node *)n;
}
;
| /*EMPTY*/ { $$ = NIL; }
;
+vacuum_relation:
+ qualified_name opt_name_list
+ {
+ $$ = (Node *) makeVacuumRelation($1, InvalidOid, $2);
+ }
+ ;
+
+vacuum_relation_list:
+ vacuum_relation
+ { $$ = list_make1($1); }
+ | vacuum_relation_list ',' vacuum_relation
+ { $$ = lappend($1, $3); }
+ ;
+
+opt_vacuum_relation_list:
+ vacuum_relation_list { $$ = $1; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
/*****************************************************************************
*
#include "lib/ilist.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
+#include "nodes/makefuncs.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "postmaster/fork_process.h"
static void
autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
{
- RangeVar rangevar;
-
- /* Set up command parameters --- use local variables instead of palloc */
- MemSet(&rangevar, 0, sizeof(rangevar));
-
- rangevar.schemaname = tab->at_nspname;
- rangevar.relname = tab->at_relname;
- rangevar.location = -1;
+ RangeVar *rangevar;
+ VacuumRelation *rel;
+ List *rel_list;
/* Let pgstat know what we're doing */
autovac_report_activity(tab);
- vacuum(tab->at_vacoptions, &rangevar, tab->at_relid, &tab->at_params, NIL,
- bstrategy, true);
+ /* Set up one VacuumRelation target, identified by OID, for vacuum() */
+ rangevar = makeRangeVar(tab->at_nspname, tab->at_relname, -1);
+ rel = makeVacuumRelation(rangevar, tab->at_relid, NIL);
+ rel_list = list_make1(rel);
+
+ vacuum(tab->at_vacoptions, rel_list, &tab->at_params, bstrategy, true);
}
/*
/* in commands/vacuum.c */
extern void ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel);
-extern void vacuum(int options, RangeVar *relation, Oid relid,
- VacuumParams *params, List *va_cols,
+extern void vacuum(int options, List *relations, VacuumParams *params,
BufferAccessStrategy bstrategy, bool isTopLevel);
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
int *nindexes, Relation **Irel);
extern GroupingSet *makeGroupingSet(GroupingSetKind kind, List *content, int location);
+extern VacuumRelation *makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols);
+
#endif /* MAKEFUNC_H */
T_PartitionBoundSpec,
T_PartitionRangeDatum,
T_PartitionCmd,
+ T_VacuumRelation,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
AlterTableType subtype; /* Type of table alteration to apply */
char *name; /* column, constraint, or trigger to act on,
* or tablespace */
- int16 num; /* attribute number for columns referenced
- * by number */
+ int16 num; /* attribute number for columns referenced by
+ * number */
RoleSpec *newowner;
Node *def; /* definition of new column, index,
* constraint, or parent table */
VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */
} VacuumOption;
+/*
+ * Info about a single target table of VACUUM/ANALYZE.
+ *
+ * If the OID field is set, it always identifies the table to process.
+ * Then the relation field can be NULL; if it isn't, it's used only to report
+ * failure to open/lock the relation.
+ */
+typedef struct VacuumRelation
+{
+ NodeTag type;
+ RangeVar *relation; /* table name to process, or NULL */
+ Oid oid; /* table's OID; InvalidOid if not looked up */
+ List *va_cols; /* list of column names, or NIL for all */
+} VacuumRelation;
+
typedef struct VacuumStmt
{
NodeTag type;
int options; /* OR of VacuumOption flags */
- RangeVar *relation; /* single table to process, or NULL */
- List *va_cols; /* list of column names, or NIL for all */
+ List *rels; /* list of VacuumRelation, or NIL for all */
} VacuumStmt;
/* ----------------------
SQL function "wrap_do_analyze" statement 1
VACUUM FULL vactst;
VACUUM (DISABLE_PAGE_SKIPPING) vaccluster;
-DROP TABLE vaccluster;
-DROP TABLE vactst;
-- partitioned table
CREATE TABLE vacparted (a int, b char) PARTITION BY LIST (a);
CREATE TABLE vacparted1 PARTITION OF vacparted FOR VALUES IN (1);
ERROR: column "a" of relation "vacparted" appears more than once
ANALYZE vacparted(a,b,b);
ERROR: column "b" of relation "vacparted" appears more than once
+-- multiple tables specified
+VACUUM vaccluster, vactst;
+VACUUM vacparted, does_not_exist;
+ERROR: relation "does_not_exist" does not exist
+VACUUM (FREEZE) vacparted, vaccluster, vactst;
+VACUUM (FREEZE) does_not_exist, vaccluster;
+ERROR: relation "does_not_exist" does not exist
+VACUUM ANALYZE vactst, vacparted (a);
+VACUUM ANALYZE vactst (does_not_exist), vacparted (b);
+ERROR: column "does_not_exist" of relation "vactst" does not exist
+VACUUM FULL vacparted, vactst;
+VACUUM FULL vactst, vacparted (a, b), vaccluster (i);
+ERROR: ANALYZE option must be specified when a column list is provided
+ANALYZE vactst, vacparted;
+ANALYZE vacparted (b), vactst;
+ANALYZE vactst, does_not_exist, vacparted;
+ERROR: relation "does_not_exist" does not exist
+ANALYZE vactst (i), vacparted (does_not_exist);
+ERROR: column "does_not_exist" of relation "vacparted" does not exist
+DROP TABLE vaccluster;
+DROP TABLE vactst;
DROP TABLE vacparted;
VACUUM (DISABLE_PAGE_SKIPPING) vaccluster;
-DROP TABLE vaccluster;
-DROP TABLE vactst;
-
-- partitioned table
CREATE TABLE vacparted (a int, b char) PARTITION BY LIST (a);
CREATE TABLE vacparted1 PARTITION OF vacparted FOR VALUES IN (1);
VACUUM ANALYZE vacparted(a,b,a);
ANALYZE vacparted(a,b,b);
+-- multiple tables specified
+VACUUM vaccluster, vactst;
+VACUUM vacparted, does_not_exist;
+VACUUM (FREEZE) vacparted, vaccluster, vactst;
+VACUUM (FREEZE) does_not_exist, vaccluster;
+VACUUM ANALYZE vactst, vacparted (a);
+VACUUM ANALYZE vactst (does_not_exist), vacparted (b);
+VACUUM FULL vacparted, vactst;
+VACUUM FULL vactst, vacparted (a, b), vaccluster (i);
+ANALYZE vactst, vacparted;
+ANALYZE vacparted (b), vactst;
+ANALYZE vactst, does_not_exist, vacparted;
+ANALYZE vactst (i), vacparted (does_not_exist);
+
+DROP TABLE vaccluster;
+DROP TABLE vactst;
DROP TABLE vacparted;