PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
vacuumdb.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * vacuumdb
4 *
5 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
7 *
8 * src/bin/scripts/vacuumdb.c
9 *
10 *-------------------------------------------------------------------------
11 */
12
13#include "postgres_fe.h"
14
15#include <limits.h>
16
17#include "common.h"
18#include "common/logging.h"
20#include "vacuuming.h"
21
22static void help(const char *progname);
23static void check_objfilter(bits32 objfilter);
24
25
26int
27main(int argc, char *argv[])
28{
29 static struct option long_options[] = {
30 {"host", required_argument, NULL, 'h'},
31 {"port", required_argument, NULL, 'p'},
32 {"username", required_argument, NULL, 'U'},
33 {"no-password", no_argument, NULL, 'w'},
34 {"password", no_argument, NULL, 'W'},
35 {"echo", no_argument, NULL, 'e'},
36 {"quiet", no_argument, NULL, 'q'},
37 {"dbname", required_argument, NULL, 'd'},
38 {"analyze", no_argument, NULL, 'z'},
39 {"analyze-only", no_argument, NULL, 'Z'},
40 {"freeze", no_argument, NULL, 'F'},
41 {"all", no_argument, NULL, 'a'},
42 {"table", required_argument, NULL, 't'},
43 {"full", no_argument, NULL, 'f'},
44 {"verbose", no_argument, NULL, 'v'},
45 {"jobs", required_argument, NULL, 'j'},
46 {"parallel", required_argument, NULL, 'P'},
47 {"schema", required_argument, NULL, 'n'},
48 {"exclude-schema", required_argument, NULL, 'N'},
49 {"maintenance-db", required_argument, NULL, 2},
50 {"analyze-in-stages", no_argument, NULL, 3},
51 {"disable-page-skipping", no_argument, NULL, 4},
52 {"skip-locked", no_argument, NULL, 5},
53 {"min-xid-age", required_argument, NULL, 6},
54 {"min-mxid-age", required_argument, NULL, 7},
55 {"no-index-cleanup", no_argument, NULL, 8},
56 {"force-index-cleanup", no_argument, NULL, 9},
57 {"no-truncate", no_argument, NULL, 10},
58 {"no-process-toast", no_argument, NULL, 11},
59 {"no-process-main", no_argument, NULL, 12},
60 {"buffer-usage-limit", required_argument, NULL, 13},
61 {"missing-stats-only", no_argument, NULL, 14},
62 {NULL, 0, NULL, 0}
63 };
64
65 const char *progname;
66 int optindex;
67 int c;
68 const char *dbname = NULL;
69 const char *maintenance_db = NULL;
70 ConnParams cparams;
71 bool echo = false;
72 bool quiet = false;
73 vacuumingOptions vacopts;
74 SimpleStringList objects = {NULL, NULL};
75 int concurrentCons = 1;
76 unsigned int tbl_count = 0;
77 int ret;
78
79 /* initialize options */
80 memset(&vacopts, 0, sizeof(vacopts));
81 vacopts.objfilter = 0; /* no filter */
82 vacopts.parallel_workers = -1;
83 vacopts.buffer_usage_limit = NULL;
84 vacopts.no_index_cleanup = false;
85 vacopts.force_index_cleanup = false;
86 vacopts.do_truncate = true;
87 vacopts.process_main = true;
88 vacopts.process_toast = true;
89
90 /* the same for connection parameters */
91 memset(&cparams, 0, sizeof(cparams));
93
94 pg_logging_init(argv[0]);
95 progname = get_progname(argv[0]);
96 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
97
98 handle_help_version_opts(argc, argv, "vacuumdb", help);
99
100 while ((c = getopt_long(argc, argv, "ad:efFh:j:n:N:p:P:qt:U:vwWzZ",
101 long_options, &optindex)) != -1)
102 {
103 switch (c)
104 {
105 case 'a':
106 vacopts.objfilter |= OBJFILTER_ALL_DBS;
107 break;
108 case 'd':
109 vacopts.objfilter |= OBJFILTER_DATABASE;
111 break;
112 case 'e':
113 echo = true;
114 break;
115 case 'f':
116 vacopts.full = true;
117 break;
118 case 'F':
119 vacopts.freeze = true;
120 break;
121 case 'h':
122 cparams.pghost = pg_strdup(optarg);
123 break;
124 case 'j':
125 if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
126 &concurrentCons))
127 exit(1);
128 break;
129 case 'n':
130 vacopts.objfilter |= OBJFILTER_SCHEMA;
132 break;
133 case 'N':
136 break;
137 case 'p':
138 cparams.pgport = pg_strdup(optarg);
139 break;
140 case 'P':
141 if (!option_parse_int(optarg, "-P/--parallel", 0, INT_MAX,
142 &vacopts.parallel_workers))
143 exit(1);
144 break;
145 case 'q':
146 quiet = true;
147 break;
148 case 't':
149 vacopts.objfilter |= OBJFILTER_TABLE;
151 tbl_count++;
152 break;
153 case 'U':
154 cparams.pguser = pg_strdup(optarg);
155 break;
156 case 'v':
157 vacopts.verbose = true;
158 break;
159 case 'w':
160 cparams.prompt_password = TRI_NO;
161 break;
162 case 'W':
163 cparams.prompt_password = TRI_YES;
164 break;
165 case 'z':
166 vacopts.and_analyze = true;
167 break;
168 case 'Z':
169 /* if analyze-in-stages is given, don't override it */
170 if (vacopts.mode != MODE_ANALYZE_IN_STAGES)
171 vacopts.mode = MODE_ANALYZE;
172 break;
173 case 2:
174 maintenance_db = pg_strdup(optarg);
175 break;
176 case 3:
178 break;
179 case 4:
180 vacopts.disable_page_skipping = true;
181 break;
182 case 5:
183 vacopts.skip_locked = true;
184 break;
185 case 6:
186 if (!option_parse_int(optarg, "--min-xid-age", 1, INT_MAX,
187 &vacopts.min_xid_age))
188 exit(1);
189 break;
190 case 7:
191 if (!option_parse_int(optarg, "--min-mxid-age", 1, INT_MAX,
192 &vacopts.min_mxid_age))
193 exit(1);
194 break;
195 case 8:
196 vacopts.no_index_cleanup = true;
197 break;
198 case 9:
199 vacopts.force_index_cleanup = true;
200 break;
201 case 10:
202 vacopts.do_truncate = false;
203 break;
204 case 11:
205 vacopts.process_toast = false;
206 break;
207 case 12:
208 vacopts.process_main = false;
209 break;
210 case 13:
212 break;
213 case 14:
214 vacopts.missing_stats_only = true;
215 break;
216 default:
217 /* getopt_long already emitted a complaint */
218 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
219 exit(1);
220 }
221 }
222
223 /*
224 * Non-option argument specifies database name as long as it wasn't
225 * already specified with -d / --dbname
226 */
227 if (optind < argc && dbname == NULL)
228 {
229 vacopts.objfilter |= OBJFILTER_DATABASE;
230 dbname = argv[optind];
231 optind++;
232 }
233
234 if (optind < argc)
235 {
236 pg_log_error("too many command-line arguments (first is \"%s\")",
237 argv[optind]);
238 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
239 exit(1);
240 }
241
242 /*
243 * Validate the combination of filters specified in the command-line
244 * options.
245 */
246 check_objfilter(vacopts.objfilter);
247
248 if (vacopts.mode == MODE_ANALYZE ||
249 vacopts.mode == MODE_ANALYZE_IN_STAGES)
250 {
251 if (vacopts.full)
252 pg_fatal("cannot use the \"%s\" option when performing only analyze",
253 "full");
254 if (vacopts.freeze)
255 pg_fatal("cannot use the \"%s\" option when performing only analyze",
256 "freeze");
257 if (vacopts.disable_page_skipping)
258 pg_fatal("cannot use the \"%s\" option when performing only analyze",
259 "disable-page-skipping");
260 if (vacopts.no_index_cleanup)
261 pg_fatal("cannot use the \"%s\" option when performing only analyze",
262 "no-index-cleanup");
263 if (vacopts.force_index_cleanup)
264 pg_fatal("cannot use the \"%s\" option when performing only analyze",
265 "force-index-cleanup");
266 if (!vacopts.do_truncate)
267 pg_fatal("cannot use the \"%s\" option when performing only analyze",
268 "no-truncate");
269 if (!vacopts.process_main)
270 pg_fatal("cannot use the \"%s\" option when performing only analyze",
271 "no-process-main");
272 if (!vacopts.process_toast)
273 pg_fatal("cannot use the \"%s\" option when performing only analyze",
274 "no-process-toast");
275 /* allow 'and_analyze' with 'analyze_only' */
276 }
277
278 /* Prohibit full and analyze_only options with parallel option */
279 if (vacopts.parallel_workers >= 0)
280 {
281 if (vacopts.mode == MODE_ANALYZE ||
282 vacopts.mode == MODE_ANALYZE_IN_STAGES)
283 pg_fatal("cannot use the \"%s\" option when performing only analyze",
284 "parallel");
285 if (vacopts.full)
286 pg_fatal("cannot use the \"%s\" option when performing full vacuum",
287 "parallel");
288 }
289
290 /* Prohibit --no-index-cleanup and --force-index-cleanup together */
291 if (vacopts.no_index_cleanup && vacopts.force_index_cleanup)
292 pg_fatal("cannot use the \"%s\" option with the \"%s\" option",
293 "no-index-cleanup", "force-index-cleanup");
294
295 /*
296 * buffer-usage-limit is not allowed with VACUUM FULL unless ANALYZE is
297 * included too.
298 */
299 if (vacopts.buffer_usage_limit && vacopts.full && !vacopts.and_analyze)
300 pg_fatal("cannot use the \"%s\" option with the \"%s\" option",
301 "buffer-usage-limit", "full");
302
303 /*
304 * Prohibit --missing-stats-only without --analyze-only or
305 * --analyze-in-stages.
306 */
307 if (vacopts.missing_stats_only && (vacopts.mode != MODE_ANALYZE &&
308 vacopts.mode != MODE_ANALYZE_IN_STAGES))
309 pg_fatal("cannot use the \"%s\" option without \"%s\" or \"%s\"",
310 "missing-stats-only", "analyze-only", "analyze-in-stages");
311
312 ret = vacuuming_main(&cparams, dbname, maintenance_db, &vacopts,
313 &objects, tbl_count,
314 concurrentCons,
315 progname, echo, quiet);
316 exit(ret);
317}
318
319/*
320 * Verify that the filters used at command line are compatible.
321 */
322void
324{
325 if ((objfilter & OBJFILTER_ALL_DBS) &&
326 (objfilter & OBJFILTER_DATABASE))
327 pg_fatal("cannot vacuum all databases and a specific one at the same time");
328
329 if ((objfilter & OBJFILTER_TABLE) &&
330 (objfilter & OBJFILTER_SCHEMA))
331 pg_fatal("cannot vacuum all tables in schema(s) and specific table(s) at the same time");
332
333 if ((objfilter & OBJFILTER_TABLE) &&
334 (objfilter & OBJFILTER_SCHEMA_EXCLUDE))
335 pg_fatal("cannot vacuum specific table(s) and exclude schema(s) at the same time");
336
337 if ((objfilter & OBJFILTER_SCHEMA) &&
338 (objfilter & OBJFILTER_SCHEMA_EXCLUDE))
339 pg_fatal("cannot vacuum all tables in schema(s) and exclude schema(s) at the same time");
340}
341
342
343static void
344help(const char *progname)
345{
346 printf(_("%s cleans and analyzes a PostgreSQL database.\n\n"), progname);
347 printf(_("Usage:\n"));
348 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
349 printf(_("\nOptions:\n"));
350 printf(_(" -a, --all vacuum all databases\n"));
351 printf(_(" --buffer-usage-limit=SIZE size of ring buffer used for vacuum\n"));
352 printf(_(" -d, --dbname=DBNAME database to vacuum\n"));
353 printf(_(" --disable-page-skipping disable all page-skipping behavior\n"));
354 printf(_(" -e, --echo show the commands being sent to the server\n"));
355 printf(_(" -f, --full do full vacuuming\n"));
356 printf(_(" -F, --freeze freeze row transaction information\n"));
357 printf(_(" --force-index-cleanup always remove index entries that point to dead tuples\n"));
358 printf(_(" -j, --jobs=NUM use this many concurrent connections to vacuum\n"));
359 printf(_(" --min-mxid-age=MXID_AGE minimum multixact ID age of tables to vacuum\n"));
360 printf(_(" --min-xid-age=XID_AGE minimum transaction ID age of tables to vacuum\n"));
361 printf(_(" --missing-stats-only only analyze relations with missing statistics\n"));
362 printf(_(" --no-index-cleanup don't remove index entries that point to dead tuples\n"));
363 printf(_(" --no-process-main skip the main relation\n"));
364 printf(_(" --no-process-toast skip the TOAST table associated with the table to vacuum\n"));
365 printf(_(" --no-truncate don't truncate empty pages at the end of the table\n"));
366 printf(_(" -n, --schema=SCHEMA vacuum tables in the specified schema(s) only\n"));
367 printf(_(" -N, --exclude-schema=SCHEMA do not vacuum tables in the specified schema(s)\n"));
368 printf(_(" -P, --parallel=PARALLEL_WORKERS use this many background workers for vacuum, if available\n"));
369 printf(_(" -q, --quiet don't write any messages\n"));
370 printf(_(" --skip-locked skip relations that cannot be immediately locked\n"));
371 printf(_(" -t, --table='TABLE[(COLUMNS)]' vacuum specific table(s) only\n"));
372 printf(_(" -v, --verbose write a lot of output\n"));
373 printf(_(" -V, --version output version information, then exit\n"));
374 printf(_(" -z, --analyze update optimizer statistics\n"));
375 printf(_(" -Z, --analyze-only only update optimizer statistics; no vacuum\n"));
376 printf(_(" --analyze-in-stages only update optimizer statistics, in multiple\n"
377 " stages for faster results; no vacuum\n"));
378 printf(_(" -?, --help show this help, then exit\n"));
379 printf(_("\nConnection options:\n"));
380 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
381 printf(_(" -p, --port=PORT database server port\n"));
382 printf(_(" -U, --username=USERNAME user name to connect as\n"));
383 printf(_(" -w, --no-password never prompt for password\n"));
384 printf(_(" -W, --password force password prompt\n"));
385 printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
386 printf(_("\nRead the description of the SQL command VACUUM for details.\n"));
387 printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
388 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
389}
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1217
uint32 bits32
Definition: c.h:551
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:430
#define _(x)
Definition: elog.c:91
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define no_argument
Definition: getopt_long.h:25
#define required_argument
Definition: getopt_long.h:26
static char * escape_quotes(const char *src)
Definition: initdb.c:406
void pg_logging_init(const char *argv0)
Definition: logging.c:83
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_error_hint(...)
Definition: logging.h:112
const char * progname
Definition: main.c:44
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
Definition: option_utils.c:50
void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
Definition: option_utils.c:24
#define pg_fatal(...)
PGDLLIMPORT int optind
Definition: getopt.c:51
PGDLLIMPORT char * optarg
Definition: getopt.c:53
const char * get_progname(const char *argv0)
Definition: path.c:652
#define printf(...)
Definition: port.h:245
char * c
void simple_string_list_append(SimpleStringList *list, const char *val)
Definition: simple_list.c:63
char * dbname
Definition: streamutil.c:49
const char * pguser
Definition: connect_utils.h:31
char * pgport
Definition: pg_backup.h:87
char * pghost
Definition: pg_backup.h:88
enum trivalue prompt_password
Definition: connect_utils.h:32
bool force_index_cleanup
Definition: vacuuming.h:47
RunMode mode
Definition: vacuuming.h:34
bool no_index_cleanup
Definition: vacuuming.h:46
bits32 objfilter
Definition: vacuuming.h:35
int parallel_workers
Definition: vacuuming.h:44
bool disable_page_skipping
Definition: vacuuming.h:40
bool process_toast
Definition: vacuuming.h:50
char * buffer_usage_limit
Definition: vacuuming.h:52
bool missing_stats_only
Definition: vacuuming.h:53
int main(int argc, char *argv[])
Definition: vacuumdb.c:27
static void help(const char *progname)
Definition: vacuumdb.c:344
static void check_objfilter(bits32 objfilter)
Definition: vacuumdb.c:323
int vacuuming_main(ConnParams *cparams, const char *dbname, const char *maintenance_db, vacuumingOptions *vacopts, SimpleStringList *objects, unsigned int tbl_count, int concurrentCons, const char *progname, bool echo, bool quiet)
Definition: vacuuming.c:55
#define OBJFILTER_ALL_DBS
Definition: vacuuming.h:57
@ MODE_ANALYZE
Definition: vacuuming.h:23
@ MODE_ANALYZE_IN_STAGES
Definition: vacuuming.h:24
#define OBJFILTER_SCHEMA_EXCLUDE
Definition: vacuuming.h:61
#define OBJFILTER_TABLE
Definition: vacuuming.h:59
#define OBJFILTER_DATABASE
Definition: vacuuming.h:58
#define OBJFILTER_SCHEMA
Definition: vacuuming.h:60
@ TRI_YES
Definition: vacuumlo.c:38
@ TRI_DEFAULT
Definition: vacuumlo.c:36
@ TRI_NO
Definition: vacuumlo.c:37