PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
vacuumdb.c File Reference
#include "postgres_fe.h"
#include <limits.h>
#include "catalog/pg_class_d.h"
#include "common.h"
#include "common/connect.h"
#include "common/logging.h"
#include "fe_utils/cancel.h"
#include "fe_utils/option_utils.h"
#include "fe_utils/parallel_slot.h"
#include "fe_utils/query_utils.h"
#include "fe_utils/simple_list.h"
#include "fe_utils/string_utils.h"
Include dependency graph for vacuumdb.c:

Go to the source code of this file.

Data Structures

struct  vacuumingOptions
 

Macros

#define ANALYZE_NO_STAGE   -1
 
#define ANALYZE_NUM_STAGES   3
 

Typedefs

typedef struct vacuumingOptions vacuumingOptions
 

Enumerations

enum  VacObjFilter {
  OBJFILTER_NONE = 0 , OBJFILTER_ALL_DBS = (1 << 0) , OBJFILTER_DATABASE = (1 << 1) , OBJFILTER_TABLE = (1 << 2) ,
  OBJFILTER_SCHEMA = (1 << 3) , OBJFILTER_SCHEMA_EXCLUDE = (1 << 4)
}
 

Functions

static SimpleStringListretrieve_objects (PGconn *conn, vacuumingOptions *vacopts, SimpleStringList *objects, bool echo)
 
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 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 prepare_vacuum_command (PQExpBuffer sql, int serverVersion, vacuumingOptions *vacopts, const char *table)
 
static void run_vacuum_command (PGconn *conn, const char *sql, bool echo, const char *table)
 
static void help (const char *progname)
 
void check_objfilter (void)
 
static char * escape_quotes (const char *src)
 
int main (int argc, char *argv[])
 

Variables

static VacObjFilter objfilter = OBJFILTER_NONE
 

Macro Definition Documentation

◆ ANALYZE_NO_STAGE

#define ANALYZE_NO_STAGE   -1

Definition at line 99 of file vacuumdb.c.

◆ ANALYZE_NUM_STAGES

#define ANALYZE_NUM_STAGES   3

Definition at line 100 of file vacuumdb.c.

Typedef Documentation

◆ vacuumingOptions

Enumeration Type Documentation

◆ VacObjFilter

Enumerator
OBJFILTER_NONE 
OBJFILTER_ALL_DBS 
OBJFILTER_DATABASE 
OBJFILTER_TABLE 
OBJFILTER_SCHEMA 
OBJFILTER_SCHEMA_EXCLUDE 

Definition at line 54 of file vacuumdb.c.

55{
56 OBJFILTER_NONE = 0, /* no filter used */
57 OBJFILTER_ALL_DBS = (1 << 0), /* -a | --all */
58 OBJFILTER_DATABASE = (1 << 1), /* -d | --dbname */
59 OBJFILTER_TABLE = (1 << 2), /* -t | --table */
60 OBJFILTER_SCHEMA = (1 << 3), /* -n | --schema */
61 OBJFILTER_SCHEMA_EXCLUDE = (1 << 4), /* -N | --exclude-schema */
VacObjFilter
Definition: vacuumdb.c:55
@ OBJFILTER_DATABASE
Definition: vacuumdb.c:58
@ OBJFILTER_ALL_DBS
Definition: vacuumdb.c:57
@ OBJFILTER_SCHEMA
Definition: vacuumdb.c:60
@ OBJFILTER_SCHEMA_EXCLUDE
Definition: vacuumdb.c:61
@ OBJFILTER_TABLE
Definition: vacuumdb.c:59
@ OBJFILTER_NONE
Definition: vacuumdb.c:56

Function Documentation

◆ check_objfilter()

void check_objfilter ( void  )

Definition at line 449 of file vacuumdb.c.

450{
453 pg_fatal("cannot vacuum all databases and a specific one at the same time");
454
455 if ((objfilter & OBJFILTER_TABLE) &&
457 pg_fatal("cannot vacuum all tables in schema(s) and specific table(s) at the same time");
458
459 if ((objfilter & OBJFILTER_TABLE) &&
461 pg_fatal("cannot vacuum specific table(s) and exclude schema(s) at the same time");
462
463 if ((objfilter & OBJFILTER_SCHEMA) &&
465 pg_fatal("cannot vacuum all tables in schema(s) and exclude schema(s) at the same time");
466}
#define pg_fatal(...)
static VacObjFilter objfilter
Definition: vacuumdb.c:64

References objfilter, OBJFILTER_ALL_DBS, OBJFILTER_DATABASE, OBJFILTER_SCHEMA, OBJFILTER_SCHEMA_EXCLUDE, OBJFILTER_TABLE, and pg_fatal.

Referenced by main().

◆ escape_quotes()

static char * escape_quotes ( const char *  src)
static

Definition at line 473 of file vacuumdb.c.

474{
475 char *result = escape_single_quotes_ascii(src);
476
477 if (!result)
478 pg_fatal("out of memory");
479 return result;
480}
char * escape_single_quotes_ascii(const char *src)
Definition: quotes.c:33

References escape_single_quotes_ascii(), and pg_fatal.

Referenced by main().

◆ help()

static void help ( const char *  progname)
static

Definition at line 1334 of file vacuumdb.c.

1335{
1336 printf(_("%s cleans and analyzes a PostgreSQL database.\n\n"), progname);
1337 printf(_("Usage:\n"));
1338 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1339 printf(_("\nOptions:\n"));
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);
1379}
#define _(x)
Definition: elog.c:91
const char * progname
Definition: main.c:44
#define printf(...)
Definition: port.h:245

References _, printf, and progname.

Referenced by main().

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 104 of file vacuumdb.c.

105{
106 static struct option long_options[] = {
107 {"host", required_argument, NULL, 'h'},
108 {"port", required_argument, NULL, 'p'},
109 {"username", required_argument, NULL, 'U'},
110 {"no-password", no_argument, NULL, 'w'},
111 {"password", no_argument, NULL, 'W'},
112 {"echo", no_argument, NULL, 'e'},
113 {"quiet", no_argument, NULL, 'q'},
114 {"dbname", required_argument, NULL, 'd'},
115 {"analyze", no_argument, NULL, 'z'},
116 {"analyze-only", no_argument, NULL, 'Z'},
117 {"freeze", no_argument, NULL, 'F'},
118 {"all", no_argument, NULL, 'a'},
119 {"table", required_argument, NULL, 't'},
120 {"full", no_argument, NULL, 'f'},
121 {"verbose", no_argument, NULL, 'v'},
122 {"jobs", required_argument, NULL, 'j'},
123 {"parallel", required_argument, NULL, 'P'},
124 {"schema", required_argument, NULL, 'n'},
125 {"exclude-schema", required_argument, NULL, 'N'},
126 {"maintenance-db", required_argument, NULL, 2},
127 {"analyze-in-stages", no_argument, NULL, 3},
128 {"disable-page-skipping", no_argument, NULL, 4},
129 {"skip-locked", no_argument, NULL, 5},
130 {"min-xid-age", required_argument, NULL, 6},
131 {"min-mxid-age", required_argument, NULL, 7},
132 {"no-index-cleanup", no_argument, NULL, 8},
133 {"force-index-cleanup", no_argument, NULL, 9},
134 {"no-truncate", no_argument, NULL, 10},
135 {"no-process-toast", no_argument, NULL, 11},
136 {"no-process-main", no_argument, NULL, 12},
137 {"buffer-usage-limit", required_argument, NULL, 13},
138 {"missing-stats-only", no_argument, NULL, 14},
139 {NULL, 0, NULL, 0}
140 };
141
142 const char *progname;
143 int optindex;
144 int c;
145 const char *dbname = NULL;
146 const char *maintenance_db = NULL;
147 char *host = NULL;
148 char *port = NULL;
149 char *username = NULL;
150 enum trivalue prompt_password = TRI_DEFAULT;
151 ConnParams cparams;
152 bool echo = false;
153 bool quiet = false;
154 vacuumingOptions vacopts;
155 bool analyze_in_stages = false;
156 SimpleStringList objects = {NULL, NULL};
157 int concurrentCons = 1;
158 int tbl_count = 0;
159
160 /* initialize options */
161 memset(&vacopts, 0, sizeof(vacopts));
162 vacopts.parallel_workers = -1;
163 vacopts.buffer_usage_limit = NULL;
164 vacopts.no_index_cleanup = false;
165 vacopts.force_index_cleanup = false;
166 vacopts.do_truncate = true;
167 vacopts.process_main = true;
168 vacopts.process_toast = true;
169
170 pg_logging_init(argv[0]);
171 progname = get_progname(argv[0]);
172 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
173
174 handle_help_version_opts(argc, argv, "vacuumdb", help);
175
176 while ((c = getopt_long(argc, argv, "ad:efFh:j:n:N:p:P:qt:U:vwWzZ", long_options, &optindex)) != -1)
177 {
178 switch (c)
179 {
180 case 'a':
182 break;
183 case 'd':
186 break;
187 case 'e':
188 echo = true;
189 break;
190 case 'f':
191 vacopts.full = true;
192 break;
193 case 'F':
194 vacopts.freeze = true;
195 break;
196 case 'h':
197 host = pg_strdup(optarg);
198 break;
199 case 'j':
200 if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
201 &concurrentCons))
202 exit(1);
203 break;
204 case 'n':
207 break;
208 case 'N':
211 break;
212 case 'p':
214 break;
215 case 'P':
216 if (!option_parse_int(optarg, "-P/--parallel", 0, INT_MAX,
217 &vacopts.parallel_workers))
218 exit(1);
219 break;
220 case 'q':
221 quiet = true;
222 break;
223 case 't':
226 tbl_count++;
227 break;
228 case 'U':
230 break;
231 case 'v':
232 vacopts.verbose = true;
233 break;
234 case 'w':
235 prompt_password = TRI_NO;
236 break;
237 case 'W':
238 prompt_password = TRI_YES;
239 break;
240 case 'z':
241 vacopts.and_analyze = true;
242 break;
243 case 'Z':
244 vacopts.analyze_only = true;
245 break;
246 case 2:
247 maintenance_db = pg_strdup(optarg);
248 break;
249 case 3:
250 analyze_in_stages = vacopts.analyze_only = true;
251 break;
252 case 4:
253 vacopts.disable_page_skipping = true;
254 break;
255 case 5:
256 vacopts.skip_locked = true;
257 break;
258 case 6:
259 if (!option_parse_int(optarg, "--min-xid-age", 1, INT_MAX,
260 &vacopts.min_xid_age))
261 exit(1);
262 break;
263 case 7:
264 if (!option_parse_int(optarg, "--min-mxid-age", 1, INT_MAX,
265 &vacopts.min_mxid_age))
266 exit(1);
267 break;
268 case 8:
269 vacopts.no_index_cleanup = true;
270 break;
271 case 9:
272 vacopts.force_index_cleanup = true;
273 break;
274 case 10:
275 vacopts.do_truncate = false;
276 break;
277 case 11:
278 vacopts.process_toast = false;
279 break;
280 case 12:
281 vacopts.process_main = false;
282 break;
283 case 13:
285 break;
286 case 14:
287 vacopts.missing_stats_only = true;
288 break;
289 default:
290 /* getopt_long already emitted a complaint */
291 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
292 exit(1);
293 }
294 }
295
296 /*
297 * Non-option argument specifies database name as long as it wasn't
298 * already specified with -d / --dbname
299 */
300 if (optind < argc && dbname == NULL)
301 {
303 dbname = argv[optind];
304 optind++;
305 }
306
307 if (optind < argc)
308 {
309 pg_log_error("too many command-line arguments (first is \"%s\")",
310 argv[optind]);
311 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
312 exit(1);
313 }
314
315 /*
316 * Validate the combination of filters specified in the command-line
317 * options.
318 */
320
321 if (vacopts.analyze_only)
322 {
323 if (vacopts.full)
324 pg_fatal("cannot use the \"%s\" option when performing only analyze",
325 "full");
326 if (vacopts.freeze)
327 pg_fatal("cannot use the \"%s\" option when performing only analyze",
328 "freeze");
329 if (vacopts.disable_page_skipping)
330 pg_fatal("cannot use the \"%s\" option when performing only analyze",
331 "disable-page-skipping");
332 if (vacopts.no_index_cleanup)
333 pg_fatal("cannot use the \"%s\" option when performing only analyze",
334 "no-index-cleanup");
335 if (vacopts.force_index_cleanup)
336 pg_fatal("cannot use the \"%s\" option when performing only analyze",
337 "force-index-cleanup");
338 if (!vacopts.do_truncate)
339 pg_fatal("cannot use the \"%s\" option when performing only analyze",
340 "no-truncate");
341 if (!vacopts.process_main)
342 pg_fatal("cannot use the \"%s\" option when performing only analyze",
343 "no-process-main");
344 if (!vacopts.process_toast)
345 pg_fatal("cannot use the \"%s\" option when performing only analyze",
346 "no-process-toast");
347 /* allow 'and_analyze' with 'analyze_only' */
348 }
349
350 /* Prohibit full and analyze_only options with parallel option */
351 if (vacopts.parallel_workers >= 0)
352 {
353 if (vacopts.analyze_only)
354 pg_fatal("cannot use the \"%s\" option when performing only analyze",
355 "parallel");
356 if (vacopts.full)
357 pg_fatal("cannot use the \"%s\" option when performing full vacuum",
358 "parallel");
359 }
360
361 /* Prohibit --no-index-cleanup and --force-index-cleanup together */
362 if (vacopts.no_index_cleanup && vacopts.force_index_cleanup)
363 pg_fatal("cannot use the \"%s\" option with the \"%s\" option",
364 "no-index-cleanup", "force-index-cleanup");
365
366 /*
367 * buffer-usage-limit is not allowed with VACUUM FULL unless ANALYZE is
368 * included too.
369 */
370 if (vacopts.buffer_usage_limit && vacopts.full && !vacopts.and_analyze)
371 pg_fatal("cannot use the \"%s\" option with the \"%s\" option",
372 "buffer-usage-limit", "full");
373
374 /*
375 * Prohibit --missing-stats-only without --analyze-only or
376 * --analyze-in-stages.
377 */
378 if (vacopts.missing_stats_only && !vacopts.analyze_only)
379 pg_fatal("cannot use the \"%s\" option without \"%s\" or \"%s\"",
380 "missing-stats-only", "analyze-only", "analyze-in-stages");
381
382 /* fill cparams except for dbname, which is set below */
383 cparams.pghost = host;
384 cparams.pgport = port;
385 cparams.pguser = username;
386 cparams.prompt_password = prompt_password;
387 cparams.override_dbname = NULL;
388
390
391 /* Avoid opening extra connections. */
392 if (tbl_count && (concurrentCons > tbl_count))
393 concurrentCons = tbl_count;
394
396 {
397 cparams.dbname = maintenance_db;
398
399 vacuum_all_databases(&cparams, &vacopts,
400 analyze_in_stages,
401 &objects,
402 concurrentCons,
403 progname, echo, quiet);
404 }
405 else
406 {
407 if (dbname == NULL)
408 {
409 if (getenv("PGDATABASE"))
410 dbname = getenv("PGDATABASE");
411 else if (getenv("PGUSER"))
412 dbname = getenv("PGUSER");
413 else
415 }
416
417 cparams.dbname = dbname;
418
419 if (analyze_in_stages)
420 {
421 int stage;
422 SimpleStringList *found_objs = NULL;
423
424 for (stage = 0; stage < ANALYZE_NUM_STAGES; stage++)
425 {
426 vacuum_one_database(&cparams, &vacopts,
427 stage,
428 &objects,
429 vacopts.missing_stats_only ? &found_objs : NULL,
430 concurrentCons,
431 progname, echo, quiet);
432 }
433 }
434 else
435 vacuum_one_database(&cparams, &vacopts,
437 &objects, NULL,
438 concurrentCons,
439 progname, echo, quiet);
440 }
441
442 exit(0);
443}
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1185
void setup_cancel_handler(void(*query_cancel_callback)(void))
Definition: cancel.c:183
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:429
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 * username
Definition: initdb.c:153
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
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
PGDLLIMPORT int optind
Definition: getopt.c:51
PGDLLIMPORT char * optarg
Definition: getopt.c:53
static int port
Definition: pg_regress.c:115
const char * get_progname(const char *argv0)
Definition: path.c:652
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 * override_dbname
Definition: pg_backup.h:93
char * pgport
Definition: pg_backup.h:87
char * pghost
Definition: pg_backup.h:88
char * dbname
Definition: pg_backup.h:86
enum trivalue prompt_password
Definition: connect_utils.h:32
bool force_index_cleanup
Definition: vacuumdb.c:44
bool no_index_cleanup
Definition: vacuumdb.c:43
int parallel_workers
Definition: vacuumdb.c:41
bool disable_page_skipping
Definition: vacuumdb.c:37
bool skip_locked
Definition: vacuumdb.c:38
bool process_toast
Definition: vacuumdb.c:47
char * buffer_usage_limit
Definition: vacuumdb.c:49
bool do_truncate
Definition: vacuumdb.c:45
bool process_main
Definition: vacuumdb.c:46
bool missing_stats_only
Definition: vacuumdb.c:50
bool and_analyze
Definition: vacuumdb.c:34
bool analyze_only
Definition: vacuumdb.c:32
const char * get_user_name_or_exit(const char *progname)
Definition: username.c:74
void check_objfilter(void)
Definition: vacuumdb.c:449
static void vacuum_all_databases(ConnParams *cparams, vacuumingOptions *vacopts, bool analyze_in_stages, SimpleStringList *objects, int concurrentCons, const char *progname, bool echo, bool quiet)
Definition: vacuumdb.c:1069
static void help(const char *progname)
Definition: vacuumdb.c:1334
#define ANALYZE_NUM_STAGES
Definition: vacuumdb.c:100
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)
Definition: vacuumdb.c:523
#define ANALYZE_NO_STAGE
Definition: vacuumdb.c:99
static char * escape_quotes(const char *src)
Definition: vacuumdb.c:473
trivalue
Definition: vacuumlo.c:35
@ TRI_YES
Definition: vacuumlo.c:38
@ TRI_DEFAULT
Definition: vacuumlo.c:36
@ TRI_NO
Definition: vacuumlo.c:37

References ANALYZE_NO_STAGE, ANALYZE_NUM_STAGES, vacuumingOptions::analyze_only, vacuumingOptions::and_analyze, vacuumingOptions::buffer_usage_limit, check_objfilter(), dbname, _connParams::dbname, vacuumingOptions::disable_page_skipping, vacuumingOptions::do_truncate, escape_quotes(), vacuumingOptions::force_index_cleanup, vacuumingOptions::freeze, vacuumingOptions::full, get_progname(), get_user_name_or_exit(), getopt_long(), handle_help_version_opts(), help(), vacuumingOptions::min_mxid_age, vacuumingOptions::min_xid_age, vacuumingOptions::missing_stats_only, no_argument, vacuumingOptions::no_index_cleanup, objfilter, OBJFILTER_ALL_DBS, OBJFILTER_DATABASE, OBJFILTER_SCHEMA, OBJFILTER_SCHEMA_EXCLUDE, OBJFILTER_TABLE, optarg, optind, option_parse_int(), _connParams::override_dbname, vacuumingOptions::parallel_workers, pg_fatal, pg_log_error, pg_log_error_hint, pg_logging_init(), pg_strdup(), PG_TEXTDOMAIN, _connParams::pghost, _connParams::pgport, _connParams::pguser, port, vacuumingOptions::process_main, vacuumingOptions::process_toast, progname, _connParams::prompt_password, required_argument, set_pglocale_pgservice(), setup_cancel_handler(), simple_string_list_append(), vacuumingOptions::skip_locked, TRI_DEFAULT, TRI_NO, TRI_YES, username, vacuum_all_databases(), vacuum_one_database(), and vacuumingOptions::verbose.

◆ prepare_vacuum_command()

static void prepare_vacuum_command ( PQExpBuffer  sql,
int  serverVersion,
vacuumingOptions vacopts,
const char *  table 
)
static

Definition at line 1142 of file vacuumdb.c.

1144{
1145 const char *paren = " (";
1146 const char *comma = ", ";
1147 const char *sep = paren;
1148
1149 resetPQExpBuffer(sql);
1150
1151 if (vacopts->analyze_only)
1152 {
1153 appendPQExpBufferStr(sql, "ANALYZE");
1154
1155 /* parenthesized grammar of ANALYZE is supported since v11 */
1156 if (serverVersion >= 110000)
1157 {
1158 if (vacopts->skip_locked)
1159 {
1160 /* SKIP_LOCKED is supported since v12 */
1161 Assert(serverVersion >= 120000);
1162 appendPQExpBuffer(sql, "%sSKIP_LOCKED", sep);
1163 sep = comma;
1164 }
1165 if (vacopts->verbose)
1166 {
1167 appendPQExpBuffer(sql, "%sVERBOSE", sep);
1168 sep = comma;
1169 }
1170 if (vacopts->buffer_usage_limit)
1171 {
1172 Assert(serverVersion >= 160000);
1173 appendPQExpBuffer(sql, "%sBUFFER_USAGE_LIMIT '%s'", sep,
1174 vacopts->buffer_usage_limit);
1175 sep = comma;
1176 }
1177 if (sep != paren)
1178 appendPQExpBufferChar(sql, ')');
1179 }
1180 else
1181 {
1182 if (vacopts->verbose)
1183 appendPQExpBufferStr(sql, " VERBOSE");
1184 }
1185 }
1186 else
1187 {
1188 appendPQExpBufferStr(sql, "VACUUM");
1189
1190 /* parenthesized grammar of VACUUM is supported since v9.0 */
1191 if (serverVersion >= 90000)
1192 {
1193 if (vacopts->disable_page_skipping)
1194 {
1195 /* DISABLE_PAGE_SKIPPING is supported since v9.6 */
1196 Assert(serverVersion >= 90600);
1197 appendPQExpBuffer(sql, "%sDISABLE_PAGE_SKIPPING", sep);
1198 sep = comma;
1199 }
1200 if (vacopts->no_index_cleanup)
1201 {
1202 /* "INDEX_CLEANUP FALSE" has been supported since v12 */
1203 Assert(serverVersion >= 120000);
1204 Assert(!vacopts->force_index_cleanup);
1205 appendPQExpBuffer(sql, "%sINDEX_CLEANUP FALSE", sep);
1206 sep = comma;
1207 }
1208 if (vacopts->force_index_cleanup)
1209 {
1210 /* "INDEX_CLEANUP TRUE" has been supported since v12 */
1211 Assert(serverVersion >= 120000);
1212 Assert(!vacopts->no_index_cleanup);
1213 appendPQExpBuffer(sql, "%sINDEX_CLEANUP TRUE", sep);
1214 sep = comma;
1215 }
1216 if (!vacopts->do_truncate)
1217 {
1218 /* TRUNCATE is supported since v12 */
1219 Assert(serverVersion >= 120000);
1220 appendPQExpBuffer(sql, "%sTRUNCATE FALSE", sep);
1221 sep = comma;
1222 }
1223 if (!vacopts->process_main)
1224 {
1225 /* PROCESS_MAIN is supported since v16 */
1226 Assert(serverVersion >= 160000);
1227 appendPQExpBuffer(sql, "%sPROCESS_MAIN FALSE", sep);
1228 sep = comma;
1229 }
1230 if (!vacopts->process_toast)
1231 {
1232 /* PROCESS_TOAST is supported since v14 */
1233 Assert(serverVersion >= 140000);
1234 appendPQExpBuffer(sql, "%sPROCESS_TOAST FALSE", sep);
1235 sep = comma;
1236 }
1237 if (vacopts->skip_database_stats)
1238 {
1239 /* SKIP_DATABASE_STATS is supported since v16 */
1240 Assert(serverVersion >= 160000);
1241 appendPQExpBuffer(sql, "%sSKIP_DATABASE_STATS", sep);
1242 sep = comma;
1243 }
1244 if (vacopts->skip_locked)
1245 {
1246 /* SKIP_LOCKED is supported since v12 */
1247 Assert(serverVersion >= 120000);
1248 appendPQExpBuffer(sql, "%sSKIP_LOCKED", sep);
1249 sep = comma;
1250 }
1251 if (vacopts->full)
1252 {
1253 appendPQExpBuffer(sql, "%sFULL", sep);
1254 sep = comma;
1255 }
1256 if (vacopts->freeze)
1257 {
1258 appendPQExpBuffer(sql, "%sFREEZE", sep);
1259 sep = comma;
1260 }
1261 if (vacopts->verbose)
1262 {
1263 appendPQExpBuffer(sql, "%sVERBOSE", sep);
1264 sep = comma;
1265 }
1266 if (vacopts->and_analyze)
1267 {
1268 appendPQExpBuffer(sql, "%sANALYZE", sep);
1269 sep = comma;
1270 }
1271 if (vacopts->parallel_workers >= 0)
1272 {
1273 /* PARALLEL is supported since v13 */
1274 Assert(serverVersion >= 130000);
1275 appendPQExpBuffer(sql, "%sPARALLEL %d", sep,
1276 vacopts->parallel_workers);
1277 sep = comma;
1278 }
1279 if (vacopts->buffer_usage_limit)
1280 {
1281 Assert(serverVersion >= 160000);
1282 appendPQExpBuffer(sql, "%sBUFFER_USAGE_LIMIT '%s'", sep,
1283 vacopts->buffer_usage_limit);
1284 sep = comma;
1285 }
1286 if (sep != paren)
1287 appendPQExpBufferChar(sql, ')');
1288 }
1289 else
1290 {
1291 if (vacopts->full)
1292 appendPQExpBufferStr(sql, " FULL");
1293 if (vacopts->freeze)
1294 appendPQExpBufferStr(sql, " FREEZE");
1295 if (vacopts->verbose)
1296 appendPQExpBufferStr(sql, " VERBOSE");
1297 if (vacopts->and_analyze)
1298 appendPQExpBufferStr(sql, " ANALYZE");
1299 }
1300 }
1301
1302 appendPQExpBuffer(sql, " %s;", table);
1303}
Assert(PointerIsAligned(start, uint64))
#define comma
Definition: indent_codes.h:48
static const struct lconv_member_info table[]
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
bool skip_database_stats
Definition: vacuumdb.c:48

References vacuumingOptions::analyze_only, vacuumingOptions::and_analyze, appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), Assert(), vacuumingOptions::buffer_usage_limit, comma, vacuumingOptions::disable_page_skipping, vacuumingOptions::do_truncate, vacuumingOptions::force_index_cleanup, vacuumingOptions::freeze, vacuumingOptions::full, vacuumingOptions::no_index_cleanup, vacuumingOptions::parallel_workers, vacuumingOptions::process_main, vacuumingOptions::process_toast, resetPQExpBuffer(), vacuumingOptions::skip_database_stats, vacuumingOptions::skip_locked, table, and vacuumingOptions::verbose.

Referenced by vacuum_one_database().

◆ retrieve_objects()

static SimpleStringList * retrieve_objects ( PGconn conn,
vacuumingOptions vacopts,
SimpleStringList objects,
bool  echo 
)
static

Definition at line 793 of file vacuumdb.c.

795{
797 PQExpBufferData catalog_query;
798 PGresult *res;
800 SimpleStringList *found_objs = palloc0(sizeof(SimpleStringList));
801 bool objects_listed = false;
802
803 initPQExpBuffer(&catalog_query);
804 for (cell = objects ? objects->head : NULL; cell; cell = cell->next)
805 {
806 char *just_table = NULL;
807 const char *just_columns = NULL;
808
809 if (!objects_listed)
810 {
811 appendPQExpBufferStr(&catalog_query,
812 "WITH listed_objects (object_oid, column_list) "
813 "AS (\n VALUES (");
814 objects_listed = true;
815 }
816 else
817 appendPQExpBufferStr(&catalog_query, ",\n (");
818
820 {
821 appendStringLiteralConn(&catalog_query, cell->val, conn);
822 appendPQExpBufferStr(&catalog_query, "::pg_catalog.regnamespace, ");
823 }
824
826 {
827 /*
828 * Split relation and column names given by the user, this is used
829 * to feed the CTE with values on which are performed pre-run
830 * validity checks as well. For now these happen only on the
831 * relation name.
832 */
834 &just_table, &just_columns);
835
836 appendStringLiteralConn(&catalog_query, just_table, conn);
837 appendPQExpBufferStr(&catalog_query, "::pg_catalog.regclass, ");
838 }
839
840 if (just_columns && just_columns[0] != '\0')
841 appendStringLiteralConn(&catalog_query, just_columns, conn);
842 else
843 appendPQExpBufferStr(&catalog_query, "NULL");
844
845 appendPQExpBufferStr(&catalog_query, "::pg_catalog.text)");
846
847 pg_free(just_table);
848 }
849
850 /* Finish formatting the CTE */
851 if (objects_listed)
852 appendPQExpBufferStr(&catalog_query, "\n)\n");
853
854 appendPQExpBufferStr(&catalog_query, "SELECT c.relname, ns.nspname");
855
856 if (objects_listed)
857 appendPQExpBufferStr(&catalog_query, ", listed_objects.column_list");
858
859 appendPQExpBufferStr(&catalog_query,
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 ("
864 CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
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");
868
869 /*
870 * Used to match the tables or schemas listed by the user, completing the
871 * JOIN clause.
872 */
873 if (objects_listed)
874 {
875 appendPQExpBufferStr(&catalog_query, " LEFT JOIN listed_objects"
876 " ON listed_objects.object_oid"
877 " OPERATOR(pg_catalog.=) ");
878
880 appendPQExpBufferStr(&catalog_query, "c.oid\n");
881 else
882 appendPQExpBufferStr(&catalog_query, "ns.oid\n");
883 }
884
885 /*
886 * Exclude temporary tables, beginning the WHERE clause.
887 */
888 appendPQExpBufferStr(&catalog_query,
889 " WHERE c.relpersistence OPERATOR(pg_catalog.!=) "
890 CppAsString2(RELPERSISTENCE_TEMP) "\n");
891
892 /*
893 * Used to match the tables or schemas listed by the user, for the WHERE
894 * clause.
895 */
896 if (objects_listed)
897 {
899 appendPQExpBufferStr(&catalog_query,
900 " AND listed_objects.object_oid IS NULL\n");
901 else
902 appendPQExpBufferStr(&catalog_query,
903 " AND listed_objects.object_oid IS NOT NULL\n");
904 }
905
906 /*
907 * If no tables were listed, filter for the relevant relation types. If
908 * tables were given via --table, don't bother filtering by relation type.
909 * Instead, let the server decide whether a given relation can be
910 * processed in which case the user will know about it.
911 */
912 if ((objfilter & OBJFILTER_TABLE) == 0)
913 {
914 appendPQExpBufferStr(&catalog_query,
915 " AND c.relkind OPERATOR(pg_catalog.=) ANY (array["
916 CppAsString2(RELKIND_RELATION) ", "
917 CppAsString2(RELKIND_MATVIEW) "])\n");
918 }
919
920 /*
921 * For --min-xid-age and --min-mxid-age, the age of the relation is the
922 * greatest of the ages of the main relation and its associated TOAST
923 * table. The commands generated by vacuumdb will also process the TOAST
924 * table for the relation if necessary, so it does not need to be
925 * considered separately.
926 */
927 if (vacopts->min_xid_age != 0)
928 {
929 appendPQExpBuffer(&catalog_query,
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",
935 vacopts->min_xid_age);
936 }
937
938 if (vacopts->min_mxid_age != 0)
939 {
940 appendPQExpBuffer(&catalog_query,
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",
946 vacopts->min_mxid_age);
947 }
948
949 if (vacopts->missing_stats_only)
950 {
951 appendPQExpBufferStr(&catalog_query, " AND (\n");
952
953 /* regular stats */
954 appendPQExpBufferStr(&catalog_query,
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");
965
966 /* extended stats */
967 appendPQExpBufferStr(&catalog_query,
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");
975
976 /* expression indexes */
977 appendPQExpBufferStr(&catalog_query,
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");
992
993 /* inheritance and regular stats */
994 appendPQExpBufferStr(&catalog_query,
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");
1009
1010 /* inheritance and extended stats */
1011 appendPQExpBufferStr(&catalog_query,
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");
1023
1024 appendPQExpBufferStr(&catalog_query, " )\n");
1025 }
1026
1027 /*
1028 * Execute the catalog query. We use the default search_path for this
1029 * query for consistency with table lookups done elsewhere by the user.
1030 */
1031 appendPQExpBufferStr(&catalog_query, " ORDER BY c.relpages DESC;");
1032 executeCommand(conn, "RESET search_path;", echo);
1033 res = executeQuery(conn, catalog_query.data, echo);
1034 termPQExpBuffer(&catalog_query);
1036
1037 /*
1038 * Build qualified identifiers for each table, including the column list
1039 * if given.
1040 */
1042 for (int i = 0; i < PQntuples(res); i++)
1043 {
1046 PQgetvalue(res, i, 0),
1048
1049 if (objects_listed && !PQgetisnull(res, i, 2))
1051
1052 simple_string_list_append(found_objs, buf.data);
1054 }
1056 PQclear(res);
1057
1058 return found_objs;
1059}
void splitTableColumnsSpec(const char *spec, int encoding, char **table, const char **columns)
Definition: common.c:33
#define CppAsString2(x)
Definition: c.h:363
#define ALWAYS_SECURE_SEARCH_PATH_SQL
Definition: connect.h:25
PGresult * executeQuery(PGconn *conn, const char *query)
Definition: connectdb.c:278
int PQclientEncoding(const PGconn *conn)
Definition: fe-connect.c:7709
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3876
void PQclear(PGresult *res)
Definition: fe-exec.c:721
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3481
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3901
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
Definition: isn.c:77
void * palloc0(Size size)
Definition: mcxt.c:1973
static void executeCommand(PGconn *conn, const char *query)
Definition: pg_dumpall.c:1855
static char * buf
Definition: pg_test_fsync.c:72
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
PGconn * conn
Definition: streamutil.c:52
const char * fmtQualifiedIdEnc(const char *schema, const char *id, int encoding)
Definition: string_utils.c:263
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
Definition: string_utils.c:446
char val[FLEXIBLE_ARRAY_MEMBER]
Definition: simple_list.h:37
struct SimpleStringListCell * next
Definition: simple_list.h:34
SimpleStringListCell * head
Definition: simple_list.h:42

References ALWAYS_SECURE_SEARCH_PATH_SQL, appendPQExpBuffer(), appendPQExpBufferStr(), appendStringLiteralConn(), buf, conn, CppAsString2, PQExpBufferData::data, executeCommand(), executeQuery(), fmtQualifiedIdEnc(), SimpleStringList::head, i, initPQExpBuffer(), vacuumingOptions::min_mxid_age, vacuumingOptions::min_xid_age, vacuumingOptions::missing_stats_only, SimpleStringListCell::next, objfilter, OBJFILTER_SCHEMA, OBJFILTER_SCHEMA_EXCLUDE, OBJFILTER_TABLE, palloc0(), pg_free(), PQclear(), PQclientEncoding(), PQgetisnull(), PQgetvalue(), PQntuples(), resetPQExpBuffer(), simple_string_list_append(), splitTableColumnsSpec(), termPQExpBuffer(), and SimpleStringListCell::val.

Referenced by vacuum_one_database().

◆ run_vacuum_command()

static void run_vacuum_command ( PGconn conn,
const char *  sql,
bool  echo,
const char *  table 
)
static

Definition at line 1312 of file vacuumdb.c.

1314{
1315 bool status;
1316
1317 if (echo)
1318 printf("%s\n", sql);
1319
1320 status = PQsendQuery(conn, sql) == 1;
1321
1322 if (!status)
1323 {
1324 if (table)
1325 pg_log_error("vacuuming of table \"%s\" in database \"%s\" failed: %s",
1327 else
1328 pg_log_error("vacuuming of database \"%s\" failed: %s",
1330 }
1331}
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:7447
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7619
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1416

References conn, pg_log_error, PQdb(), PQerrorMessage(), PQsendQuery(), printf, and table.

Referenced by vacuum_one_database().

◆ vacuum_all_databases()

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

Definition at line 1069 of file vacuumdb.c.

1075{
1076 PGconn *conn;
1077 PGresult *result;
1078 int stage;
1079 int i;
1080
1081 conn = connectMaintenanceDatabase(cparams, progname, echo);
1082 result = executeQuery(conn,
1083 "SELECT datname FROM pg_database WHERE datallowconn AND datconnlimit <> -2 ORDER BY 1;",
1084 echo);
1085 PQfinish(conn);
1086
1087 if (analyze_in_stages)
1088 {
1089 SimpleStringList **found_objs = NULL;
1090
1091 if (vacopts->missing_stats_only)
1092 found_objs = palloc0(PQntuples(result) * sizeof(SimpleStringList *));
1093
1094 /*
1095 * When analyzing all databases in stages, we analyze them all in the
1096 * fastest stage first, so that initial statistics become available
1097 * for all of them as soon as possible.
1098 *
1099 * This means we establish several times as many connections, but
1100 * that's a secondary consideration.
1101 */
1102 for (stage = 0; stage < ANALYZE_NUM_STAGES; stage++)
1103 {
1104 for (i = 0; i < PQntuples(result); i++)
1105 {
1106 cparams->override_dbname = PQgetvalue(result, i, 0);
1107
1108 vacuum_one_database(cparams, vacopts,
1109 stage,
1110 objects,
1111 vacopts->missing_stats_only ? &found_objs[i] : NULL,
1112 concurrentCons,
1113 progname, echo, quiet);
1114 }
1115 }
1116 }
1117 else
1118 {
1119 for (i = 0; i < PQntuples(result); i++)
1120 {
1121 cparams->override_dbname = PQgetvalue(result, i, 0);
1122
1123 vacuum_one_database(cparams, vacopts,
1125 objects, NULL,
1126 concurrentCons,
1127 progname, echo, quiet);
1128 }
1129 }
1130
1131 PQclear(result);
1132}
PGconn * connectMaintenanceDatabase(ConnParams *cparams, const char *progname, bool echo)
void PQfinish(PGconn *conn)
Definition: fe-connect.c:5290

References ANALYZE_NO_STAGE, ANALYZE_NUM_STAGES, conn, connectMaintenanceDatabase(), executeQuery(), i, vacuumingOptions::missing_stats_only, _connParams::override_dbname, palloc0(), PQclear(), PQfinish(), PQgetvalue(), PQntuples(), progname, and vacuum_one_database().

Referenced by main().

◆ vacuum_one_database()

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

Definition at line 523 of file vacuumdb.c.

530{
531 PQExpBufferData sql;
532 PGconn *conn;
535 int ntups = 0;
536 bool failed = false;
537 const char *initcmd;
538 SimpleStringList *ret = NULL;
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;"
543 };
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")
548 };
549
550 Assert(stage == ANALYZE_NO_STAGE ||
551 (stage >= 0 && stage < ANALYZE_NUM_STAGES));
552
553 conn = connectDatabase(cparams, progname, echo, false, true);
554
555 if (vacopts->disable_page_skipping && PQserverVersion(conn) < 90600)
556 {
557 PQfinish(conn);
558 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
559 "disable-page-skipping", "9.6");
560 }
561
562 if (vacopts->no_index_cleanup && PQserverVersion(conn) < 120000)
563 {
564 PQfinish(conn);
565 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
566 "no-index-cleanup", "12");
567 }
568
569 if (vacopts->force_index_cleanup && PQserverVersion(conn) < 120000)
570 {
571 PQfinish(conn);
572 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
573 "force-index-cleanup", "12");
574 }
575
576 if (!vacopts->do_truncate && PQserverVersion(conn) < 120000)
577 {
578 PQfinish(conn);
579 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
580 "no-truncate", "12");
581 }
582
583 if (!vacopts->process_main && PQserverVersion(conn) < 160000)
584 {
585 PQfinish(conn);
586 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
587 "no-process-main", "16");
588 }
589
590 if (!vacopts->process_toast && PQserverVersion(conn) < 140000)
591 {
592 PQfinish(conn);
593 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
594 "no-process-toast", "14");
595 }
596
597 if (vacopts->skip_locked && PQserverVersion(conn) < 120000)
598 {
599 PQfinish(conn);
600 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
601 "skip-locked", "12");
602 }
603
604 if (vacopts->min_xid_age != 0 && PQserverVersion(conn) < 90600)
605 {
606 PQfinish(conn);
607 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
608 "--min-xid-age", "9.6");
609 }
610
611 if (vacopts->min_mxid_age != 0 && PQserverVersion(conn) < 90600)
612 {
613 PQfinish(conn);
614 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
615 "--min-mxid-age", "9.6");
616 }
617
618 if (vacopts->parallel_workers >= 0 && PQserverVersion(conn) < 130000)
619 {
620 PQfinish(conn);
621 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
622 "--parallel", "13");
623 }
624
625 if (vacopts->buffer_usage_limit && PQserverVersion(conn) < 160000)
626 {
627 PQfinish(conn);
628 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
629 "--buffer-usage-limit", "16");
630 }
631
632 if (vacopts->missing_stats_only && PQserverVersion(conn) < 150000)
633 {
634 PQfinish(conn);
635 pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
636 "--missing-stats-only", "15");
637 }
638
639 /* skip_database_stats is used automatically if server supports it */
640 vacopts->skip_database_stats = (PQserverVersion(conn) >= 160000);
641
642 if (!quiet)
643 {
644 if (stage != ANALYZE_NO_STAGE)
645 printf(_("%s: processing database \"%s\": %s\n"),
646 progname, PQdb(conn), _(stage_messages[stage]));
647 else
648 printf(_("%s: vacuuming database \"%s\"\n"),
649 progname, PQdb(conn));
650 fflush(stdout);
651 }
652
653 /*
654 * If the caller provided the results of a previous catalog query, just
655 * use that. Otherwise, run the catalog query ourselves and set the
656 * return variable if provided.
657 */
658 if (found_objs && *found_objs)
659 ret = *found_objs;
660 else
661 {
662 ret = retrieve_objects(conn, vacopts, objects, echo);
663 if (found_objs)
664 *found_objs = ret;
665 }
666
667 /*
668 * Count the number of objects in the catalog query result. If there are
669 * none, we are done.
670 */
671 for (cell = ret ? ret->head : NULL; cell; cell = cell->next)
672 ntups++;
673
674 if (ntups == 0)
675 {
676 PQfinish(conn);
677 return;
678 }
679
680 /*
681 * Ensure concurrentCons is sane. If there are more connections than
682 * vacuumable relations, we don't need to use them all.
683 */
684 if (concurrentCons > ntups)
685 concurrentCons = ntups;
686 if (concurrentCons <= 0)
687 concurrentCons = 1;
688
689 /*
690 * All slots need to be prepared to run the appropriate analyze stage, if
691 * caller requested that mode. We have to prepare the initial connection
692 * ourselves before setting up the slots.
693 */
694 if (stage == ANALYZE_NO_STAGE)
695 initcmd = NULL;
696 else
697 {
698 initcmd = stage_commands[stage];
699 executeCommand(conn, initcmd, echo);
700 }
701
702 /*
703 * Setup the database connections. We reuse the connection we already have
704 * for the first slot. If not in parallel mode, the first slot in the
705 * array contains the connection.
706 */
707 sa = ParallelSlotsSetup(concurrentCons, cparams, progname, echo, initcmd);
709
710 initPQExpBuffer(&sql);
711
712 cell = ret->head;
713 do
714 {
715 const char *tabname = cell->val;
716 ParallelSlot *free_slot;
717
718 if (CancelRequested)
719 {
720 failed = true;
721 goto finish;
722 }
723
724 free_slot = ParallelSlotsGetIdle(sa, NULL);
725 if (!free_slot)
726 {
727 failed = true;
728 goto finish;
729 }
730
732 vacopts, tabname);
733
734 /*
735 * Execute the vacuum. All errors are handled in processQueryResult
736 * through ParallelSlotsGetIdle.
737 */
739 run_vacuum_command(free_slot->connection, sql.data,
740 echo, tabname);
741
742 cell = cell->next;
743 } while (cell != NULL);
744
746 {
747 failed = true;
748 goto finish;
749 }
750
751 /* If we used SKIP_DATABASE_STATS, mop up with ONLY_DATABASE_STATS */
752 if (vacopts->skip_database_stats && stage == ANALYZE_NO_STAGE)
753 {
754 const char *cmd = "VACUUM (ONLY_DATABASE_STATS);";
755 ParallelSlot *free_slot = ParallelSlotsGetIdle(sa, NULL);
756
757 if (!free_slot)
758 {
759 failed = true;
760 goto finish;
761 }
762
764 run_vacuum_command(free_slot->connection, cmd, echo, NULL);
765
767 failed = true;
768 }
769
770finish:
772 pg_free(sa);
773
774 termPQExpBuffer(&sql);
775
776 if (failed)
777 exit(1);
778}
#define gettext_noop(x)
Definition: c.h:1167
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
PGconn * connectDatabase(const ConnParams *cparams, const char *progname, bool echo, bool fail_ok, bool allow_password_reuse)
Definition: connect_utils.c:32
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:7609
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)
Definition: parallel_slot.h:47
PGconn * connection
Definition: parallel_slot.h:23
static SimpleStringList * retrieve_objects(PGconn *conn, vacuumingOptions *vacopts, SimpleStringList *objects, bool echo)
Definition: vacuumdb.c:793
static void run_vacuum_command(PGconn *conn, const char *sql, bool echo, const char *table)
Definition: vacuumdb.c:1312
static void prepare_vacuum_command(PQExpBuffer sql, int serverVersion, vacuumingOptions *vacopts, const char *table)
Definition: vacuumdb.c:1142

References _, ANALYZE_NO_STAGE, ANALYZE_NUM_STAGES, Assert(), vacuumingOptions::buffer_usage_limit, CancelRequested, conn, connectDatabase(), ParallelSlot::connection, PQExpBufferData::data, vacuumingOptions::disable_page_skipping, vacuumingOptions::do_truncate, executeCommand(), vacuumingOptions::force_index_cleanup, gettext_noop, SimpleStringList::head, initPQExpBuffer(), vacuumingOptions::min_mxid_age, vacuumingOptions::min_xid_age, vacuumingOptions::missing_stats_only, SimpleStringListCell::next, vacuumingOptions::no_index_cleanup, vacuumingOptions::parallel_workers, ParallelSlotsAdoptConn(), ParallelSlotSetHandler(), ParallelSlotsGetIdle(), ParallelSlotsSetup(), ParallelSlotsTerminate(), ParallelSlotsWaitCompletion(), pg_fatal, pg_free(), PQdb(), PQfinish(), PQserverVersion(), prepare_vacuum_command(), printf, vacuumingOptions::process_main, vacuumingOptions::process_toast, progname, retrieve_objects(), run_vacuum_command(), vacuumingOptions::skip_database_stats, vacuumingOptions::skip_locked, generate_unaccent_rules::stdout, TableCommandResultHandler(), termPQExpBuffer(), and SimpleStringListCell::val.

Referenced by main(), and vacuum_all_databases().

Variable Documentation

◆ objfilter

VacObjFilter objfilter = OBJFILTER_NONE
static

Definition at line 64 of file vacuumdb.c.

Referenced by check_objfilter(), main(), and retrieve_objects().