17#include "catalog/pg_class_d.h"
77 const char *
progname,
bool echo,
bool quiet);
81 bool analyze_in_stages,
84 const char *
progname,
bool echo,
bool quiet);
99#define ANALYZE_NO_STAGE -1
100#define ANALYZE_NUM_STAGES 3
106 static struct option long_options[] = {
145 const char *
dbname = NULL;
146 const char *maintenance_db = NULL;
155 bool analyze_in_stages =
false;
157 int concurrentCons = 1;
161 memset(&vacopts, 0,
sizeof(vacopts));
176 while ((
c =
getopt_long(argc, argv,
"ad:efFh:j:n:N:p:P:qt:U:vwWzZ", long_options, &optindex)) != -1)
309 pg_log_error(
"too many command-line arguments (first is \"%s\")",
324 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
327 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
330 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
331 "disable-page-skipping");
333 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
336 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
337 "force-index-cleanup");
339 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
342 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
345 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
354 pg_fatal(
"cannot use the \"%s\" option when performing only analyze",
357 pg_fatal(
"cannot use the \"%s\" option when performing full vacuum",
363 pg_fatal(
"cannot use the \"%s\" option with the \"%s\" option",
364 "no-index-cleanup",
"force-index-cleanup");
371 pg_fatal(
"cannot use the \"%s\" option with the \"%s\" option",
372 "buffer-usage-limit",
"full");
379 pg_fatal(
"cannot use the \"%s\" option without \"%s\" or \"%s\"",
380 "missing-stats-only",
"analyze-only",
"analyze-in-stages");
392 if (tbl_count && (concurrentCons > tbl_count))
393 concurrentCons = tbl_count;
397 cparams.
dbname = maintenance_db;
409 if (getenv(
"PGDATABASE"))
410 dbname = getenv(
"PGDATABASE");
411 else if (getenv(
"PGUSER"))
412 dbname = getenv(
"PGUSER");
419 if (analyze_in_stages)
453 pg_fatal(
"cannot vacuum all databases and a specific one at the same time");
457 pg_fatal(
"cannot vacuum all tables in schema(s) and specific table(s) at the same time");
461 pg_fatal(
"cannot vacuum specific table(s) and exclude schema(s) at the same time");
465 pg_fatal(
"cannot vacuum all tables in schema(s) and exclude schema(s) at the same time");
529 const char *
progname,
bool echo,
bool quiet)
539 const char *stage_commands[] = {
540 "SET default_statistics_target=1; SET vacuum_cost_delay=0;",
541 "SET default_statistics_target=10; RESET vacuum_cost_delay;",
542 "RESET default_statistics_target;"
544 const char *stage_messages[] = {
545 gettext_noop(
"Generating minimal optimizer statistics (1 target)"),
546 gettext_noop(
"Generating medium optimizer statistics (10 targets)"),
547 gettext_noop(
"Generating default (full) optimizer statistics")
558 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
559 "disable-page-skipping",
"9.6");
565 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
566 "no-index-cleanup",
"12");
572 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
573 "force-index-cleanup",
"12");
579 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
580 "no-truncate",
"12");
586 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
587 "no-process-main",
"16");
593 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
594 "no-process-toast",
"14");
600 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
601 "skip-locked",
"12");
607 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
608 "--min-xid-age",
"9.6");
614 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
615 "--min-mxid-age",
"9.6");
621 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
628 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
629 "--buffer-usage-limit",
"16");
635 pg_fatal(
"cannot use the \"%s\" option on server versions older than PostgreSQL %s",
636 "--missing-stats-only",
"15");
645 printf(
_(
"%s: processing database \"%s\": %s\n"),
648 printf(
_(
"%s: vacuuming database \"%s\"\n"),
658 if (found_objs && *found_objs)
671 for (cell = ret ? ret->
head : NULL; cell; cell = cell->
next)
684 if (concurrentCons > ntups)
685 concurrentCons = ntups;
686 if (concurrentCons <= 0)
698 initcmd = stage_commands[stage];
715 const char *tabname = cell->
val;
743 }
while (cell != NULL);
754 const char *cmd =
"VACUUM (ONLY_DATABASE_STATS);";
801 bool objects_listed =
false;
804 for (cell = objects ? objects->
head : NULL; cell; cell = cell->
next)
806 char *just_table = NULL;
807 const char *just_columns = NULL;
812 "WITH listed_objects (object_oid, column_list) "
814 objects_listed =
true;
834 &just_table, &just_columns);
840 if (just_columns && just_columns[0] !=
'\0')
860 " FROM pg_catalog.pg_class c\n"
861 " JOIN pg_catalog.pg_namespace ns"
862 " ON c.relnamespace OPERATOR(pg_catalog.=) ns.oid\n"
863 " CROSS JOIN LATERAL (SELECT c.relkind IN ("
865 CppAsString2(RELKIND_PARTITIONED_INDEX)
")) as p (inherited)\n"
866 " LEFT JOIN pg_catalog.pg_class t"
867 " ON c.reltoastrelid OPERATOR(pg_catalog.=) t.oid\n");
876 " ON listed_objects.object_oid"
877 " OPERATOR(pg_catalog.=) ");
889 " WHERE c.relpersistence OPERATOR(pg_catalog.!=) "
900 " AND listed_objects.object_oid IS NULL\n");
903 " AND listed_objects.object_oid IS NOT NULL\n");
915 " AND c.relkind OPERATOR(pg_catalog.=) ANY (array["
930 " AND GREATEST(pg_catalog.age(c.relfrozenxid),"
931 " pg_catalog.age(t.relfrozenxid)) "
932 " OPERATOR(pg_catalog.>=) '%d'::pg_catalog.int4\n"
933 " AND c.relfrozenxid OPERATOR(pg_catalog.!=)"
934 " '0'::pg_catalog.xid\n",
941 " AND GREATEST(pg_catalog.mxid_age(c.relminmxid),"
942 " pg_catalog.mxid_age(t.relminmxid)) OPERATOR(pg_catalog.>=)"
943 " '%d'::pg_catalog.int4\n"
944 " AND c.relminmxid OPERATOR(pg_catalog.!=)"
945 " '0'::pg_catalog.xid\n",
955 " EXISTS (SELECT NULL FROM pg_catalog.pg_attribute a\n"
956 " WHERE a.attrelid OPERATOR(pg_catalog.=) c.oid\n"
957 " AND c.reltuples OPERATOR(pg_catalog.!=) 0::pg_catalog.float4\n"
958 " AND a.attnum OPERATOR(pg_catalog.>) 0::pg_catalog.int2\n"
959 " AND NOT a.attisdropped\n"
960 " AND a.attstattarget IS DISTINCT FROM 0::pg_catalog.int2\n"
961 " AND NOT EXISTS (SELECT NULL FROM pg_catalog.pg_statistic s\n"
962 " WHERE s.starelid OPERATOR(pg_catalog.=) a.attrelid\n"
963 " AND s.staattnum OPERATOR(pg_catalog.=) a.attnum\n"
964 " AND s.stainherit OPERATOR(pg_catalog.=) p.inherited))\n");
968 " OR EXISTS (SELECT NULL FROM pg_catalog.pg_statistic_ext e\n"
969 " WHERE e.stxrelid OPERATOR(pg_catalog.=) c.oid\n"
970 " AND c.reltuples OPERATOR(pg_catalog.!=) 0::pg_catalog.float4\n"
971 " AND e.stxstattarget IS DISTINCT FROM 0::pg_catalog.int2\n"
972 " AND NOT EXISTS (SELECT NULL FROM pg_catalog.pg_statistic_ext_data d\n"
973 " WHERE d.stxoid OPERATOR(pg_catalog.=) e.oid\n"
974 " AND d.stxdinherit OPERATOR(pg_catalog.=) p.inherited))\n");
978 " OR EXISTS (SELECT NULL FROM pg_catalog.pg_attribute a\n"
979 " JOIN pg_catalog.pg_index i"
980 " ON i.indexrelid OPERATOR(pg_catalog.=) a.attrelid\n"
981 " WHERE i.indrelid OPERATOR(pg_catalog.=) c.oid\n"
982 " AND c.reltuples OPERATOR(pg_catalog.!=) 0::pg_catalog.float4\n"
983 " AND i.indkey[a.attnum OPERATOR(pg_catalog.-) 1::pg_catalog.int2]"
984 " OPERATOR(pg_catalog.=) 0::pg_catalog.int2\n"
985 " AND a.attnum OPERATOR(pg_catalog.>) 0::pg_catalog.int2\n"
986 " AND NOT a.attisdropped\n"
987 " AND a.attstattarget IS DISTINCT FROM 0::pg_catalog.int2\n"
988 " AND NOT EXISTS (SELECT NULL FROM pg_catalog.pg_statistic s\n"
989 " WHERE s.starelid OPERATOR(pg_catalog.=) a.attrelid\n"
990 " AND s.staattnum OPERATOR(pg_catalog.=) a.attnum\n"
991 " AND s.stainherit OPERATOR(pg_catalog.=) p.inherited))\n");
995 " OR EXISTS (SELECT NULL FROM pg_catalog.pg_attribute a\n"
996 " WHERE a.attrelid OPERATOR(pg_catalog.=) c.oid\n"
997 " AND c.reltuples OPERATOR(pg_catalog.!=) 0::pg_catalog.float4\n"
998 " AND a.attnum OPERATOR(pg_catalog.>) 0::pg_catalog.int2\n"
999 " AND NOT a.attisdropped\n"
1000 " AND a.attstattarget IS DISTINCT FROM 0::pg_catalog.int2\n"
1001 " AND c.relhassubclass\n"
1002 " AND NOT p.inherited\n"
1003 " AND EXISTS (SELECT NULL FROM pg_catalog.pg_inherits h\n"
1004 " WHERE h.inhparent OPERATOR(pg_catalog.=) c.oid)\n"
1005 " AND NOT EXISTS (SELECT NULL FROM pg_catalog.pg_statistic s\n"
1006 " WHERE s.starelid OPERATOR(pg_catalog.=) a.attrelid\n"
1007 " AND s.staattnum OPERATOR(pg_catalog.=) a.attnum\n"
1008 " AND s.stainherit))\n");
1012 " OR EXISTS (SELECT NULL FROM pg_catalog.pg_statistic_ext e\n"
1013 " WHERE e.stxrelid OPERATOR(pg_catalog.=) c.oid\n"
1014 " AND c.reltuples OPERATOR(pg_catalog.!=) 0::pg_catalog.float4\n"
1015 " AND e.stxstattarget IS DISTINCT FROM 0::pg_catalog.int2\n"
1016 " AND c.relhassubclass\n"
1017 " AND NOT p.inherited\n"
1018 " AND EXISTS (SELECT NULL FROM pg_catalog.pg_inherits h\n"
1019 " WHERE h.inhparent OPERATOR(pg_catalog.=) c.oid)\n"
1020 " AND NOT EXISTS (SELECT NULL FROM pg_catalog.pg_statistic_ext_data d\n"
1021 " WHERE d.stxoid OPERATOR(pg_catalog.=) e.oid\n"
1022 " AND d.stxdinherit))\n");
1071 bool analyze_in_stages,
1074 const char *
progname,
bool echo,
bool quiet)
1083 "SELECT datname FROM pg_database WHERE datallowconn AND datconnlimit <> -2 ORDER BY 1;",
1087 if (analyze_in_stages)
1145 const char *paren =
" (";
1146 const char *
comma =
", ";
1147 const char *sep = paren;
1156 if (serverVersion >= 110000)
1161 Assert(serverVersion >= 120000);
1172 Assert(serverVersion >= 160000);
1191 if (serverVersion >= 90000)
1196 Assert(serverVersion >= 90600);
1203 Assert(serverVersion >= 120000);
1211 Assert(serverVersion >= 120000);
1219 Assert(serverVersion >= 120000);
1226 Assert(serverVersion >= 160000);
1233 Assert(serverVersion >= 140000);
1240 Assert(serverVersion >= 160000);
1247 Assert(serverVersion >= 120000);
1274 Assert(serverVersion >= 130000);
1281 Assert(serverVersion >= 160000);
1325 pg_log_error(
"vacuuming of table \"%s\" in database \"%s\" failed: %s",
1328 pg_log_error(
"vacuuming of database \"%s\" failed: %s",
1336 printf(
_(
"%s cleans and analyzes a PostgreSQL database.\n\n"),
progname);
1340 printf(
_(
" -a, --all vacuum all databases\n"));
1341 printf(
_(
" --buffer-usage-limit=SIZE size of ring buffer used for vacuum\n"));
1342 printf(
_(
" -d, --dbname=DBNAME database to vacuum\n"));
1343 printf(
_(
" --disable-page-skipping disable all page-skipping behavior\n"));
1344 printf(
_(
" -e, --echo show the commands being sent to the server\n"));
1345 printf(
_(
" -f, --full do full vacuuming\n"));
1346 printf(
_(
" -F, --freeze freeze row transaction information\n"));
1347 printf(
_(
" --force-index-cleanup always remove index entries that point to dead tuples\n"));
1348 printf(
_(
" -j, --jobs=NUM use this many concurrent connections to vacuum\n"));
1349 printf(
_(
" --min-mxid-age=MXID_AGE minimum multixact ID age of tables to vacuum\n"));
1350 printf(
_(
" --min-xid-age=XID_AGE minimum transaction ID age of tables to vacuum\n"));
1351 printf(
_(
" --missing-stats-only only analyze relations with missing statistics\n"));
1352 printf(
_(
" --no-index-cleanup don't remove index entries that point to dead tuples\n"));
1353 printf(
_(
" --no-process-main skip the main relation\n"));
1354 printf(
_(
" --no-process-toast skip the TOAST table associated with the table to vacuum\n"));
1355 printf(
_(
" --no-truncate don't truncate empty pages at the end of the table\n"));
1356 printf(
_(
" -n, --schema=SCHEMA vacuum tables in the specified schema(s) only\n"));
1357 printf(
_(
" -N, --exclude-schema=SCHEMA do not vacuum tables in the specified schema(s)\n"));
1358 printf(
_(
" -P, --parallel=PARALLEL_WORKERS use this many background workers for vacuum, if available\n"));
1359 printf(
_(
" -q, --quiet don't write any messages\n"));
1360 printf(
_(
" --skip-locked skip relations that cannot be immediately locked\n"));
1361 printf(
_(
" -t, --table='TABLE[(COLUMNS)]' vacuum specific table(s) only\n"));
1362 printf(
_(
" -v, --verbose write a lot of output\n"));
1363 printf(
_(
" -V, --version output version information, then exit\n"));
1364 printf(
_(
" -z, --analyze update optimizer statistics\n"));
1365 printf(
_(
" -Z, --analyze-only only update optimizer statistics; no vacuum\n"));
1366 printf(
_(
" --analyze-in-stages only update optimizer statistics, in multiple\n"
1367 " stages for faster results; no vacuum\n"));
1368 printf(
_(
" -?, --help show this help, then exit\n"));
1369 printf(
_(
"\nConnection options:\n"));
1370 printf(
_(
" -h, --host=HOSTNAME database server host or socket directory\n"));
1371 printf(
_(
" -p, --port=PORT database server port\n"));
1372 printf(
_(
" -U, --username=USERNAME user name to connect as\n"));
1373 printf(
_(
" -w, --no-password never prompt for password\n"));
1374 printf(
_(
" -W, --password force password prompt\n"));
1375 printf(
_(
" --maintenance-db=DBNAME alternate maintenance database\n"));
1376 printf(
_(
"\nRead the description of the SQL command VACUUM for details.\n"));
1377 printf(
_(
"\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1378 printf(
_(
"%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
void splitTableColumnsSpec(const char *spec, int encoding, char **table, const char **columns)
#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)
PGconn * connectDatabase(const ConnParams *cparams, const char *progname, bool echo, bool fail_ok, bool allow_password_reuse)
PGresult * executeQuery(PGconn *conn, const char *query)
int PQserverVersion(const PGconn *conn)
char * PQdb(const PGconn *conn)
int PQclientEncoding(const PGconn *conn)
void PQfinish(PGconn *conn)
char * PQerrorMessage(const PGconn *conn)
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
void PQclear(PGresult *res)
int PQntuples(const PGresult *res)
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
Assert(PointerIsAligned(start, uint64))
void pg_logging_init(const char *argv0)
#define pg_log_error(...)
#define pg_log_error_hint(...)
void * palloc0(Size size)
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)
ParallelSlotArray * ParallelSlotsSetup(int numslots, ConnParams *cparams, const char *progname, bool echo, const char *initcmd)
bool ParallelSlotsWaitCompletion(ParallelSlotArray *sa)
bool TableCommandResultHandler(PGresult *res, PGconn *conn, void *context)
ParallelSlot * ParallelSlotsGetIdle(ParallelSlotArray *sa, const char *dbname)
void ParallelSlotsTerminate(ParallelSlotArray *sa)
void ParallelSlotsAdoptConn(ParallelSlotArray *sa, PGconn *conn)
static void ParallelSlotSetHandler(ParallelSlot *slot, ParallelSlotResultHandler handler, void *context)
static void executeCommand(PGconn *conn, const char *query)
PGDLLIMPORT char * optarg
static const struct lconv_member_info table[]
char * escape_single_quotes_ascii(const char *src)
const char * get_progname(const char *argv0)
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)
const char * fmtQualifiedIdEnc(const char *schema, const char *id, int encoding)
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
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)
static SimpleStringList * retrieve_objects(PGconn *conn, vacuumingOptions *vacopts, SimpleStringList *objects, bool echo)
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 void vacuum_one_database(ConnParams *cparams, vacuumingOptions *vacopts, int stage, SimpleStringList *objects, SimpleStringList **found_objs, int concurrentCons, const char *progname, bool echo, bool quiet)
static char * escape_quotes(const char *src)
static VacObjFilter objfilter