diff -cprN head/doc/src/sgml/ref/vacuum.sgml work/doc/src/sgml/ref/vacuum.sgml *** head/doc/src/sgml/ref/vacuum.sgml 2009-03-25 05:17:08.000000000 +0900 --- work/doc/src/sgml/ref/vacuum.sgml 2009-11-13 10:17:39.141536000 +0900 *************** PostgreSQL documentation *** 21,26 **** --- 21,27 ---- + VACUUM [ ( { FULL | FREEZE | VERBOSE | ANALYZE } [, ...] ) ] [ table [ (column [, ...] ) ] ] VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ table ] VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ] diff -cprN head/src/backend/commands/analyze.c work/src/backend/commands/analyze.c *** head/src/backend/commands/analyze.c 2009-08-13 03:23:49.000000000 +0900 --- work/src/backend/commands/analyze.c 2009-11-13 10:00:02.275841676 +0900 *************** analyze_rel(Oid relid, VacuumStmt *vacst *** 135,141 **** Oid save_userid; bool save_secdefcxt; ! if (vacstmt->verbose) elevel = INFO; else elevel = DEBUG2; --- 135,141 ---- Oid save_userid; bool save_secdefcxt; ! if (vacstmt->options & VACOPT_VERBOSE) elevel = INFO; else elevel = DEBUG2; *************** analyze_rel(Oid relid, VacuumStmt *vacst *** 173,179 **** (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared))) { /* No need for a WARNING if we already complained during VACUUM */ ! if (!vacstmt->vacuum) { if (onerel->rd_rel->relisshared) ereport(WARNING, --- 173,179 ---- (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 (onerel->rd_rel->relisshared) ereport(WARNING, *************** analyze_rel(Oid relid, VacuumStmt *vacst *** 199,205 **** if (onerel->rd_rel->relkind != RELKIND_RELATION) { /* No need for a WARNING if we already complained during VACUUM */ ! if (!vacstmt->vacuum) ereport(WARNING, (errmsg("skipping \"%s\" --- cannot analyze indexes, views, or special system tables", RelationGetRelationName(onerel)))); --- 199,205 ---- if (onerel->rd_rel->relkind != RELKIND_RELATION) { /* No need for a WARNING if we already complained during VACUUM */ ! if (!(vacstmt->options & VACOPT_VACUUM)) ereport(WARNING, (errmsg("skipping \"%s\" --- cannot analyze indexes, views, or special system tables", RelationGetRelationName(onerel)))); *************** analyze_rel(Oid relid, VacuumStmt *vacst *** 475,481 **** * VACUUM ANALYZE, don't overwrite the accurate count already inserted by * VACUUM. */ ! if (!vacstmt->vacuum) { for (ind = 0; ind < nindexes; ind++) { --- 475,481 ---- * VACUUM ANALYZE, don't overwrite the accurate count already inserted by * VACUUM. */ ! if (!(vacstmt->options & VACOPT_VACUUM)) { for (ind = 0; ind < nindexes; ind++) { *************** analyze_rel(Oid relid, VacuumStmt *vacst *** 493,499 **** cleanup: /* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup */ ! if (!vacstmt->vacuum) { for (ind = 0; ind < nindexes; ind++) { --- 493,499 ---- cleanup: /* If this isn't part of VACUUM ANALYZE, let index AMs do cleanup */ ! if (!(vacstmt->options & VACOPT_VACUUM)) { for (ind = 0; ind < nindexes; ind++) { diff -cprN head/src/backend/commands/vacuum.c work/src/backend/commands/vacuum.c *** head/src/backend/commands/vacuum.c 2009-11-11 03:00:06.000000000 +0900 --- work/src/backend/commands/vacuum.c 2009-11-13 10:33:33.200912128 +0900 *************** void *** 289,302 **** vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel) { ! const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE"; volatile MemoryContext anl_context = NULL; volatile bool all_rels, in_outer_xact, use_own_xacts; List *relations; ! if (vacstmt->verbose) elevel = INFO; else elevel = DEBUG2; --- 289,310 ---- vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel) { ! const char *stmttype; volatile MemoryContext anl_context = NULL; volatile bool all_rels, in_outer_xact, use_own_xacts; List *relations; ! /* sanity checks */ ! Assert(vacstmt->options & (VACOPT_VACUUM | VACOPT_ANALYZE)); ! Assert(!(vacstmt->options & (VACOPT_FULL | VACOPT_FREEZE)) || ! (vacstmt->options & VACOPT_VACUUM)); ! Assert(vacstmt->va_cols == NIL || (vacstmt->options & VACOPT_ANALYZE)); ! ! stmttype = (vacstmt->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE"; ! ! if (vacstmt->options & VACOPT_VERBOSE) elevel = INFO; else elevel = DEBUG2; *************** vacuum(VacuumStmt *vacstmt, Oid relid, b *** 315,336 **** * * ANALYZE (without VACUUM) can run either way. */ ! if (vacstmt->vacuum) { PreventTransactionChain(isTopLevel, stmttype); in_outer_xact = false; } else in_outer_xact = IsInTransactionChain(isTopLevel); /* - * Send info about dead objects to the statistics collector, unless we are - * in autovacuum --- autovacuum.c does this for itself. - */ - if (vacstmt->vacuum && !IsAutoVacuumWorkerProcess()) - pgstat_vacuum_stat(); - - /* * Create special memory context for cross-transaction storage. * * Since it is a child of PortalContext, it will go away eventually even --- 323,344 ---- * * ANALYZE (without VACUUM) can run either way. */ ! if (vacstmt->options & VACOPT_VACUUM) { PreventTransactionChain(isTopLevel, stmttype); in_outer_xact = false; + + /* + * Send info about dead objects to the statistics collector, unless + * we are in autovacuum --- autovacuum.c does this for itself. + */ + if (!IsAutoVacuumWorkerProcess()) + pgstat_vacuum_stat(); } else in_outer_xact = IsInTransactionChain(isTopLevel); /* * Create special memory context for cross-transaction storage. * * Since it is a child of PortalContext, it will go away eventually even *************** vacuum(VacuumStmt *vacstmt, Oid relid, b *** 378,388 **** * transaction block, and also in an autovacuum worker, use own * transactions so we can release locks sooner. */ ! if (vacstmt->vacuum) use_own_xacts = true; else { ! Assert(vacstmt->analyze); if (IsAutoVacuumWorkerProcess()) use_own_xacts = true; else if (in_outer_xact) --- 386,396 ---- * transaction block, and also in an autovacuum worker, use own * transactions so we can release locks sooner. */ ! if (vacstmt->options & VACOPT_VACUUM) use_own_xacts = true; else { ! Assert(vacstmt->options & VACOPT_ANALYZE); if (IsAutoVacuumWorkerProcess()) use_own_xacts = true; else if (in_outer_xact) *************** vacuum(VacuumStmt *vacstmt, Oid relid, b *** 438,448 **** Oid relid = lfirst_oid(cur); bool scanned_all = false; ! if (vacstmt->vacuum) vacuum_rel(relid, vacstmt, do_toast, for_wraparound, &scanned_all); ! if (vacstmt->analyze) { MemoryContext old_context = NULL; --- 446,456 ---- Oid relid = lfirst_oid(cur); bool scanned_all = false; ! if (vacstmt->options & VACOPT_VACUUM) vacuum_rel(relid, vacstmt, do_toast, for_wraparound, &scanned_all); ! if (vacstmt->options & VACOPT_ANALYZE) { MemoryContext old_context = NULL; *************** vacuum(VacuumStmt *vacstmt, Oid relid, b *** 502,508 **** StartTransactionCommand(); } ! if (vacstmt->vacuum && !IsAutoVacuumWorkerProcess()) { /* * Update pg_database.datfrozenxid, and truncate pg_clog if possible. --- 510,516 ---- StartTransactionCommand(); } ! if ((vacstmt->options & VACOPT_VACUUM) && !IsAutoVacuumWorkerProcess()) { /* * Update pg_database.datfrozenxid, and truncate pg_clog if possible. *************** vacuum_rel(Oid relid, VacuumStmt *vacstm *** 1034,1040 **** */ PushActiveSnapshot(GetTransactionSnapshot()); ! if (!vacstmt->full) { /* * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets --- 1042,1048 ---- */ PushActiveSnapshot(GetTransactionSnapshot()); ! if (!(vacstmt->options & VACOPT_FULL)) { /* * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets *************** vacuum_rel(Oid relid, VacuumStmt *vacstm *** 1074,1080 **** * vacuum, but just ShareUpdateExclusiveLock for concurrent vacuum. Either * way, we can be sure that no other backend is vacuuming the same table. */ ! lmode = vacstmt->full ? AccessExclusiveLock : ShareUpdateExclusiveLock; /* * Open the relation and get the appropriate lock on it. --- 1082,1090 ---- * 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; /* * Open the relation and get the appropriate lock on it. *************** vacuum_rel(Oid relid, VacuumStmt *vacstm *** 1186,1192 **** /* * Do the actual work --- either FULL or "lazy" vacuum */ ! if (vacstmt->full) heldoff = full_vacuum_rel(onerel, vacstmt); else heldoff = lazy_vacuum_rel(onerel, vacstmt, vac_strategy, scanned_all); --- 1196,1202 ---- /* * Do the actual work --- either FULL or "lazy" vacuum */ ! if (vacstmt->options & VACOPT_FULL) heldoff = full_vacuum_rel(onerel, vacstmt); else heldoff = lazy_vacuum_rel(onerel, vacstmt, vac_strategy, scanned_all); *************** full_vacuum_rel(Relation onerel, VacuumS *** 1332,1338 **** /* report results to the stats collector, too */ pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, ! true, vacstmt->analyze, vacrelstats->rel_tuples); return heldoff; } --- 1342,1348 ---- /* report results to the stats collector, too */ pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, ! true, (vacstmt->options & VACOPT_ANALYZE) != 0, vacrelstats->rel_tuples); return heldoff; } diff -cprN head/src/backend/commands/vacuumlazy.c work/src/backend/commands/vacuumlazy.c *** head/src/backend/commands/vacuumlazy.c 2009-11-11 03:00:06.000000000 +0900 --- work/src/backend/commands/vacuumlazy.c 2009-11-13 10:00:02.277828910 +0900 *************** lazy_vacuum_rel(Relation onerel, VacuumS *** 164,170 **** if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration > 0) starttime = GetCurrentTimestamp(); ! if (vacstmt->verbose) elevel = INFO; else elevel = DEBUG2; --- 164,170 ---- if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration > 0) starttime = GetCurrentTimestamp(); ! if (vacstmt->options & VACOPT_VERBOSE) elevel = INFO; else elevel = DEBUG2; *************** lazy_vacuum_rel(Relation onerel, VacuumS *** 236,242 **** pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, vacrelstats->scanned_all, ! vacstmt->analyze, vacrelstats->rel_tuples); /* and log the action if appropriate */ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) --- 236,243 ---- pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, vacrelstats->scanned_all, ! (vacstmt->options & VACOPT_ANALYZE) != 0, ! vacrelstats->rel_tuples); /* and log the action if appropriate */ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) diff -cprN head/src/backend/nodes/copyfuncs.c work/src/backend/nodes/copyfuncs.c *** head/src/backend/nodes/copyfuncs.c 2009-10-28 23:55:38.000000000 +0900 --- work/src/backend/nodes/copyfuncs.c 2009-11-13 10:00:02.278845497 +0900 *************** _copyVacuumStmt(VacuumStmt *from) *** 2957,2966 **** { VacuumStmt *newnode = makeNode(VacuumStmt); ! COPY_SCALAR_FIELD(vacuum); ! COPY_SCALAR_FIELD(full); ! COPY_SCALAR_FIELD(analyze); ! COPY_SCALAR_FIELD(verbose); COPY_SCALAR_FIELD(freeze_min_age); COPY_SCALAR_FIELD(freeze_table_age); COPY_NODE_FIELD(relation); --- 2957,2963 ---- { VacuumStmt *newnode = makeNode(VacuumStmt); ! COPY_SCALAR_FIELD(options); COPY_SCALAR_FIELD(freeze_min_age); COPY_SCALAR_FIELD(freeze_table_age); COPY_NODE_FIELD(relation); diff -cprN head/src/backend/nodes/equalfuncs.c work/src/backend/nodes/equalfuncs.c *** head/src/backend/nodes/equalfuncs.c 2009-10-28 23:55:38.000000000 +0900 --- work/src/backend/nodes/equalfuncs.c 2009-11-13 10:00:02.279860288 +0900 *************** _equalDropdbStmt(DropdbStmt *a, DropdbSt *** 1483,1492 **** static bool _equalVacuumStmt(VacuumStmt *a, VacuumStmt *b) { ! COMPARE_SCALAR_FIELD(vacuum); ! COMPARE_SCALAR_FIELD(full); ! COMPARE_SCALAR_FIELD(analyze); ! COMPARE_SCALAR_FIELD(verbose); COMPARE_SCALAR_FIELD(freeze_min_age); COMPARE_SCALAR_FIELD(freeze_table_age); COMPARE_NODE_FIELD(relation); --- 1483,1489 ---- static bool _equalVacuumStmt(VacuumStmt *a, VacuumStmt *b) { ! COMPARE_SCALAR_FIELD(options); COMPARE_SCALAR_FIELD(freeze_min_age); COMPARE_SCALAR_FIELD(freeze_table_age); COMPARE_NODE_FIELD(relation); diff -cprN head/src/backend/parser/gram.y work/src/backend/parser/gram.y *** head/src/backend/parser/gram.y 2009-11-12 05:31:26.000000000 +0900 --- work/src/backend/parser/gram.y 2009-11-13 10:29:38.737883224 +0900 *************** static TypeName *TableFuncTypeName(List *** 229,234 **** --- 229,235 ---- transaction_mode_item %type opt_lock lock_type cast_context + %type vacuum_option_list vacuum_option_elem %type opt_force opt_or_replace opt_grant_grant_option opt_grant_admin_option opt_nowait opt_if_exists opt_with_data *************** static TypeName *TableFuncTypeName(List *** 484,490 **** IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P ! INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION JOIN --- 485,491 ---- IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P ! INNER_P INOUT INPLACE INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION JOIN *************** cluster_index_specification: *** 6625,6636 **** VacuumStmt: VACUUM opt_full opt_freeze opt_verbose { VacuumStmt *n = makeNode(VacuumStmt); ! n->vacuum = true; ! n->analyze = false; ! n->full = $2; n->freeze_min_age = $3 ? 0 : -1; n->freeze_table_age = $3 ? 0 : -1; - n->verbose = $4; n->relation = NULL; n->va_cols = NIL; $$ = (Node *)n; --- 6626,6638 ---- VacuumStmt: VACUUM opt_full opt_freeze opt_verbose { VacuumStmt *n = makeNode(VacuumStmt); ! n->options = VACOPT_VACUUM; ! if ($2) ! n->options |= VACOPT_FULL; ! if ($4) ! n->options |= VACOPT_VERBOSE; n->freeze_min_age = $3 ? 0 : -1; n->freeze_table_age = $3 ? 0 : -1; n->relation = NULL; n->va_cols = NIL; $$ = (Node *)n; *************** VacuumStmt: VACUUM opt_full opt_freeze o *** 6638,6649 **** | VACUUM opt_full opt_freeze opt_verbose qualified_name { VacuumStmt *n = makeNode(VacuumStmt); ! n->vacuum = true; ! n->analyze = false; ! n->full = $2; n->freeze_min_age = $3 ? 0 : -1; n->freeze_table_age = $3 ? 0 : -1; - n->verbose = $4; n->relation = $5; n->va_cols = NIL; $$ = (Node *)n; --- 6640,6652 ---- | VACUUM opt_full opt_freeze opt_verbose qualified_name { VacuumStmt *n = makeNode(VacuumStmt); ! n->options = VACOPT_VACUUM; ! if ($2) ! n->options |= VACOPT_FULL; ! if ($4) ! n->options |= VACOPT_VERBOSE; n->freeze_min_age = $3 ? 0 : -1; n->freeze_table_age = $3 ? 0 : -1; n->relation = $5; n->va_cols = NIL; $$ = (Node *)n; *************** VacuumStmt: VACUUM opt_full opt_freeze o *** 6651,6675 **** | VACUUM opt_full opt_freeze opt_verbose AnalyzeStmt { VacuumStmt *n = (VacuumStmt *) $5; ! n->vacuum = true; ! n->full = $2; n->freeze_min_age = $3 ? 0 : -1; n->freeze_table_age = $3 ? 0 : -1; - n->verbose |= $4; $$ = (Node *)n; } ; AnalyzeStmt: analyze_keyword opt_verbose { VacuumStmt *n = makeNode(VacuumStmt); ! n->vacuum = false; ! n->analyze = true; ! n->full = false; n->freeze_min_age = -1; n->freeze_table_age = -1; - n->verbose = $2; n->relation = NULL; n->va_cols = NIL; $$ = (Node *)n; --- 6654,6717 ---- | VACUUM opt_full opt_freeze opt_verbose AnalyzeStmt { VacuumStmt *n = (VacuumStmt *) $5; ! n->options |= VACOPT_VACUUM; ! if ($2) ! n->options |= VACOPT_FULL; ! if ($4) ! n->options |= VACOPT_VERBOSE; n->freeze_min_age = $3 ? 0 : -1; n->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; + else + n->freeze_min_age = n->freeze_table_age = -1; + n->relation = NULL; + n->va_cols = NIL; + $$ = (Node *) n; + } + | VACUUM '(' vacuum_option_list ')' qualified_name opt_name_list + { + VacuumStmt *n = makeNode(VacuumStmt); + n->options = VACOPT_VACUUM | $3; + if (n->options & VACOPT_FREEZE) + n->freeze_min_age = n->freeze_table_age = 0; + else + n->freeze_min_age = n->freeze_table_age = -1; + n->relation = $5; + n->va_cols = $6; + if (n->va_cols != NIL) /* implies analyze */ + n->options |= VACOPT_ANALYZE; + $$ = (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; } ; AnalyzeStmt: analyze_keyword opt_verbose { VacuumStmt *n = makeNode(VacuumStmt); ! n->options = VACOPT_ANALYZE; ! if ($2) ! n->options |= VACOPT_VERBOSE; n->freeze_min_age = -1; n->freeze_table_age = -1; n->relation = NULL; n->va_cols = NIL; $$ = (Node *)n; *************** AnalyzeStmt: *** 6677,6688 **** | analyze_keyword opt_verbose qualified_name opt_name_list { VacuumStmt *n = makeNode(VacuumStmt); ! n->vacuum = false; ! n->analyze = true; ! n->full = false; n->freeze_min_age = -1; n->freeze_table_age = -1; - n->verbose = $2; n->relation = $3; n->va_cols = $4; $$ = (Node *)n; --- 6719,6729 ---- | analyze_keyword opt_verbose qualified_name opt_name_list { VacuumStmt *n = makeNode(VacuumStmt); ! n->options = VACOPT_ANALYZE; ! if ($2) ! n->options |= VACOPT_VERBOSE; n->freeze_min_age = -1; n->freeze_table_age = -1; n->relation = $3; n->va_cols = $4; $$ = (Node *)n; diff -cprN head/src/backend/postmaster/autovacuum.c work/src/backend/postmaster/autovacuum.c *** head/src/backend/postmaster/autovacuum.c 2009-09-01 04:40:59.000000000 +0900 --- work/src/backend/postmaster/autovacuum.c 2009-11-13 10:00:02.283848658 +0900 *************** autovacuum_do_vac_analyze(autovac_table *** 2640,2651 **** MemSet(&vacstmt, 0, sizeof(vacstmt)); vacstmt.type = T_VacuumStmt; ! vacstmt.vacuum = tab->at_dovacuum; ! vacstmt.full = false; ! vacstmt.analyze = tab->at_doanalyze; vacstmt.freeze_min_age = tab->at_freeze_min_age; vacstmt.freeze_table_age = tab->at_freeze_table_age; - vacstmt.verbose = false; vacstmt.relation = NULL; /* not used since we pass a relid */ vacstmt.va_cols = NIL; --- 2640,2651 ---- MemSet(&vacstmt, 0, sizeof(vacstmt)); vacstmt.type = T_VacuumStmt; ! 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.relation = NULL; /* not used since we pass a relid */ vacstmt.va_cols = NIL; diff -cprN head/src/backend/tcop/utility.c work/src/backend/tcop/utility.c *** head/src/backend/tcop/utility.c 2009-10-26 11:26:40.000000000 +0900 --- work/src/backend/tcop/utility.c 2009-11-13 10:00:02.284847777 +0900 *************** CreateCommandTag(Node *parsetree) *** 1815,1821 **** break; case T_VacuumStmt: ! if (((VacuumStmt *) parsetree)->vacuum) tag = "VACUUM"; else tag = "ANALYZE"; --- 1815,1821 ---- break; case T_VacuumStmt: ! if (((VacuumStmt *) parsetree)->options & VACOPT_VACUUM) tag = "VACUUM"; else tag = "ANALYZE"; diff -cprN head/src/include/nodes/parsenodes.h work/src/include/nodes/parsenodes.h *** head/src/include/nodes/parsenodes.h 2009-11-07 06:57:57.000000000 +0900 --- work/src/include/nodes/parsenodes.h 2009-11-13 10:04:59.222848463 +0900 *************** typedef struct ClusterStmt *** 2212,2224 **** * just one node type for both. * ---------------------- */ typedef struct VacuumStmt { NodeTag type; ! bool vacuum; /* do VACUUM step */ ! bool full; /* do FULL (non-concurrent) vacuum */ ! bool analyze; /* do ANALYZE step */ ! bool verbose; /* print progress info */ int freeze_min_age; /* min freeze age, or -1 to use default */ int freeze_table_age; /* age at which to scan whole table */ RangeVar *relation; /* single table to process, or NULL */ --- 2212,2231 ---- * just one node type for both. * ---------------------- */ + + typedef enum VacuumOption + { + VACOPT_VACUUM = 1 << 0, /* do VACUUM */ + VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */ + VACOPT_VERBOSE = 1 << 2, /* VERBOSE option */ + VACOPT_FREEZE = 1 << 3, /* FREEZE option */ + VACOPT_FULL = 1 << 4 /* FULL option */ + } VacuumOption; + typedef struct VacuumStmt { NodeTag type; ! bits32 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 */ RangeVar *relation; /* single table to process, or NULL */ diff -cprN head/src/test/regress/expected/vacuum.out work/src/test/regress/expected/vacuum.out *** head/src/test/regress/expected/vacuum.out 2002-07-20 13:58:14.000000000 +0900 --- work/src/test/regress/expected/vacuum.out 2009-11-13 10:15:10.348824551 +0900 *************** SELECT * FROM vactst; *** 56,59 **** --- 56,62 ---- --- (0 rows) + VACUUM (FULL) vactst; + VACUUM (FREEZE) vactst; + VACUUM (FULL, FREEZE) vactst; DROP TABLE vactst; diff -cprN head/src/test/regress/sql/vacuum.sql work/src/test/regress/sql/vacuum.sql *** head/src/test/regress/sql/vacuum.sql 2002-07-20 13:58:14.000000000 +0900 --- work/src/test/regress/sql/vacuum.sql 2009-11-13 10:14:15.709830767 +0900 *************** VACUUM FULL vactst; *** 39,42 **** --- 39,46 ---- DELETE FROM vactst; SELECT * FROM vactst; + VACUUM (FULL) vactst; + VACUUM (FREEZE) vactst; + VACUUM (FULL, FREEZE) vactst; + DROP TABLE vactst;