TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * vacuumdb
4 : *
5 : * Portions Copyright (c) 1996-2023, 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 "catalog/pg_class_d.h"
18 : #include "common.h"
19 : #include "common/connect.h"
20 : #include "common/logging.h"
21 : #include "fe_utils/cancel.h"
22 : #include "fe_utils/option_utils.h"
23 : #include "fe_utils/parallel_slot.h"
24 : #include "fe_utils/query_utils.h"
25 : #include "fe_utils/simple_list.h"
26 : #include "fe_utils/string_utils.h"
27 :
28 :
29 : /* vacuum options controlled by user flags */
30 : typedef struct vacuumingOptions
31 : {
32 : bool analyze_only;
33 : bool verbose;
34 : bool and_analyze;
35 : bool full;
36 : bool freeze;
37 : bool disable_page_skipping;
38 : bool skip_locked;
39 : int min_xid_age;
40 : int min_mxid_age;
41 : int parallel_workers; /* >= 0 indicates user specified the
42 : * parallel degree, otherwise -1 */
43 : bool no_index_cleanup;
44 : bool force_index_cleanup;
45 : bool do_truncate;
46 : bool process_main;
47 : bool process_toast;
48 : bool skip_database_stats;
49 : char *buffer_usage_limit;
50 : } vacuumingOptions;
51 :
52 : /* object filter options */
53 : typedef enum
54 : {
55 : OBJFILTER_NONE = 0, /* no filter used */
56 : OBJFILTER_ALL_DBS = (1 << 0), /* -a | --all */
57 : OBJFILTER_DATABASE = (1 << 1), /* -d | --dbname */
58 : OBJFILTER_TABLE = (1 << 2), /* -t | --table */
59 : OBJFILTER_SCHEMA = (1 << 3), /* -n | --schema */
60 : OBJFILTER_SCHEMA_EXCLUDE = (1 << 4) /* -N | --exclude-schema */
61 : } VacObjFilter;
62 :
63 : VacObjFilter objfilter = OBJFILTER_NONE;
64 :
65 : static void vacuum_one_database(ConnParams *cparams,
66 : vacuumingOptions *vacopts,
67 : int stage,
68 : SimpleStringList *objects,
69 : int concurrentCons,
70 : const char *progname, bool echo, bool quiet);
71 :
72 : static void vacuum_all_databases(ConnParams *cparams,
73 : vacuumingOptions *vacopts,
74 : bool analyze_in_stages,
75 : int concurrentCons,
76 : const char *progname, bool echo, bool quiet);
77 :
78 : static void prepare_vacuum_command(PQExpBuffer sql, int serverVersion,
79 : vacuumingOptions *vacopts, const char *table);
80 :
81 : static void run_vacuum_command(PGconn *conn, const char *sql, bool echo,
82 : const char *table);
83 :
84 : static void help(const char *progname);
85 :
86 : void check_objfilter(void);
87 :
88 : /* For analyze-in-stages mode */
89 : #define ANALYZE_NO_STAGE -1
90 : #define ANALYZE_NUM_STAGES 3
91 :
92 :
93 : int
94 GIC 54 : main(int argc, char *argv[])
95 : {
96 : static struct option long_options[] = {
97 : {"host", required_argument, NULL, 'h'},
98 : {"port", required_argument, NULL, 'p'},
99 : {"username", required_argument, NULL, 'U'},
100 : {"no-password", no_argument, NULL, 'w'},
101 : {"password", no_argument, NULL, 'W'},
102 : {"echo", no_argument, NULL, 'e'},
103 : {"quiet", no_argument, NULL, 'q'},
104 : {"dbname", required_argument, NULL, 'd'},
105 : {"analyze", no_argument, NULL, 'z'},
106 : {"analyze-only", no_argument, NULL, 'Z'},
107 : {"freeze", no_argument, NULL, 'F'},
108 : {"all", no_argument, NULL, 'a'},
109 : {"table", required_argument, NULL, 't'},
110 : {"full", no_argument, NULL, 'f'},
111 ECB : {"verbose", no_argument, NULL, 'v'},
112 : {"jobs", required_argument, NULL, 'j'},
113 : {"parallel", required_argument, NULL, 'P'},
114 : {"schema", required_argument, NULL, 'n'},
115 : {"exclude-schema", required_argument, NULL, 'N'},
116 : {"maintenance-db", required_argument, NULL, 2},
117 : {"analyze-in-stages", no_argument, NULL, 3},
118 : {"disable-page-skipping", no_argument, NULL, 4},
119 : {"skip-locked", no_argument, NULL, 5},
120 : {"min-xid-age", required_argument, NULL, 6},
121 : {"min-mxid-age", required_argument, NULL, 7},
122 : {"no-index-cleanup", no_argument, NULL, 8},
123 : {"force-index-cleanup", no_argument, NULL, 9},
124 : {"no-truncate", no_argument, NULL, 10},
125 : {"no-process-toast", no_argument, NULL, 11},
126 : {"no-process-main", no_argument, NULL, 12},
127 : {"buffer-usage-limit", required_argument, NULL, 13},
128 : {NULL, 0, NULL, 0}
129 : };
130 :
131 : const char *progname;
132 : int optindex;
133 : int c;
134 GIC 54 : const char *dbname = NULL;
135 54 : const char *maintenance_db = NULL;
136 54 : char *host = NULL;
137 54 : char *port = NULL;
138 54 : char *username = NULL;
139 54 : enum trivalue prompt_password = TRI_DEFAULT;
140 : ConnParams cparams;
141 54 : bool echo = false;
142 54 : bool quiet = false;
143 : vacuumingOptions vacopts;
144 54 : bool analyze_in_stages = false;
145 GNC 54 : SimpleStringList objects = {NULL, NULL};
146 GIC 54 : int concurrentCons = 1;
147 54 : int tbl_count = 0;
148 :
149 : /* initialize options */
150 54 : memset(&vacopts, 0, sizeof(vacopts));
151 54 : vacopts.parallel_workers = -1;
152 GNC 54 : vacopts.buffer_usage_limit = NULL;
153 GIC 54 : vacopts.no_index_cleanup = false;
154 54 : vacopts.force_index_cleanup = false;
155 CBC 54 : vacopts.do_truncate = true;
156 GNC 54 : vacopts.process_main = true;
157 CBC 54 : vacopts.process_toast = true;
158 ECB :
159 CBC 54 : pg_logging_init(argv[0]);
160 54 : progname = get_progname(argv[0]);
161 54 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
162 :
163 54 : handle_help_version_opts(argc, argv, "vacuumdb", help);
164 ECB :
165 GNC 132 : while ((c = getopt_long(argc, argv, "ad:efFh:j:n:N:p:P:qt:U:vwWzZ", long_options, &optindex)) != -1)
166 ECB : {
167 CBC 86 : switch (c)
168 ECB : {
169 GNC 10 : case 'a':
170 10 : objfilter |= OBJFILTER_ALL_DBS;
171 10 : break;
172 1 : case 'd':
173 1 : objfilter |= OBJFILTER_DATABASE;
174 1 : dbname = pg_strdup(optarg);
175 1 : break;
176 1 : case 'e':
177 1 : echo = true;
178 1 : break;
179 1 : case 'f':
180 1 : vacopts.full = true;
181 1 : break;
182 2 : case 'F':
183 2 : vacopts.freeze = true;
184 2 : break;
185 CBC 2 : case 'h':
186 GIC 2 : host = pg_strdup(optarg);
187 2 : break;
188 GNC 1 : case 'j':
189 1 : if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
190 : &concurrentCons))
191 UNC 0 : exit(1);
192 GNC 1 : break;
193 4 : case 'n':
194 4 : objfilter |= OBJFILTER_SCHEMA;
195 4 : simple_string_list_append(&objects, optarg);
196 4 : break;
197 4 : case 'N':
198 4 : objfilter |= OBJFILTER_SCHEMA_EXCLUDE;
199 4 : simple_string_list_append(&objects, optarg);
200 4 : break;
201 CBC 2 : case 'p':
202 2 : port = pg_strdup(optarg);
203 2 : break;
204 GNC 3 : case 'P':
205 3 : if (!option_parse_int(optarg, "-P/--parallel", 0, INT_MAX,
206 : &vacopts.parallel_workers))
207 1 : exit(1);
208 2 : break;
209 UNC 0 : case 'q':
210 0 : quiet = true;
211 0 : break;
212 GNC 15 : case 't':
213 15 : objfilter |= OBJFILTER_TABLE;
214 15 : simple_string_list_append(&objects, optarg);
215 15 : tbl_count++;
216 15 : break;
217 CBC 2 : case 'U':
218 2 : username = pg_strdup(optarg);
219 2 : break;
220 UNC 0 : case 'v':
221 0 : vacopts.verbose = true;
222 0 : break;
223 LBC 0 : case 'w':
224 0 : prompt_password = TRI_NO;
225 UIC 0 : break;
226 LBC 0 : case 'W':
227 0 : prompt_password = TRI_YES;
228 0 : break;
229 CBC 5 : case 'z':
230 5 : vacopts.and_analyze = true;
231 5 : break;
232 14 : case 'Z':
233 14 : vacopts.analyze_only = true;
234 14 : break;
235 LBC 0 : case 2:
236 UIC 0 : maintenance_db = pg_strdup(optarg);
237 LBC 0 : break;
238 CBC 2 : case 3:
239 GBC 2 : analyze_in_stages = vacopts.analyze_only = true;
240 2 : break;
241 2 : case 4:
242 CBC 2 : vacopts.disable_page_skipping = true;
243 2 : break;
244 2 : case 5:
245 2 : vacopts.skip_locked = true;
246 2 : break;
247 2 : case 6:
248 2 : if (!option_parse_int(optarg, "--min-xid-age", 1, INT_MAX,
249 ECB : &vacopts.min_xid_age))
250 GBC 1 : exit(1);
251 1 : break;
252 2 : case 7:
253 2 : if (!option_parse_int(optarg, "--min-mxid-age", 1, INT_MAX,
254 EUB : &vacopts.min_mxid_age))
255 GBC 1 : exit(1);
256 1 : break;
257 2 : case 8:
258 2 : vacopts.no_index_cleanup = true;
259 CBC 2 : break;
260 LBC 0 : case 9:
261 0 : vacopts.force_index_cleanup = true;
262 0 : break;
263 CBC 2 : case 10:
264 2 : vacopts.do_truncate = false;
265 GBC 2 : break;
266 2 : case 11:
267 2 : vacopts.process_toast = false;
268 CBC 2 : break;
269 GNC 2 : case 12:
270 2 : vacopts.process_main = false;
271 2 : break;
272 UNC 0 : case 13:
273 0 : vacopts.buffer_usage_limit = pg_strdup(optarg);
274 0 : break;
275 CBC 1 : default:
276 ECB : /* getopt_long already emitted a complaint */
277 CBC 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
278 1 : exit(1);
279 ECB : }
280 : }
281 :
282 : /*
283 : * Non-option argument specifies database name as long as it wasn't
284 : * already specified with -d / --dbname
285 : */
286 CBC 46 : if (optind < argc && dbname == NULL)
287 ECB : {
288 GNC 37 : objfilter |= OBJFILTER_DATABASE;
289 CBC 37 : dbname = argv[optind];
290 37 : optind++;
291 : }
292 ECB :
293 CBC 46 : if (optind < argc)
294 ECB : {
295 LBC 0 : pg_log_error("too many command-line arguments (first is \"%s\")",
296 ECB : argv[optind]);
297 UBC 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
298 0 : exit(1);
299 EUB : }
300 ECB :
301 : /*
302 : * Validate the combination of filters specified in the command-line
303 : * options.
304 : */
305 GNC 46 : check_objfilter();
306 :
307 CBC 38 : if (vacopts.analyze_only)
308 ECB : {
309 CBC 16 : if (vacopts.full)
310 LBC 0 : pg_fatal("cannot use the \"%s\" option when performing only analyze",
311 ECB : "full");
312 CBC 16 : if (vacopts.freeze)
313 LBC 0 : pg_fatal("cannot use the \"%s\" option when performing only analyze",
314 ECB : "freeze");
315 GBC 16 : if (vacopts.disable_page_skipping)
316 1 : pg_fatal("cannot use the \"%s\" option when performing only analyze",
317 EUB : "disable-page-skipping");
318 CBC 15 : if (vacopts.no_index_cleanup)
319 GIC 1 : pg_fatal("cannot use the \"%s\" option when performing only analyze",
320 ECB : "no-index-cleanup");
321 CBC 14 : if (vacopts.force_index_cleanup)
322 UIC 0 : pg_fatal("cannot use the \"%s\" option when performing only analyze",
323 : "force-index-cleanup");
324 GIC 14 : if (!vacopts.do_truncate)
325 1 : pg_fatal("cannot use the \"%s\" option when performing only analyze",
326 : "no-truncate");
327 GNC 13 : if (!vacopts.process_main)
328 1 : pg_fatal("cannot use the \"%s\" option when performing only analyze",
329 : "no-process-main");
330 GIC 12 : if (!vacopts.process_toast)
331 1 : pg_fatal("cannot use the \"%s\" option when performing only analyze",
332 ECB : "no-process-toast");
333 : /* allow 'and_analyze' with 'analyze_only' */
334 : }
335 :
336 : /* Prohibit full and analyze_only options with parallel option */
337 GIC 33 : if (vacopts.parallel_workers >= 0)
338 : {
339 CBC 2 : if (vacopts.analyze_only)
340 UIC 0 : pg_fatal("cannot use the \"%s\" option when performing only analyze",
341 EUB : "parallel");
342 GIC 2 : if (vacopts.full)
343 UBC 0 : pg_fatal("cannot use the \"%s\" option when performing full vacuum",
344 EUB : "parallel");
345 : }
346 :
347 : /* Prohibit --no-index-cleanup and --force-index-cleanup together */
348 GIC 33 : if (vacopts.no_index_cleanup && vacopts.force_index_cleanup)
349 UIC 0 : pg_fatal("cannot use the \"%s\" option with the \"%s\" option",
350 : "no-index-cleanup", "force-index-cleanup");
351 ECB :
352 : /*
353 : * buffer-usage-limit is not allowed with VACUUM FULL unless ANALYZE is
354 : * included too.
355 : */
356 GNC 33 : if (vacopts.buffer_usage_limit && vacopts.full && !vacopts.and_analyze)
357 UNC 0 : pg_fatal("cannot use the \"%s\" option with the \"%s\" option",
358 : "buffer-usage-limit", "full");
359 :
360 : /* fill cparams except for dbname, which is set below */
361 CBC 33 : cparams.pghost = host;
362 GIC 33 : cparams.pgport = port;
363 CBC 33 : cparams.pguser = username;
364 GBC 33 : cparams.prompt_password = prompt_password;
365 GIC 33 : cparams.override_dbname = NULL;
366 ECB :
367 GBC 33 : setup_cancel_handler(NULL);
368 :
369 ECB : /* Avoid opening extra connections. */
370 CBC 33 : if (tbl_count && (concurrentCons > tbl_count))
371 UIC 0 : concurrentCons = tbl_count;
372 ECB :
373 GNC 33 : if (objfilter & OBJFILTER_ALL_DBS)
374 : {
375 GIC 5 : cparams.dbname = maintenance_db;
376 ECB :
377 CBC 5 : vacuum_all_databases(&cparams, &vacopts,
378 : analyze_in_stages,
379 ECB : concurrentCons,
380 : progname, echo, quiet);
381 : }
382 : else
383 : {
384 GIC 28 : if (dbname == NULL)
385 : {
386 LBC 0 : if (getenv("PGDATABASE"))
387 UIC 0 : dbname = getenv("PGDATABASE");
388 LBC 0 : else if (getenv("PGUSER"))
389 UBC 0 : dbname = getenv("PGUSER");
390 : else
391 LBC 0 : dbname = get_user_name_or_exit(progname);
392 EUB : }
393 :
394 GIC 28 : cparams.dbname = dbname;
395 :
396 28 : if (analyze_in_stages)
397 ECB : {
398 EUB : int stage;
399 :
400 GIC 4 : for (stage = 0; stage < ANALYZE_NUM_STAGES; stage++)
401 : {
402 3 : vacuum_one_database(&cparams, &vacopts,
403 : stage,
404 : &objects,
405 ECB : concurrentCons,
406 EUB : progname, echo, quiet);
407 : }
408 : }
409 : else
410 CBC 27 : vacuum_one_database(&cparams, &vacopts,
411 ECB : ANALYZE_NO_STAGE,
412 : &objects,
413 : concurrentCons,
414 : progname, echo, quiet);
415 : }
416 :
417 GIC 30 : exit(0);
418 : }
419 ECB :
420 : /*
421 : * Verify that the filters used at command line are compatible.
422 : */
423 : void
424 GNC 46 : check_objfilter(void)
425 : {
426 46 : if ((objfilter & OBJFILTER_ALL_DBS) &&
427 10 : (objfilter & OBJFILTER_DATABASE))
428 2 : pg_fatal("cannot vacuum all databases and a specific one at the same time");
429 :
430 44 : if ((objfilter & OBJFILTER_ALL_DBS) &&
431 8 : (objfilter & OBJFILTER_TABLE))
432 1 : pg_fatal("cannot vacuum specific table(s) in all databases");
433 :
434 43 : if ((objfilter & OBJFILTER_ALL_DBS) &&
435 7 : (objfilter & OBJFILTER_SCHEMA))
436 1 : pg_fatal("cannot vacuum specific schema(s) in all databases");
437 :
438 42 : if ((objfilter & OBJFILTER_ALL_DBS) &&
439 6 : (objfilter & OBJFILTER_SCHEMA_EXCLUDE))
440 1 : pg_fatal("cannot exclude specific schema(s) in all databases");
441 :
442 41 : if ((objfilter & OBJFILTER_TABLE) &&
443 12 : (objfilter & OBJFILTER_SCHEMA))
444 1 : pg_fatal("cannot vacuum all tables in schema(s) and specific table(s) at the same time");
445 :
446 40 : if ((objfilter & OBJFILTER_TABLE) &&
447 11 : (objfilter & OBJFILTER_SCHEMA_EXCLUDE))
448 1 : pg_fatal("cannot vacuum specific table(s) and exclude schema(s) at the same time");
449 :
450 39 : if ((objfilter & OBJFILTER_SCHEMA) &&
451 2 : (objfilter & OBJFILTER_SCHEMA_EXCLUDE))
452 1 : pg_fatal("cannot vacuum all tables in schema(s) and exclude schema(s) at the same time");
453 38 : }
454 :
455 EUB : /*
456 : * vacuum_one_database
457 ECB : *
458 : * Process tables in the given database. If the 'tables' list is empty,
459 : * process all tables in the database.
460 : *
461 : * Note that this function is only concerned with running exactly one stage
462 : * when in analyze-in-stages mode; caller must iterate on us if necessary.
463 : *
464 : * If concurrentCons is > 1, multiple connections are used to vacuum tables
465 : * in parallel. In this case and if the table list is empty, we first obtain
466 : * a list of tables from the database.
467 : */
468 : static void
469 GIC 49 : vacuum_one_database(ConnParams *cparams,
470 EUB : vacuumingOptions *vacopts,
471 : int stage,
472 : SimpleStringList *objects,
473 : int concurrentCons,
474 : const char *progname, bool echo, bool quiet)
475 : {
476 : PQExpBufferData sql;
477 : PQExpBufferData buf;
478 ECB : PQExpBufferData catalog_query;
479 : PGresult *res;
480 : PGconn *conn;
481 : SimpleStringListCell *cell;
482 : ParallelSlotArray *sa;
483 GIC 49 : SimpleStringList dbtables = {NULL, NULL};
484 ECB : int i;
485 : int ntups;
486 CBC 49 : bool failed = false;
487 GNC 49 : bool objects_listed = false;
488 GIC 49 : bool has_where = false;
489 : const char *initcmd;
490 49 : const char *stage_commands[] = {
491 : "SET default_statistics_target=1; SET vacuum_cost_delay=0;",
492 : "SET default_statistics_target=10; RESET vacuum_cost_delay;",
493 : "RESET default_statistics_target;"
494 ECB : };
495 GIC 49 : const char *stage_messages[] = {
496 : gettext_noop("Generating minimal optimizer statistics (1 target)"),
497 : gettext_noop("Generating medium optimizer statistics (10 targets)"),
498 : gettext_noop("Generating default (full) optimizer statistics")
499 : };
500 :
501 CBC 49 : Assert(stage == ANALYZE_NO_STAGE ||
502 : (stage >= 0 && stage < ANALYZE_NUM_STAGES));
503 :
504 GIC 49 : conn = connectDatabase(cparams, progname, echo, false, true);
505 :
506 49 : if (vacopts->disable_page_skipping && PQserverVersion(conn) < 90600)
507 : {
508 LBC 0 : PQfinish(conn);
509 UIC 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
510 ECB : "disable-page-skipping", "9.6");
511 : }
512 :
513 GIC 49 : if (vacopts->no_index_cleanup && PQserverVersion(conn) < 120000)
514 ECB : {
515 LBC 0 : PQfinish(conn);
516 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
517 : "no-index-cleanup", "12");
518 ECB : }
519 :
520 CBC 49 : if (vacopts->force_index_cleanup && PQserverVersion(conn) < 120000)
521 : {
522 LBC 0 : PQfinish(conn);
523 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
524 ECB : "force-index-cleanup", "12");
525 : }
526 :
527 CBC 49 : if (!vacopts->do_truncate && PQserverVersion(conn) < 120000)
528 ECB : {
529 UIC 0 : PQfinish(conn);
530 LBC 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
531 ECB : "no-truncate", "12");
532 : }
533 :
534 GNC 49 : if (!vacopts->process_main && PQserverVersion(conn) < 160000)
535 : {
536 UNC 0 : PQfinish(conn);
537 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
538 : "no-process-main", "16");
539 : }
540 :
541 CBC 49 : if (!vacopts->process_toast && PQserverVersion(conn) < 140000)
542 ECB : {
543 LBC 0 : PQfinish(conn);
544 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
545 : "no-process-toast", "14");
546 : }
547 :
548 GIC 49 : if (vacopts->skip_locked && PQserverVersion(conn) < 120000)
549 : {
550 UIC 0 : PQfinish(conn);
551 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
552 : "skip-locked", "12");
553 : }
554 :
555 GIC 49 : if (vacopts->min_xid_age != 0 && PQserverVersion(conn) < 90600)
556 UIC 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
557 : "--min-xid-age", "9.6");
558 :
559 GIC 49 : if (vacopts->min_mxid_age != 0 && PQserverVersion(conn) < 90600)
560 LBC 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
561 : "--min-mxid-age", "9.6");
562 :
563 GIC 49 : if (vacopts->parallel_workers >= 0 && PQserverVersion(conn) < 130000)
564 UIC 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
565 : "--parallel", "13");
566 :
567 GNC 49 : if (vacopts->buffer_usage_limit && PQserverVersion(conn) < 160000)
568 UNC 0 : pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
569 : "--buffer-usage-limit", "16");
570 :
571 : /* skip_database_stats is used automatically if server supports it */
572 GNC 49 : vacopts->skip_database_stats = (PQserverVersion(conn) >= 160000);
573 :
574 GIC 49 : if (!quiet)
575 : {
576 49 : if (stage != ANALYZE_NO_STAGE)
577 9 : printf(_("%s: processing database \"%s\": %s\n"),
578 : progname, PQdb(conn), _(stage_messages[stage]));
579 : else
580 40 : printf(_("%s: vacuuming database \"%s\"\n"),
581 ECB : progname, PQdb(conn));
582 GIC 49 : fflush(stdout);
583 : }
584 ECB :
585 : /*
586 : * Prepare the list of tables to process by querying the catalogs.
587 : *
588 : * Since we execute the constructed query with the default search_path
589 : * (which could be unsafe), everything in this query MUST be fully
590 : * qualified.
591 : *
592 : * First, build a WITH clause for the catalog query if any tables were
593 : * specified, with a set of values made of relation names and their
594 : * optional set of columns. This is used to match any provided column
595 : * lists with the generated qualified identifiers and to filter for the
596 : * tables provided via --table. If a listed table does not exist, the
597 : * catalog query will fail.
598 : */
599 CBC 49 : initPQExpBuffer(&catalog_query);
600 GNC 61 : for (cell = objects ? objects->head : NULL; cell; cell = cell->next)
601 : {
602 12 : char *just_table = NULL;
603 12 : const char *just_columns = NULL;
604 ECB :
605 GNC 12 : if (!objects_listed)
606 EUB : {
607 GIC 12 : appendPQExpBufferStr(&catalog_query,
608 : "WITH listed_objects (object_oid, column_list) "
609 : "AS (\n VALUES (");
610 GNC 12 : objects_listed = true;
611 : }
612 EUB : else
613 UBC 0 : appendPQExpBufferStr(&catalog_query, ",\n (");
614 :
615 GNC 12 : if (objfilter & (OBJFILTER_SCHEMA | OBJFILTER_SCHEMA_EXCLUDE))
616 : {
617 2 : appendStringLiteralConn(&catalog_query, cell->val, conn);
618 2 : appendPQExpBufferStr(&catalog_query, "::pg_catalog.regnamespace, ");
619 : }
620 :
621 12 : if (objfilter & OBJFILTER_TABLE)
622 : {
623 : /*
624 : * Split relation and column names given by the user, this is used
625 : * to feed the CTE with values on which are performed pre-run
626 : * validity checks as well. For now these happen only on the
627 : * relation name.
628 : */
629 10 : splitTableColumnsSpec(cell->val, PQclientEncoding(conn),
630 : &just_table, &just_columns);
631 :
632 10 : appendStringLiteralConn(&catalog_query, just_table, conn);
633 10 : appendPQExpBufferStr(&catalog_query, "::pg_catalog.regclass, ");
634 : }
635 ECB :
636 GIC 12 : if (just_columns && just_columns[0] != '\0')
637 GBC 5 : appendStringLiteralConn(&catalog_query, just_columns, conn);
638 EUB : else
639 GIC 7 : appendPQExpBufferStr(&catalog_query, "NULL");
640 :
641 12 : appendPQExpBufferStr(&catalog_query, "::pg_catalog.text)");
642 ECB :
643 GIC 12 : pg_free(just_table);
644 EUB : }
645 :
646 : /* Finish formatting the CTE */
647 GNC 49 : if (objects_listed)
648 GIC 12 : appendPQExpBufferStr(&catalog_query, "\n)\n");
649 ECB :
650 GIC 49 : appendPQExpBufferStr(&catalog_query, "SELECT c.relname, ns.nspname");
651 EUB :
652 GNC 49 : if (objects_listed)
653 12 : appendPQExpBufferStr(&catalog_query, ", listed_objects.column_list");
654 :
655 GIC 49 : appendPQExpBufferStr(&catalog_query,
656 ECB : " FROM pg_catalog.pg_class c\n"
657 : " JOIN pg_catalog.pg_namespace ns"
658 EUB : " ON c.relnamespace OPERATOR(pg_catalog.=) ns.oid\n"
659 : " LEFT JOIN pg_catalog.pg_class t"
660 : " ON c.reltoastrelid OPERATOR(pg_catalog.=) t.oid\n");
661 :
662 : /* Used to match the tables or schemas listed by the user */
663 GNC 49 : if (objects_listed)
664 : {
665 12 : appendPQExpBufferStr(&catalog_query, " JOIN listed_objects"
666 : " ON listed_objects.object_oid ");
667 :
668 12 : if (objfilter & OBJFILTER_SCHEMA_EXCLUDE)
669 1 : appendPQExpBufferStr(&catalog_query, "OPERATOR(pg_catalog.!=) ");
670 : else
671 11 : appendPQExpBufferStr(&catalog_query, "OPERATOR(pg_catalog.=) ");
672 :
673 12 : if (objfilter & OBJFILTER_TABLE)
674 10 : appendPQExpBufferStr(&catalog_query, "c.oid\n");
675 : else
676 2 : appendPQExpBufferStr(&catalog_query, "ns.oid\n");
677 : }
678 :
679 ECB : /*
680 EUB : * If no tables were listed, filter for the relevant relation types. If
681 : * tables were given via --table, don't bother filtering by relation type.
682 : * Instead, let the server decide whether a given relation can be
683 ECB : * processed in which case the user will know about it.
684 EUB : */
685 GNC 49 : if ((objfilter & OBJFILTER_TABLE) == 0)
686 : {
687 CBC 39 : appendPQExpBufferStr(&catalog_query, " WHERE c.relkind OPERATOR(pg_catalog.=) ANY (array["
688 EUB : CppAsString2(RELKIND_RELATION) ", "
689 : CppAsString2(RELKIND_MATVIEW) "])\n");
690 GIC 39 : has_where = true;
691 : }
692 ECB :
693 : /*
694 : * For --min-xid-age and --min-mxid-age, the age of the relation is the
695 : * greatest of the ages of the main relation and its associated TOAST
696 : * table. The commands generated by vacuumdb will also process the TOAST
697 : * table for the relation if necessary, so it does not need to be
698 : * considered separately.
699 : */
700 CBC 49 : if (vacopts->min_xid_age != 0)
701 : {
702 1 : appendPQExpBuffer(&catalog_query,
703 : " %s GREATEST(pg_catalog.age(c.relfrozenxid),"
704 : " pg_catalog.age(t.relfrozenxid)) "
705 : " OPERATOR(pg_catalog.>=) '%d'::pg_catalog.int4\n"
706 : " AND c.relfrozenxid OPERATOR(pg_catalog.!=)"
707 : " '0'::pg_catalog.xid\n",
708 : has_where ? "AND" : "WHERE", vacopts->min_xid_age);
709 GIC 1 : has_where = true;
710 : }
711 :
712 49 : if (vacopts->min_mxid_age != 0)
713 : {
714 1 : appendPQExpBuffer(&catalog_query,
715 : " %s GREATEST(pg_catalog.mxid_age(c.relminmxid),"
716 : " pg_catalog.mxid_age(t.relminmxid)) OPERATOR(pg_catalog.>=)"
717 : " '%d'::pg_catalog.int4\n"
718 : " AND c.relminmxid OPERATOR(pg_catalog.!=)"
719 ECB : " '0'::pg_catalog.xid\n",
720 : has_where ? "AND" : "WHERE", vacopts->min_mxid_age);
721 GIC 1 : has_where = true;
722 ECB : }
723 :
724 : /*
725 : * Execute the catalog query. We use the default search_path for this
726 : * query for consistency with table lookups done elsewhere by the user.
727 : */
728 GIC 49 : appendPQExpBufferStr(&catalog_query, " ORDER BY c.relpages DESC;");
729 49 : executeCommand(conn, "RESET search_path;", echo);
730 CBC 49 : res = executeQuery(conn, catalog_query.data, echo);
731 GIC 48 : termPQExpBuffer(&catalog_query);
732 48 : PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
733 EUB :
734 : /*
735 ECB : * If no rows are returned, there are no matching tables, so we are done.
736 : */
737 CBC 48 : ntups = PQntuples(res);
738 48 : if (ntups == 0)
739 : {
740 GIC 2 : PQclear(res);
741 CBC 2 : PQfinish(conn);
742 GIC 2 : return;
743 : }
744 :
745 : /*
746 : * Build qualified identifiers for each table, including the column list
747 : * if given.
748 : */
749 CBC 46 : initPQExpBuffer(&buf);
750 GIC 2574 : for (i = 0; i < ntups; i++)
751 : {
752 CBC 2528 : appendPQExpBufferStr(&buf,
753 2528 : fmtQualifiedId(PQgetvalue(res, i, 1),
754 GIC 2528 : PQgetvalue(res, i, 0)));
755 :
756 GNC 2528 : if (objects_listed && !PQgetisnull(res, i, 2))
757 CBC 5 : appendPQExpBufferStr(&buf, PQgetvalue(res, i, 2));
758 :
759 2528 : simple_string_list_append(&dbtables, buf.data);
760 GIC 2528 : resetPQExpBuffer(&buf);
761 ECB : }
762 GIC 46 : termPQExpBuffer(&buf);
763 CBC 46 : PQclear(res);
764 :
765 : /*
766 : * Ensure concurrentCons is sane. If there are more connections than
767 ECB : * vacuumable relations, we don't need to use them all.
768 : */
769 GIC 46 : if (concurrentCons > ntups)
770 LBC 0 : concurrentCons = ntups;
771 GIC 46 : if (concurrentCons <= 0)
772 LBC 0 : concurrentCons = 1;
773 ECB :
774 : /*
775 : * All slots need to be prepared to run the appropriate analyze stage, if
776 : * caller requested that mode. We have to prepare the initial connection
777 : * ourselves before setting up the slots.
778 : */
779 GIC 46 : if (stage == ANALYZE_NO_STAGE)
780 37 : initcmd = NULL;
781 : else
782 : {
783 CBC 9 : initcmd = stage_commands[stage];
784 GIC 9 : executeCommand(conn, initcmd, echo);
785 ECB : }
786 :
787 : /*
788 : * Setup the database connections. We reuse the connection we already have
789 : * for the first slot. If not in parallel mode, the first slot in the
790 : * array contains the connection.
791 : */
792 GIC 46 : sa = ParallelSlotsSetup(concurrentCons, cparams, progname, echo, initcmd);
793 CBC 46 : ParallelSlotsAdoptConn(sa, conn);
794 ECB :
795 GIC 46 : initPQExpBuffer(&sql);
796 ECB :
797 GIC 46 : cell = dbtables.head;
798 : do
799 : {
800 2528 : const char *tabname = cell->val;
801 : ParallelSlot *free_slot;
802 :
803 2528 : if (CancelRequested)
804 : {
805 LBC 0 : failed = true;
806 UIC 0 : goto finish;
807 ECB : }
808 :
809 GIC 2528 : free_slot = ParallelSlotsGetIdle(sa, NULL);
810 CBC 2528 : if (!free_slot)
811 : {
812 UIC 0 : failed = true;
813 0 : goto finish;
814 : }
815 :
816 GIC 2528 : prepare_vacuum_command(&sql, PQserverVersion(free_slot->connection),
817 : vacopts, tabname);
818 :
819 : /*
820 ECB : * Execute the vacuum. All errors are handled in processQueryResult
821 : * through ParallelSlotsGetIdle.
822 : */
823 GIC 2528 : ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL);
824 2528 : run_vacuum_command(free_slot->connection, sql.data,
825 : echo, tabname);
826 :
827 2528 : cell = cell->next;
828 2528 : } while (cell != NULL);
829 ECB :
830 GIC 46 : if (!ParallelSlotsWaitCompletion(sa))
831 : {
832 2 : failed = true;
833 GNC 2 : goto finish;
834 : }
835 :
836 : /* If we used SKIP_DATABASE_STATS, mop up with ONLY_DATABASE_STATS */
837 44 : if (vacopts->skip_database_stats && stage == ANALYZE_NO_STAGE)
838 : {
839 35 : const char *cmd = "VACUUM (ONLY_DATABASE_STATS);";
840 35 : ParallelSlot *free_slot = ParallelSlotsGetIdle(sa, NULL);
841 :
842 35 : if (!free_slot)
843 : {
844 UNC 0 : failed = true;
845 0 : goto finish;
846 : }
847 :
848 GNC 35 : ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL);
849 35 : run_vacuum_command(free_slot->connection, cmd, echo, NULL);
850 :
851 35 : if (!ParallelSlotsWaitCompletion(sa))
852 UNC 0 : failed = true;
853 : }
854 ECB :
855 GIC 44 : finish:
856 CBC 46 : ParallelSlotsTerminate(sa);
857 GIC 46 : pg_free(sa);
858 :
859 46 : termPQExpBuffer(&sql);
860 :
861 46 : if (failed)
862 2 : exit(1);
863 ECB : }
864 :
865 : /*
866 : * Vacuum/analyze all connectable databases.
867 : *
868 : * In analyze-in-stages mode, we process all databases in one stage before
869 : * moving on to the next stage. That ensure minimal stats are available
870 : * quickly everywhere before generating more detailed ones.
871 : */
872 : static void
873 CBC 5 : vacuum_all_databases(ConnParams *cparams,
874 ECB : vacuumingOptions *vacopts,
875 : bool analyze_in_stages,
876 : int concurrentCons,
877 : const char *progname, bool echo, bool quiet)
878 : {
879 : PGconn *conn;
880 : PGresult *result;
881 : int stage;
882 : int i;
883 :
884 CBC 5 : conn = connectMaintenanceDatabase(cparams, progname, echo);
885 GIC 5 : result = executeQuery(conn,
886 : "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;",
887 : echo);
888 5 : PQfinish(conn);
889 :
890 5 : if (analyze_in_stages)
891 ECB : {
892 : /*
893 : * When analyzing all databases in stages, we analyze them all in the
894 : * fastest stage first, so that initial statistics become available
895 : * for all of them as soon as possible.
896 : *
897 : * This means we establish several times as many connections, but
898 : * that's a secondary consideration.
899 : */
900 GIC 4 : for (stage = 0; stage < ANALYZE_NUM_STAGES; stage++)
901 ECB : {
902 CBC 9 : for (i = 0; i < PQntuples(result); i++)
903 : {
904 6 : cparams->override_dbname = PQgetvalue(result, i, 0);
905 ECB :
906 GIC 6 : vacuum_one_database(cparams, vacopts,
907 : stage,
908 : NULL,
909 : concurrentCons,
910 : progname, echo, quiet);
911 ECB : }
912 EUB : }
913 ECB : }
914 EUB : else
915 : {
916 GIC 17 : for (i = 0; i < PQntuples(result); i++)
917 : {
918 13 : cparams->override_dbname = PQgetvalue(result, i, 0);
919 :
920 13 : vacuum_one_database(cparams, vacopts,
921 ECB : ANALYZE_NO_STAGE,
922 : NULL,
923 : concurrentCons,
924 : progname, echo, quiet);
925 : }
926 : }
927 :
928 GIC 5 : PQclear(result);
929 5 : }
930 :
931 : /*
932 : * Construct a vacuum/analyze command to run based on the given options, in the
933 : * given string buffer, which may contain previous garbage.
934 ECB : *
935 : * The table name used must be already properly quoted. The command generated
936 : * depends on the server version involved and it is semicolon-terminated.
937 : */
938 : static void
939 CBC 2528 : prepare_vacuum_command(PQExpBuffer sql, int serverVersion,
940 : vacuumingOptions *vacopts, const char *table)
941 : {
942 2528 : const char *paren = " (";
943 GIC 2528 : const char *comma = ", ";
944 2528 : const char *sep = paren;
945 ECB :
946 GIC 2528 : resetPQExpBuffer(sql);
947 EUB :
948 GBC 2528 : if (vacopts->analyze_only)
949 : {
950 GIC 1229 : appendPQExpBufferStr(sql, "ANALYZE");
951 ECB :
952 : /* parenthesized grammar of ANALYZE is supported since v11 */
953 GIC 1229 : if (serverVersion >= 110000)
954 EUB : {
955 GBC 1229 : if (vacopts->skip_locked)
956 : {
957 : /* SKIP_LOCKED is supported since v12 */
958 CBC 68 : Assert(serverVersion >= 120000);
959 GIC 68 : appendPQExpBuffer(sql, "%sSKIP_LOCKED", sep);
960 68 : sep = comma;
961 : }
962 1229 : if (vacopts->verbose)
963 : {
964 UIC 0 : appendPQExpBuffer(sql, "%sVERBOSE", sep);
965 LBC 0 : sep = comma;
966 ECB : }
967 GIC 1229 : if (sep != paren)
968 68 : appendPQExpBufferChar(sql, ')');
969 ECB : }
970 : else
971 : {
972 LBC 0 : if (vacopts->verbose)
973 UIC 0 : appendPQExpBufferStr(sql, " VERBOSE");
974 ECB : }
975 : }
976 : else
977 : {
978 GIC 1299 : appendPQExpBufferStr(sql, "VACUUM");
979 ECB :
980 : /* parenthesized grammar of VACUUM is supported since v9.0 */
981 CBC 1299 : if (serverVersion >= 90000)
982 ECB : {
983 GIC 1299 : if (vacopts->disable_page_skipping)
984 ECB : {
985 : /* DISABLE_PAGE_SKIPPING is supported since v9.6 */
986 GBC 68 : Assert(serverVersion >= 90600);
987 68 : appendPQExpBuffer(sql, "%sDISABLE_PAGE_SKIPPING", sep);
988 GIC 68 : sep = comma;
989 : }
990 CBC 1299 : if (vacopts->no_index_cleanup)
991 ECB : {
992 : /* "INDEX_CLEANUP FALSE" has been supported since v12 */
993 CBC 68 : Assert(serverVersion >= 120000);
994 GBC 68 : Assert(!vacopts->force_index_cleanup);
995 GIC 68 : appendPQExpBuffer(sql, "%sINDEX_CLEANUP FALSE", sep);
996 68 : sep = comma;
997 ECB : }
998 CBC 1299 : if (vacopts->force_index_cleanup)
999 ECB : {
1000 : /* "INDEX_CLEANUP TRUE" has been supported since v12 */
1001 LBC 0 : Assert(serverVersion >= 120000);
1002 UIC 0 : Assert(!vacopts->no_index_cleanup);
1003 LBC 0 : appendPQExpBuffer(sql, "%sINDEX_CLEANUP TRUE", sep);
1004 0 : sep = comma;
1005 : }
1006 GIC 1299 : if (!vacopts->do_truncate)
1007 : {
1008 : /* TRUNCATE is supported since v12 */
1009 68 : Assert(serverVersion >= 120000);
1010 68 : appendPQExpBuffer(sql, "%sTRUNCATE FALSE", sep);
1011 68 : sep = comma;
1012 : }
1013 GNC 1299 : if (!vacopts->process_main)
1014 : {
1015 : /* PROCESS_MAIN is supported since v16 */
1016 68 : Assert(serverVersion >= 160000);
1017 68 : appendPQExpBuffer(sql, "%sPROCESS_MAIN FALSE", sep);
1018 68 : sep = comma;
1019 : }
1020 GIC 1299 : if (!vacopts->process_toast)
1021 : {
1022 ECB : /* PROCESS_TOAST is supported since v14 */
1023 GIC 68 : Assert(serverVersion >= 140000);
1024 68 : appendPQExpBuffer(sql, "%sPROCESS_TOAST FALSE", sep);
1025 68 : sep = comma;
1026 : }
1027 GNC 1299 : if (vacopts->skip_database_stats)
1028 : {
1029 : /* SKIP_DATABASE_STATS is supported since v16 */
1030 1299 : Assert(serverVersion >= 160000);
1031 1299 : appendPQExpBuffer(sql, "%sSKIP_DATABASE_STATS", sep);
1032 1299 : sep = comma;
1033 : }
1034 GIC 1299 : if (vacopts->skip_locked)
1035 : {
1036 : /* SKIP_LOCKED is supported since v12 */
1037 68 : Assert(serverVersion >= 120000);
1038 68 : appendPQExpBuffer(sql, "%sSKIP_LOCKED", sep);
1039 68 : sep = comma;
1040 ECB : }
1041 CBC 1299 : if (vacopts->full)
1042 : {
1043 GIC 68 : appendPQExpBuffer(sql, "%sFULL", sep);
1044 CBC 68 : sep = comma;
1045 : }
1046 1299 : if (vacopts->freeze)
1047 : {
1048 GIC 204 : appendPQExpBuffer(sql, "%sFREEZE", sep);
1049 204 : sep = comma;
1050 : }
1051 1299 : if (vacopts->verbose)
1052 : {
1053 UIC 0 : appendPQExpBuffer(sql, "%sVERBOSE", sep);
1054 0 : sep = comma;
1055 : }
1056 CBC 1299 : if (vacopts->and_analyze)
1057 : {
1058 207 : appendPQExpBuffer(sql, "%sANALYZE", sep);
1059 GIC 207 : sep = comma;
1060 ECB : }
1061 GIC 1299 : if (vacopts->parallel_workers >= 0)
1062 ECB : {
1063 : /* PARALLEL is supported since v13 */
1064 GIC 136 : Assert(serverVersion >= 130000);
1065 136 : appendPQExpBuffer(sql, "%sPARALLEL %d", sep,
1066 : vacopts->parallel_workers);
1067 136 : sep = comma;
1068 : }
1069 GNC 1299 : if (vacopts->buffer_usage_limit)
1070 : {
1071 UNC 0 : Assert(serverVersion >= 160000);
1072 0 : appendPQExpBuffer(sql, "%sBUFFER_USAGE_LIMIT '%s'", sep,
1073 : vacopts->buffer_usage_limit);
1074 0 : sep = comma;
1075 : }
1076 GIC 1299 : if (sep != paren)
1077 1299 : appendPQExpBufferChar(sql, ')');
1078 : }
1079 ECB : else
1080 : {
1081 LBC 0 : if (vacopts->full)
1082 UIC 0 : appendPQExpBufferStr(sql, " FULL");
1083 LBC 0 : if (vacopts->freeze)
1084 UIC 0 : appendPQExpBufferStr(sql, " FREEZE");
1085 0 : if (vacopts->verbose)
1086 0 : appendPQExpBufferStr(sql, " VERBOSE");
1087 0 : if (vacopts->and_analyze)
1088 0 : appendPQExpBufferStr(sql, " ANALYZE");
1089 : }
1090 : }
1091 ECB :
1092 CBC 2528 : appendPQExpBuffer(sql, " %s;", table);
1093 GIC 2528 : }
1094 :
1095 : /*
1096 : * Send a vacuum/analyze command to the server, returning after sending the
1097 : * command.
1098 : *
1099 : * Any errors during command execution are reported to stderr.
1100 : */
1101 : static void
1102 CBC 2563 : run_vacuum_command(PGconn *conn, const char *sql, bool echo,
1103 : const char *table)
1104 : {
1105 ECB : bool status;
1106 :
1107 CBC 2563 : if (echo)
1108 GIC 483 : printf("%s\n", sql);
1109 ECB :
1110 GIC 2563 : status = PQsendQuery(conn, sql) == 1;
1111 ECB :
1112 GIC 2563 : if (!status)
1113 ECB : {
1114 UIC 0 : if (table)
1115 0 : pg_log_error("vacuuming of table \"%s\" in database \"%s\" failed: %s",
1116 ECB : table, PQdb(conn), PQerrorMessage(conn));
1117 : else
1118 LBC 0 : pg_log_error("vacuuming of database \"%s\" failed: %s",
1119 : PQdb(conn), PQerrorMessage(conn));
1120 : }
1121 CBC 2563 : }
1122 ECB :
1123 : static void
1124 GIC 1 : help(const char *progname)
1125 ECB : {
1126 GIC 1 : printf(_("%s cleans and analyzes a PostgreSQL database.\n\n"), progname);
1127 GBC 1 : printf(_("Usage:\n"));
1128 1 : printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1129 GIC 1 : printf(_("\nOptions:\n"));
1130 CBC 1 : printf(_(" -a, --all vacuum all databases\n"));
1131 1 : printf(_(" -d, --dbname=DBNAME database to vacuum\n"));
1132 GIC 1 : printf(_(" --disable-page-skipping disable all page-skipping behavior\n"));
1133 1 : printf(_(" -e, --echo show the commands being sent to the server\n"));
1134 1 : printf(_(" -f, --full do full vacuuming\n"));
1135 GBC 1 : printf(_(" -F, --freeze freeze row transaction information\n"));
1136 1 : printf(_(" --force-index-cleanup always remove index entries that point to dead tuples\n"));
1137 GIC 1 : printf(_(" -j, --jobs=NUM use this many concurrent connections to vacuum\n"));
1138 1 : printf(_(" --min-mxid-age=MXID_AGE minimum multixact ID age of tables to vacuum\n"));
1139 GNC 1 : printf(_(" --buffer-usage-limit=BUFSIZE size of ring buffer used for vacuum\n"));
1140 GIC 1 : printf(_(" --min-xid-age=XID_AGE minimum transaction ID age of tables to vacuum\n"));
1141 1 : printf(_(" --no-index-cleanup don't remove index entries that point to dead tuples\n"));
1142 GNC 1 : printf(_(" --no-process-main skip the main relation\n"));
1143 CBC 1 : printf(_(" --no-process-toast skip the TOAST table associated with the table to vacuum\n"));
1144 GIC 1 : printf(_(" --no-truncate don't truncate empty pages at the end of the table\n"));
1145 GNC 1 : printf(_(" -n, --schema=PATTERN vacuum tables in the specified schema(s) only\n"));
1146 1 : printf(_(" -N, --exclude-schema=PATTERN do not vacuum tables in the specified schema(s)\n"));
1147 GIC 1 : printf(_(" -P, --parallel=PARALLEL_WORKERS use this many background workers for vacuum, if available\n"));
1148 CBC 1 : printf(_(" -q, --quiet don't write any messages\n"));
1149 GIC 1 : printf(_(" --skip-locked skip relations that cannot be immediately locked\n"));
1150 CBC 1 : printf(_(" -t, --table='TABLE[(COLUMNS)]' vacuum specific table(s) only\n"));
1151 GIC 1 : printf(_(" -v, --verbose write a lot of output\n"));
1152 1 : printf(_(" -V, --version output version information, then exit\n"));
1153 CBC 1 : printf(_(" -z, --analyze update optimizer statistics\n"));
1154 1 : printf(_(" -Z, --analyze-only only update optimizer statistics; no vacuum\n"));
1155 1 : printf(_(" --analyze-in-stages only update optimizer statistics, in multiple\n"
1156 : " stages for faster results; no vacuum\n"));
1157 1 : printf(_(" -?, --help show this help, then exit\n"));
1158 GIC 1 : printf(_("\nConnection options:\n"));
1159 1 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
1160 CBC 1 : printf(_(" -p, --port=PORT database server port\n"));
1161 1 : printf(_(" -U, --username=USERNAME user name to connect as\n"));
1162 1 : printf(_(" -w, --no-password never prompt for password\n"));
1163 1 : printf(_(" -W, --password force password prompt\n"));
1164 GIC 1 : printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
1165 CBC 1 : printf(_("\nRead the description of the SQL command VACUUM for details.\n"));
1166 GIC 1 : printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1167 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1168 GBC 1 : }
|