17 #include "catalog/pg_class_d.h"
70 const char *
progname,
bool echo,
bool quiet);
74 bool analyze_in_stages,
77 const char *
progname,
bool echo,
bool quiet);
92 #define ANALYZE_NO_STAGE -1
93 #define ANALYZE_NUM_STAGES 3
97 main(
int argc,
char *argv[])
99 static struct option long_options[] = {
137 const char *
dbname = NULL;
138 const char *maintenance_db = NULL;
147 bool analyze_in_stages =
false;
149 int concurrentCons = 1;
153 memset(&vacopts, 0,
sizeof(vacopts));
168 while ((
c =
getopt_long(argc, argv,
"ad:efFh:j:n:N:p:P:qt:U:vwWzZ", long_options, &optindex)) != -1)
298 pg_log_error(
"too many command-line arguments (first is \"%s\")",
313 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
316 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
319 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
320 "disable-page-skipping");
322 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
325 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
326 "force-index-cleanup");
328 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
331 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
334 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
343 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
346 pg_fatal(
"cannot use the \"%s\" option when performing full vacuum",
352 pg_fatal(
"cannot use the \"%s\" option with the \"%s\" option",
353 "no-index-cleanup",
"force-index-cleanup");
360 pg_fatal(
"cannot use the \"%s\" option with the \"%s\" option",
361 "buffer-usage-limit",
"full");
373 if (tbl_count && (concurrentCons > tbl_count))
374 concurrentCons = tbl_count;
378 cparams.
dbname = maintenance_db;
390 if (getenv(
"PGDATABASE"))
391 dbname = getenv(
"PGDATABASE");
392 else if (getenv(
"PGUSER"))
393 dbname = getenv(
"PGUSER");
400 if (analyze_in_stages)
432 pg_fatal(
"cannot vacuum all databases and a specific one at the same time");
436 pg_fatal(
"cannot vacuum all tables in schema(s) and specific table(s) at the same time");
440 pg_fatal(
"cannot vacuum specific table(s) and exclude schema(s) at the same time");
444 pg_fatal(
"cannot vacuum all tables in schema(s) and exclude schema(s) at the same time");
480 const char *
progname,
bool echo,
bool quiet)
493 bool objects_listed =
false;
494 bool has_where =
false;
496 const char *stage_commands[] = {
497 "SET default_statistics_target=1; SET vacuum_cost_delay=0;",
498 "SET default_statistics_target=10; RESET vacuum_cost_delay;",
499 "RESET default_statistics_target;"
501 const char *stage_messages[] = {
502 gettext_noop(
"Generating minimal optimizer statistics (1 target)"),
503 gettext_noop(
"Generating medium optimizer statistics (10 targets)"),
504 gettext_noop(
"Generating default (full) optimizer statistics")
515 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
516 "disable-page-skipping",
"9.6");
522 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
523 "no-index-cleanup",
"12");
529 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
530 "force-index-cleanup",
"12");
536 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
537 "no-truncate",
"12");
543 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
544 "no-process-main",
"16");
550 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
551 "no-process-toast",
"14");
557 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
558 "skip-locked",
"12");
562 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
563 "--min-xid-age",
"9.6");
566 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
567 "--min-mxid-age",
"9.6");
570 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
574 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
575 "--buffer-usage-limit",
"16");
583 printf(
_(
"%s: processing database \"%s\": %s\n"),
586 printf(
_(
"%s: vacuuming database \"%s\"\n"),
606 for (cell = objects ? objects->
head : NULL; cell; cell = cell->
next)
608 char *just_table = NULL;
609 const char *just_columns = NULL;
614 "WITH listed_objects (object_oid, column_list) "
616 objects_listed =
true;
636 &just_table, &just_columns);
642 if (just_columns && just_columns[0] !=
'\0')
662 " FROM pg_catalog.pg_class c\n"
663 " JOIN pg_catalog.pg_namespace ns"
664 " ON c.relnamespace OPERATOR(pg_catalog.=) ns.oid\n"
665 " LEFT JOIN pg_catalog.pg_class t"
666 " ON c.reltoastrelid OPERATOR(pg_catalog.=) t.oid\n");
672 " ON listed_objects.object_oid"
673 " OPERATOR(pg_catalog.=) ");
682 " WHERE listed_objects.object_oid IS NULL\n");
685 " WHERE listed_objects.object_oid IS NOT NULL\n");
698 " %s c.relkind OPERATOR(pg_catalog.=) ANY (array["
701 has_where ?
"AND" :
"WHERE");
715 " %s GREATEST(pg_catalog.age(c.relfrozenxid),"
716 " pg_catalog.age(t.relfrozenxid)) "
717 " OPERATOR(pg_catalog.>=) '%d'::pg_catalog.int4\n"
718 " AND c.relfrozenxid OPERATOR(pg_catalog.!=)"
719 " '0'::pg_catalog.xid\n",
720 has_where ?
"AND" :
"WHERE", vacopts->
min_xid_age);
727 " %s GREATEST(pg_catalog.mxid_age(c.relminmxid),"
728 " pg_catalog.mxid_age(t.relminmxid)) OPERATOR(pg_catalog.>=)"
729 " '%d'::pg_catalog.int4\n"
730 " AND c.relminmxid OPERATOR(pg_catalog.!=)"
731 " '0'::pg_catalog.xid\n",
762 for (
i = 0;
i < ntups;
i++)
781 if (concurrentCons > ntups)
782 concurrentCons = ntups;
783 if (concurrentCons <= 0)
795 initcmd = stage_commands[stage];
809 cell = dbtables.
head;
812 const char *tabname = cell->
val;
840 }
while (cell != NULL);
851 const char *cmd =
"VACUUM (ONLY_DATABASE_STATS);";
887 bool analyze_in_stages,
890 const char *
progname,
bool echo,
bool quiet)
899 "SELECT datname FROM pg_database WHERE datallowconn AND datconnlimit <> -2 ORDER BY 1;",
903 if (analyze_in_stages)
955 const char *paren =
" (";
956 const char *
comma =
", ";
957 const char *sep = paren;
966 if (serverVersion >= 110000)
971 Assert(serverVersion >= 120000);
982 Assert(serverVersion >= 160000);
1001 if (serverVersion >= 90000)
1006 Assert(serverVersion >= 90600);
1013 Assert(serverVersion >= 120000);
1021 Assert(serverVersion >= 120000);
1029 Assert(serverVersion >= 120000);
1036 Assert(serverVersion >= 160000);
1043 Assert(serverVersion >= 140000);
1050 Assert(serverVersion >= 160000);
1057 Assert(serverVersion >= 120000);
1084 Assert(serverVersion >= 130000);
1091 Assert(serverVersion >= 160000);
1135 pg_log_error(
"vacuuming of table \"%s\" in database \"%s\" failed: %s",
1138 pg_log_error(
"vacuuming of database \"%s\" failed: %s",
1146 printf(
_(
"%s cleans and analyzes a PostgreSQL database.\n\n"),
progname);
1150 printf(
_(
" -a, --all vacuum all databases\n"));
1151 printf(
_(
" --buffer-usage-limit=SIZE size of ring buffer used for vacuum\n"));
1152 printf(
_(
" -d, --dbname=DBNAME database to vacuum\n"));
1153 printf(
_(
" --disable-page-skipping disable all page-skipping behavior\n"));
1154 printf(
_(
" -e, --echo show the commands being sent to the server\n"));
1155 printf(
_(
" -f, --full do full vacuuming\n"));
1156 printf(
_(
" -F, --freeze freeze row transaction information\n"));
1157 printf(
_(
" --force-index-cleanup always remove index entries that point to dead tuples\n"));
1158 printf(
_(
" -j, --jobs=NUM use this many concurrent connections to vacuum\n"));
1159 printf(
_(
" --min-mxid-age=MXID_AGE minimum multixact ID age of tables to vacuum\n"));
1160 printf(
_(
" --min-xid-age=XID_AGE minimum transaction ID age of tables to vacuum\n"));
1161 printf(
_(
" --no-index-cleanup don't remove index entries that point to dead tuples\n"));
1162 printf(
_(
" --no-process-main skip the main relation\n"));
1163 printf(
_(
" --no-process-toast skip the TOAST table associated with the table to vacuum\n"));
1164 printf(
_(
" --no-truncate don't truncate empty pages at the end of the table\n"));
1165 printf(
_(
" -n, --schema=SCHEMA vacuum tables in the specified schema(s) only\n"));
1166 printf(
_(
" -N, --exclude-schema=SCHEMA do not vacuum tables in the specified schema(s)\n"));
1167 printf(
_(
" -P, --parallel=PARALLEL_WORKERS use this many background workers for vacuum, if available\n"));
1168 printf(
_(
" -q, --quiet don't write any messages\n"));
1169 printf(
_(
" --skip-locked skip relations that cannot be immediately locked\n"));
1170 printf(
_(
" -t, --table='TABLE[(COLUMNS)]' vacuum specific table(s) only\n"));
1171 printf(
_(
" -v, --verbose write a lot of output\n"));
1172 printf(
_(
" -V, --version output version information, then exit\n"));
1173 printf(
_(
" -z, --analyze update optimizer statistics\n"));
1174 printf(
_(
" -Z, --analyze-only only update optimizer statistics; no vacuum\n"));
1175 printf(
_(
" --analyze-in-stages only update optimizer statistics, in multiple\n"
1176 " stages for faster results; no vacuum\n"));
1177 printf(
_(
" -?, --help show this help, then exit\n"));
1178 printf(
_(
"\nConnection options:\n"));
1179 printf(
_(
" -h, --host=HOSTNAME database server host or socket directory\n"));
1180 printf(
_(
" -p, --port=PORT database server port\n"));
1181 printf(
_(
" -U, --username=USERNAME user name to connect as\n"));
1182 printf(
_(
" -w, --no-password never prompt for password\n"));
1183 printf(
_(
" -W, --password force password prompt\n"));
1184 printf(
_(
" --maintenance-db=DBNAME alternate maintenance database\n"));
1185 printf(
_(
"\nRead the description of the SQL command VACUUM for details.\n"));
1186 printf(
_(
"\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1187 printf(
_(
"%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
void splitTableColumnsSpec(const char *spec, int encoding, char **table, const char **columns)
#define Assert(condition)
#define PG_TEXTDOMAIN(domain)
volatile sig_atomic_t CancelRequested
void setup_cancel_handler(void(*query_cancel_callback)(void))
void set_pglocale_pgservice(const char *argv0, const char *app)
#define ALWAYS_SECURE_SEARCH_PATH_SQL
PGconn * connectMaintenanceDatabase(ConnParams *cparams, const char *progname, bool echo)
static void PGresult * res
int PQserverVersion(const PGconn *conn)
char * PQdb(const PGconn *conn)
char * PQerrorMessage(const PGconn *conn)
int PQclientEncoding(const PGconn *conn)
void PQfinish(PGconn *conn)
int PQntuples(const PGresult *res)
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
int PQsendQuery(PGconn *conn, const char *query)
char * pg_strdup(const char *in)
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
#define required_argument
static void const char fflush(stdout)
void pg_logging_init(const char *argv0)
#define pg_log_error(...)
#define pg_log_error_hint(...)
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
ParallelSlot * ParallelSlotsGetIdle(ParallelSlotArray *sa, const char *dbname)
bool ParallelSlotsWaitCompletion(ParallelSlotArray *sa)
ParallelSlotArray * ParallelSlotsSetup(int numslots, ConnParams *cparams, const char *progname, bool echo, const char *initcmd)
bool TableCommandResultHandler(PGresult *res, PGconn *conn, void *context)
void ParallelSlotsTerminate(ParallelSlotArray *sa)
void ParallelSlotsAdoptConn(ParallelSlotArray *sa, PGconn *conn)
static void ParallelSlotSetHandler(ParallelSlot *slot, ParallelSlotResultHandler handler, void *context)
static PGconn * connectDatabase(const char *dbname, const char *connection_string, const char *pghost, const char *pgport, const char *pguser, trivalue prompt_password, bool fail_on_error)
static void executeCommand(PGconn *conn, const char *query)
static PGresult * executeQuery(PGconn *conn, const char *query)
PGDLLIMPORT char * optarg
const char * get_progname(const char *argv0)
char * escape_single_quotes_ascii(const char *src)
void initPQExpBuffer(PQExpBuffer str)
void resetPQExpBuffer(PQExpBuffer str)
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
void appendPQExpBufferChar(PQExpBuffer str, char ch)
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
void termPQExpBuffer(PQExpBuffer str)
void simple_string_list_append(SimpleStringList *list, const char *val)
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
const char * fmtQualifiedId(const char *schema, const char *id)
char val[FLEXIBLE_ARRAY_MEMBER]
struct SimpleStringListCell * next
SimpleStringListCell * head
enum trivalue prompt_password
bool disable_page_skipping
char * buffer_usage_limit
const char * get_user_name_or_exit(const char *progname)
int main(int argc, char *argv[])
void check_objfilter(void)
static void vacuum_all_databases(ConnParams *cparams, vacuumingOptions *vacopts, bool analyze_in_stages, SimpleStringList *objects, int concurrentCons, const char *progname, bool echo, bool quiet)
static void help(const char *progname)
struct vacuumingOptions vacuumingOptions
static void run_vacuum_command(PGconn *conn, const char *sql, bool echo, const char *table)
#define ANALYZE_NUM_STAGES
@ OBJFILTER_SCHEMA_EXCLUDE
static void prepare_vacuum_command(PQExpBuffer sql, int serverVersion, vacuumingOptions *vacopts, const char *table)
static char * escape_quotes(const char *src)
static void vacuum_one_database(ConnParams *cparams, vacuumingOptions *vacopts, int stage, SimpleStringList *objects, int concurrentCons, const char *progname, bool echo, bool quiet)
static VacObjFilter objfilter