LCOV - differential code coverage report
Current view: top level - src/bin/scripts - vacuumdb.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 82.6 % 518 428 20 36 29 5 29 170 122 107 48 244 8 41
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 7 7 6 1 7
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 63.0 % 27 17 10 17
Legend: Lines: hit not hit (60,120] days: 75.8 % 62 47 9 5 1 1 33 13
(240..) days: 84.8 % 429 364 1 31 28 5 29 169 72 94 29 156
Function coverage date bins:
(240..) days: 58.3 % 12 7 6 1 5

 Age         Owner                  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
 7235 peter_e                    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'},
 7235 peter_e                   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;
 7235 peter_e                   134 GIC          54 :     const char *dbname = NULL;
 4142 rhaas                     135              54 :     const char *maintenance_db = NULL;
 7235 peter_e                   136              54 :     char       *host = NULL;
                                137              54 :     char       *port = NULL;
                                138              54 :     char       *username = NULL;
 5155                           139              54 :     enum trivalue prompt_password = TRI_DEFAULT;
                                140                 :     ConnParams  cparams;
 7235                           141              54 :     bool        echo = false;
                                142              54 :     bool        quiet = false;
                                143                 :     vacuumingOptions vacopts;
 3282                           144              54 :     bool        analyze_in_stages = false;
  252 andrew                    145 GNC          54 :     SimpleStringList objects = {NULL, NULL};
 2998 alvherre                  146 GIC          54 :     int         concurrentCons = 1;
                                147              54 :     int         tbl_count = 0;
                                148                 : 
                                149                 :     /* initialize options */
                                150              54 :     memset(&vacopts, 0, sizeof(vacopts));
 1166 akapila                   151              54 :     vacopts.parallel_workers = -1;
    2 drowley                   152 GNC          54 :     vacopts.buffer_usage_limit = NULL;
  660 pg                        153 GIC          54 :     vacopts.no_index_cleanup = false;
                                154              54 :     vacopts.force_index_cleanup = false;
 1021 michael                   155 CBC          54 :     vacopts.do_truncate = true;
   34 michael                   156 GNC          54 :     vacopts.process_main = true;
  789 michael                   157 CBC          54 :     vacopts.process_toast = true;
 7235 peter_e                   158 ECB             : 
 1469 peter                     159 CBC          54 :     pg_logging_init(argv[0]);
 7235 peter_e                   160              54 :     progname = get_progname(argv[0]);
 5232                           161              54 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
                                162                 : 
 7235                           163              54 :     handle_help_version_opts(argc, argv, "vacuumdb", help);
 7235 peter_e                   164 ECB             : 
  118 peter                     165 GNC         132 :     while ((c = getopt_long(argc, argv, "ad:efFh:j:n:N:p:P:qt:U:vwWzZ", long_options, &optindex)) != -1)
 7235 peter_e                   166 ECB             :     {
 7235 peter_e                   167 CBC          86 :         switch (c)
 7235 peter_e                   168 ECB             :         {
  118 peter                     169 GNC          10 :             case 'a':
                                170              10 :                 objfilter |= OBJFILTER_ALL_DBS;
 7235 peter_e                   171              10 :                 break;
                                172               1 :             case 'd':
  252 andrew                    173               1 :                 objfilter |= OBJFILTER_DATABASE;
 3831 bruce                     174               1 :                 dbname = pg_strdup(optarg);
 7235 peter_e                   175               1 :                 break;
  118 peter                     176               1 :             case 'e':
                                177               1 :                 echo = true;
 4841 bruce                     178               1 :                 break;
  118 peter                     179               1 :             case 'f':
                                180               1 :                 vacopts.full = true;
 7235 peter_e                   181               1 :                 break;
 5163 bruce                     182               2 :             case 'F':
 2998 alvherre                  183               2 :                 vacopts.freeze = true;
 5163 bruce                     184               2 :                 break;
  118 peter                     185 CBC           2 :             case 'h':
  118 peter                     186 GIC           2 :                 host = pg_strdup(optarg);
 2998 alvherre                  187               2 :                 break;
 2998 alvherre                  188 GNC           1 :             case 'j':
  624 michael                   189               1 :                 if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
                                190                 :                                       &concurrentCons))
 2998 alvherre                  191 UNC           0 :                     exit(1);
 7235 peter_e                   192 GNC           1 :                 break;
  118 peter                     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;
  118 peter                     201 CBC           2 :             case 'p':
                                202               2 :                 port = pg_strdup(optarg);
                                203               2 :                 break;
 1166 akapila                   204 GNC           3 :             case 'P':
  624 michael                   205               3 :                 if (!option_parse_int(optarg, "-P/--parallel", 0, INT_MAX,
                                206                 :                                       &vacopts.parallel_workers))
 1166 akapila                   207               1 :                     exit(1);
                                208               2 :                 break;
  118 peter                     209 UNC           0 :             case 'q':
                                210               0 :                 quiet = true;
                                211               0 :                 break;
  118 peter                     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;
  118 peter                     217 CBC           2 :             case 'U':
                                218               2 :                 username = pg_strdup(optarg);
                                219               2 :                 break;
  118 peter                     220 UNC           0 :             case 'v':
                                221               0 :                 vacopts.verbose = true;
                                222               0 :                 break;
  118 peter                     223 LBC           0 :             case 'w':
                                224               0 :                 prompt_password = TRI_NO;
  118 peter                     225 UIC           0 :                 break;
  118 peter                     226 LBC           0 :             case 'W':
                                227               0 :                 prompt_password = TRI_YES;
                                228               0 :                 break;
  118 peter                     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;
 4142 rhaas                     235 LBC           0 :             case 2:
 3831 bruce                     236 UIC           0 :                 maintenance_db = pg_strdup(optarg);
 4142 rhaas                     237 LBC           0 :                 break;
 3282 peter_e                   238 CBC           2 :             case 3:
 2998 alvherre                  239 GBC           2 :                 analyze_in_stages = vacopts.analyze_only = true;
 3282 peter_e                   240               2 :                 break;
 1552 michael                   241               2 :             case 4:
 1552 michael                   242 CBC           2 :                 vacopts.disable_page_skipping = true;
                                243               2 :                 break;
                                244               2 :             case 5:
                                245               2 :                 vacopts.skip_locked = true;
                                246               2 :                 break;
 1529                           247               2 :             case 6:
  624                           248               2 :                 if (!option_parse_int(optarg, "--min-xid-age", 1, INT_MAX,
  624 michael                   249 ECB             :                                       &vacopts.min_xid_age))
 1529 michael                   250 GBC           1 :                     exit(1);
                                251               1 :                 break;
                                252               2 :             case 7:
  624                           253               2 :                 if (!option_parse_int(optarg, "--min-mxid-age", 1, INT_MAX,
  624 michael                   254 EUB             :                                       &vacopts.min_mxid_age))
 1529 michael                   255 GBC           1 :                     exit(1);
                                256               1 :                 break;
 1021                           257               2 :             case 8:
  660 pg                        258               2 :                 vacopts.no_index_cleanup = true;
 1021 michael                   259 CBC           2 :                 break;
 1021 michael                   260 LBC           0 :             case 9:
  660 pg                        261               0 :                 vacopts.force_index_cleanup = true;
 1021 michael                   262               0 :                 break;
  789 michael                   263 CBC           2 :             case 10:
  660 pg                        264               2 :                 vacopts.do_truncate = false;
  660 pg                        265 GBC           2 :                 break;
                                266               2 :             case 11:
  789 michael                   267               2 :                 vacopts.process_toast = false;
  789 michael                   268 CBC           2 :                 break;
   34 michael                   269 GNC           2 :             case 12:
                                270               2 :                 vacopts.process_main = false;
                                271               2 :                 break;
    2 drowley                   272 UNC           0 :             case 13:
                                273               0 :                 vacopts.buffer_usage_limit = pg_strdup(optarg);
                                274               0 :                 break;
 7235 peter_e                   275 CBC           1 :             default:
  366 tgl                       276 ECB             :                 /* getopt_long already emitted a complaint */
  366 tgl                       277 CBC           1 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 7235 peter_e                   278               1 :                 exit(1);
 7235 peter_e                   279 ECB             :         }
                                280                 :     }
                                281                 : 
 3955 bruce                     282                 :     /*
                                283                 :      * Non-option argument specifies database name as long as it wasn't
                                284                 :      * already specified with -d / --dbname
                                285                 :      */
 4009 andrew                    286 CBC          46 :     if (optind < argc && dbname == NULL)
 7235 peter_e                   287 ECB             :     {
  252 andrew                    288 GNC          37 :         objfilter |= OBJFILTER_DATABASE;
 4009 andrew                    289 CBC          37 :         dbname = argv[optind];
                                290              37 :         optind++;
                                291                 :     }
 4009 andrew                    292 ECB             : 
 4009 andrew                    293 CBC          46 :     if (optind < argc)
 4009 andrew                    294 ECB             :     {
 1469 peter                     295 LBC           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
 1469 peter                     296 ECB             :                      argv[optind]);
  366 tgl                       297 UBC           0 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 4009 andrew                    298               0 :         exit(1);
 7235 peter_e                   299 EUB             :     }
 7235 peter_e                   300 ECB             : 
                                301                 :     /*
                                302                 :      * Validate the combination of filters specified in the command-line
                                303                 :      * options.
                                304                 :      */
  252 andrew                    305 GNC          46 :     check_objfilter();
                                306                 : 
 2998 alvherre                  307 CBC          38 :     if (vacopts.analyze_only)
 4841 bruce                     308 ECB             :     {
 2998 alvherre                  309 CBC          16 :         if (vacopts.full)
  366 tgl                       310 LBC           0 :             pg_fatal("cannot use the \"%s\" option when performing only analyze",
  366 tgl                       311 ECB             :                      "full");
 2998 alvherre                  312 CBC          16 :         if (vacopts.freeze)
  366 tgl                       313 LBC           0 :             pg_fatal("cannot use the \"%s\" option when performing only analyze",
  366 tgl                       314 ECB             :                      "freeze");
 1552 michael                   315 GBC          16 :         if (vacopts.disable_page_skipping)
  366 tgl                       316               1 :             pg_fatal("cannot use the \"%s\" option when performing only analyze",
  366 tgl                       317 EUB             :                      "disable-page-skipping");
  660 pg                        318 CBC          15 :         if (vacopts.no_index_cleanup)
  366 tgl                       319 GIC           1 :             pg_fatal("cannot use the \"%s\" option when performing only analyze",
  366 tgl                       320 ECB             :                      "no-index-cleanup");
  660 pg                        321 CBC          14 :         if (vacopts.force_index_cleanup)
  366 tgl                       322 UIC           0 :             pg_fatal("cannot use the \"%s\" option when performing only analyze",
                                323                 :                      "force-index-cleanup");
 1021 michael                   324 GIC          14 :         if (!vacopts.do_truncate)
  366 tgl                       325               1 :             pg_fatal("cannot use the \"%s\" option when performing only analyze",
                                326                 :                      "no-truncate");
   34 michael                   327 GNC          13 :         if (!vacopts.process_main)
                                328               1 :             pg_fatal("cannot use the \"%s\" option when performing only analyze",
                                329                 :                      "no-process-main");
  789 michael                   330 GIC          12 :         if (!vacopts.process_toast)
  366 tgl                       331               1 :             pg_fatal("cannot use the \"%s\" option when performing only analyze",
  366 tgl                       332 ECB             :                      "no-process-toast");
                                333                 :         /* allow 'and_analyze' with 'analyze_only' */
 4841 bruce                     334                 :     }
                                335                 : 
 1166 akapila                   336                 :     /* Prohibit full and analyze_only options with parallel option */
 1166 akapila                   337 GIC          33 :     if (vacopts.parallel_workers >= 0)
                                338                 :     {
 1166 akapila                   339 CBC           2 :         if (vacopts.analyze_only)
  366 tgl                       340 UIC           0 :             pg_fatal("cannot use the \"%s\" option when performing only analyze",
  366 tgl                       341 EUB             :                      "parallel");
 1166 akapila                   342 GIC           2 :         if (vacopts.full)
  366 tgl                       343 UBC           0 :             pg_fatal("cannot use the \"%s\" option when performing full vacuum",
  366 tgl                       344 EUB             :                      "parallel");
                                345                 :     }
                                346                 : 
                                347                 :     /* Prohibit --no-index-cleanup and --force-index-cleanup together */
  660 pg                        348 GIC          33 :     if (vacopts.no_index_cleanup && vacopts.force_index_cleanup)
  366 tgl                       349 UIC           0 :         pg_fatal("cannot use the \"%s\" option with the \"%s\" option",
                                350                 :                  "no-index-cleanup", "force-index-cleanup");
  660 pg                        351 ECB             : 
                                352                 :     /*
                                353                 :      * buffer-usage-limit is not allowed with VACUUM FULL unless ANALYZE is
                                354                 :      * included too.
                                355                 :      */
    2 drowley                   356 GNC          33 :     if (vacopts.buffer_usage_limit && vacopts.full && !vacopts.and_analyze)
    2 drowley                   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 */
  902 tgl                       361 CBC          33 :     cparams.pghost = host;
  902 tgl                       362 GIC          33 :     cparams.pgport = port;
  902 tgl                       363 CBC          33 :     cparams.pguser = username;
  902 tgl                       364 GBC          33 :     cparams.prompt_password = prompt_password;
  902 tgl                       365 GIC          33 :     cparams.override_dbname = NULL;
  902 tgl                       366 ECB             : 
 1224 michael                   367 GBC          33 :     setup_cancel_handler(NULL);
                                368                 : 
 2998 alvherre                  369 ECB             :     /* Avoid opening extra connections. */
 2998 alvherre                  370 CBC          33 :     if (tbl_count && (concurrentCons > tbl_count))
 2998 alvherre                  371 UIC           0 :         concurrentCons = tbl_count;
 2998 alvherre                  372 ECB             : 
  252 andrew                    373 GNC          33 :     if (objfilter & OBJFILTER_ALL_DBS)
                                374                 :     {
  902 tgl                       375 GIC           5 :         cparams.dbname = maintenance_db;
  902 tgl                       376 ECB             : 
  902 tgl                       377 CBC           5 :         vacuum_all_databases(&cparams, &vacopts,
                                378                 :                              analyze_in_stages,
 2998 alvherre                  379 ECB             :                              concurrentCons,
                                380                 :                              progname, echo, quiet);
                                381                 :     }
                                382                 :     else
                                383                 :     {
 7235 peter_e                   384 GIC          28 :         if (dbname == NULL)
                                385                 :         {
 7235 peter_e                   386 LBC           0 :             if (getenv("PGDATABASE"))
 7235 peter_e                   387 UIC           0 :                 dbname = getenv("PGDATABASE");
 7235 peter_e                   388 LBC           0 :             else if (getenv("PGUSER"))
 7235 peter_e                   389 UBC           0 :                 dbname = getenv("PGUSER");
                                390                 :             else
 3399 bruce                     391 LBC           0 :                 dbname = get_user_name_or_exit(progname);
 7235 peter_e                   392 EUB             :         }
                                393                 : 
  902 tgl                       394 GIC          28 :         cparams.dbname = dbname;
                                395                 : 
 2998 alvherre                  396              28 :         if (analyze_in_stages)
 3734 magnus                    397 ECB             :         {
 2998 alvherre                  398 EUB             :             int         stage;
                                399                 : 
 2998 alvherre                  400 GIC           4 :             for (stage = 0; stage < ANALYZE_NUM_STAGES; stage++)
                                401                 :             {
  902 tgl                       402               3 :                 vacuum_one_database(&cparams, &vacopts,
                                403                 :                                     stage,
                                404                 :                                     &objects,
 2998 alvherre                  405 ECB             :                                     concurrentCons,
 2664 tgl                       406 EUB             :                                     progname, echo, quiet);
                                407                 :             }
                                408                 :         }
                                409                 :         else
  902 tgl                       410 CBC          27 :             vacuum_one_database(&cparams, &vacopts,
 2998 alvherre                  411 ECB             :                                 ANALYZE_NO_STAGE,
                                412                 :                                 &objects,
                                413                 :                                 concurrentCons,
 2664 tgl                       414                 :                                 progname, echo, quiet);
                                415                 :     }
 7235 peter_e                   416                 : 
 7235 peter_e                   417 GIC          30 :     exit(0);
                                418                 : }
 7235 peter_e                   419 ECB             : 
                                420                 : /*
                                421                 :  * Verify that the filters used at command line are compatible.
                                422                 :  */
                                423                 : void
  252 andrew                    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                 : 
 2998 alvherre                  455 EUB             : /*
                                456                 :  * vacuum_one_database
 2998 alvherre                  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                 :  */
 3282 peter_e                   468                 : static void
  759 rhaas                     469 GIC          49 : vacuum_one_database(ConnParams *cparams,
  902 tgl                       470 EUB             :                     vacuumingOptions *vacopts,
 2998 alvherre                  471                 :                     int stage,
                                472                 :                     SimpleStringList *objects,
                                473                 :                     int concurrentCons,
                                474                 :                     const char *progname, bool echo, bool quiet)
 3282 peter_e                   475                 : {
                                476                 :     PQExpBufferData sql;
                                477                 :     PQExpBufferData buf;
 1531 michael                   478 ECB             :     PQExpBufferData catalog_query;
                                479                 :     PGresult   *res;
 2998 alvherre                  480                 :     PGconn     *conn;
                                481                 :     SimpleStringListCell *cell;
                                482                 :     ParallelSlotArray *sa;
 2998 alvherre                  483 GIC          49 :     SimpleStringList dbtables = {NULL, NULL};
 2998 alvherre                  484 ECB             :     int         i;
                                485                 :     int         ntups;
 2797 andres                    486 CBC          49 :     bool        failed = false;
  252 andrew                    487 GNC          49 :     bool        objects_listed = false;
 1529 michael                   488 GIC          49 :     bool        has_where = false;
                                489                 :     const char *initcmd;
 2998 alvherre                  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;"
 2998 alvherre                  494 ECB             :     };
 2998 alvherre                  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                 : 
 2998 alvherre                  501 CBC          49 :     Assert(stage == ANALYZE_NO_STAGE ||
                                502                 :            (stage >= 0 && stage < ANALYZE_NUM_STAGES));
                                503                 : 
  902 tgl                       504 GIC          49 :     conn = connectDatabase(cparams, progname, echo, false, true);
                                505                 : 
 1552 michael                   506              49 :     if (vacopts->disable_page_skipping && PQserverVersion(conn) < 90600)
                                507                 :     {
 1552 michael                   508 LBC           0 :         PQfinish(conn);
  366 tgl                       509 UIC           0 :         pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
  366 tgl                       510 ECB             :                  "disable-page-skipping", "9.6");
 1552 michael                   511                 :     }
                                512                 : 
  660 pg                        513 GIC          49 :     if (vacopts->no_index_cleanup && PQserverVersion(conn) < 120000)
 1021 michael                   514 ECB             :     {
 1021 michael                   515 LBC           0 :         PQfinish(conn);
  366 tgl                       516               0 :         pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
                                517                 :                  "no-index-cleanup", "12");
 1021 michael                   518 ECB             :     }
                                519                 : 
  660 pg                        520 CBC          49 :     if (vacopts->force_index_cleanup && PQserverVersion(conn) < 120000)
                                521                 :     {
  660 pg                        522 LBC           0 :         PQfinish(conn);
  366 tgl                       523               0 :         pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
  366 tgl                       524 ECB             :                  "force-index-cleanup", "12");
                                525                 :     }
  660 pg                        526                 : 
 1021 michael                   527 CBC          49 :     if (!vacopts->do_truncate && PQserverVersion(conn) < 120000)
 1021 michael                   528 ECB             :     {
 1021 michael                   529 UIC           0 :         PQfinish(conn);
  366 tgl                       530 LBC           0 :         pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
  366 tgl                       531 ECB             :                  "no-truncate", "12");
 1021 michael                   532                 :     }
                                533                 : 
   34 michael                   534 GNC          49 :     if (!vacopts->process_main && PQserverVersion(conn) < 160000)
                                535                 :     {
   34 michael                   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                 : 
  789 michael                   541 CBC          49 :     if (!vacopts->process_toast && PQserverVersion(conn) < 140000)
  789 michael                   542 ECB             :     {
  789 michael                   543 LBC           0 :         PQfinish(conn);
  366 tgl                       544               0 :         pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
                                545                 :                  "no-process-toast", "14");
                                546                 :     }
                                547                 : 
 1552 michael                   548 GIC          49 :     if (vacopts->skip_locked && PQserverVersion(conn) < 120000)
                                549                 :     {
 1552 michael                   550 UIC           0 :         PQfinish(conn);
  366 tgl                       551               0 :         pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
                                552                 :                  "skip-locked", "12");
                                553                 :     }
                                554                 : 
 1529 michael                   555 GIC          49 :     if (vacopts->min_xid_age != 0 && PQserverVersion(conn) < 90600)
  366 tgl                       556 UIC           0 :         pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
                                557                 :                  "--min-xid-age", "9.6");
                                558                 : 
 1529 michael                   559 GIC          49 :     if (vacopts->min_mxid_age != 0 && PQserverVersion(conn) < 90600)
  366 tgl                       560 LBC           0 :         pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
                                561                 :                  "--min-mxid-age", "9.6");
                                562                 : 
 1166 akapila                   563 GIC          49 :     if (vacopts->parallel_workers >= 0 && PQserverVersion(conn) < 130000)
  366 tgl                       564 UIC           0 :         pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
                                565                 :                  "--parallel", "13");
                                566                 : 
    2 drowley                   567 GNC          49 :     if (vacopts->buffer_usage_limit && PQserverVersion(conn) < 160000)
    2 drowley                   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 */
   93 tgl                       572 GNC          49 :     vacopts->skip_database_stats = (PQserverVersion(conn) >= 160000);
                                573                 : 
 2998 alvherre                  574 GIC          49 :     if (!quiet)
                                575                 :     {
                                576              49 :         if (stage != ANALYZE_NO_STAGE)
 2435 noah                      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"),
 2435 noah                      581 ECB             :                    progname, PQdb(conn));
 2998 alvherre                  582 GIC          49 :         fflush(stdout);
                                583                 :     }
 3282 peter_e                   584 ECB             : 
 2998 alvherre                  585                 :     /*
 1531 michael                   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                 :      */
 1531 michael                   599 CBC          49 :     initPQExpBuffer(&catalog_query);
  252 andrew                    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;
 2998 alvherre                  604 ECB             : 
  252 andrew                    605 GNC          12 :         if (!objects_listed)
 1531 michael                   606 EUB             :         {
 1375 drowley                   607 GIC          12 :             appendPQExpBufferStr(&catalog_query,
                                608                 :                                  "WITH listed_objects (object_oid, column_list) "
                                609                 :                                  "AS (\n  VALUES (");
  252 andrew                    610 GNC          12 :             objects_listed = true;
                                611                 :         }
 1531 michael                   612 EUB             :         else
 1375 drowley                   613 UBC           0 :             appendPQExpBufferStr(&catalog_query, ",\n  (");
                                614                 : 
  252 andrew                    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                 :         }
 2998 alvherre                  635 ECB             : 
 1531 michael                   636 GIC          12 :         if (just_columns && just_columns[0] != '\0')
 1531 michael                   637 GBC           5 :             appendStringLiteralConn(&catalog_query, just_columns, conn);
 1531 michael                   638 EUB             :         else
 1531 michael                   639 GIC           7 :             appendPQExpBufferStr(&catalog_query, "NULL");
                                640                 : 
                                641              12 :         appendPQExpBufferStr(&catalog_query, "::pg_catalog.text)");
 1531 michael                   642 ECB             : 
 1531 michael                   643 GIC          12 :         pg_free(just_table);
 1531 michael                   644 EUB             :     }
                                645                 : 
                                646                 :     /* Finish formatting the CTE */
  252 andrew                    647 GNC          49 :     if (objects_listed)
 1375 drowley                   648 GIC          12 :         appendPQExpBufferStr(&catalog_query, "\n)\n");
 1531 michael                   649 ECB             : 
 1375 drowley                   650 GIC          49 :     appendPQExpBufferStr(&catalog_query, "SELECT c.relname, ns.nspname");
 1531 michael                   651 EUB             : 
  252 andrew                    652 GNC          49 :     if (objects_listed)
                                653              12 :         appendPQExpBufferStr(&catalog_query, ", listed_objects.column_list");
                                654                 : 
 1375 drowley                   655 GIC          49 :     appendPQExpBufferStr(&catalog_query,
 1375 drowley                   656 ECB             :                          " FROM pg_catalog.pg_class c\n"
                                657                 :                          " JOIN pg_catalog.pg_namespace ns"
 1375 drowley                   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 */
  252 andrew                    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                 : 
 1530 michael                   679 ECB             :     /*
 1530 michael                   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
 1530 michael                   683 ECB             :      * processed in which case the user will know about it.
 1530 michael                   684 EUB             :      */
  252 andrew                    685 GNC          49 :     if ((objfilter & OBJFILTER_TABLE) == 0)
                                686                 :     {
 1375 drowley                   687 CBC          39 :         appendPQExpBufferStr(&catalog_query, " WHERE c.relkind OPERATOR(pg_catalog.=) ANY (array["
 1375 drowley                   688 EUB             :                              CppAsString2(RELKIND_RELATION) ", "
                                689                 :                              CppAsString2(RELKIND_MATVIEW) "])\n");
 1529 michael                   690 GIC          39 :         has_where = true;
                                691                 :     }
 1529 michael                   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                 :      */
 1529 michael                   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);
 1529 michael                   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.!=)"
 1529 michael                   719 ECB             :                           " '0'::pg_catalog.xid\n",
                                720                 :                           has_where ? "AND" : "WHERE", vacopts->min_mxid_age);
 1529 michael                   721 GIC           1 :         has_where = true;
 1529 michael                   722 ECB             :     }
 1531                           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                 :      */
 1375 drowley                   728 GIC          49 :     appendPQExpBufferStr(&catalog_query, " ORDER BY c.relpages DESC;");
 1360 michael                   729              49 :     executeCommand(conn, "RESET search_path;", echo);
 1360 michael                   730 CBC          49 :     res = executeQuery(conn, catalog_query.data, echo);
 1531 michael                   731 GIC          48 :     termPQExpBuffer(&catalog_query);
 1360                           732              48 :     PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
 1531 michael                   733 EUB             : 
                                734                 :     /*
 1531 michael                   735 ECB             :      * If no rows are returned, there are no matching tables, so we are done.
                                736                 :      */
 1531 michael                   737 CBC          48 :     ntups = PQntuples(res);
                                738              48 :     if (ntups == 0)
                                739                 :     {
 1531 michael                   740 GIC           2 :         PQclear(res);
 1531 michael                   741 CBC           2 :         PQfinish(conn);
 1531 michael                   742 GIC           2 :         return;
                                743                 :     }
                                744                 : 
                                745                 :     /*
                                746                 :      * Build qualified identifiers for each table, including the column list
                                747                 :      * if given.
                                748                 :      */
 1531 michael                   749 CBC          46 :     initPQExpBuffer(&buf);
 1531 michael                   750 GIC        2574 :     for (i = 0; i < ntups; i++)
                                751                 :     {
 1531 michael                   752 CBC        2528 :         appendPQExpBufferStr(&buf,
                                753            2528 :                              fmtQualifiedId(PQgetvalue(res, i, 1),
 1531 michael                   754 GIC        2528 :                                             PQgetvalue(res, i, 0)));
                                755                 : 
  252 andrew                    756 GNC        2528 :         if (objects_listed && !PQgetisnull(res, i, 2))
 1531 michael                   757 CBC           5 :             appendPQExpBufferStr(&buf, PQgetvalue(res, i, 2));
                                758                 : 
                                759            2528 :         simple_string_list_append(&dbtables, buf.data);
 1531 michael                   760 GIC        2528 :         resetPQExpBuffer(&buf);
 1531 michael                   761 ECB             :     }
 1531 michael                   762 GIC          46 :     termPQExpBuffer(&buf);
 1531 michael                   763 CBC          46 :     PQclear(res);
                                764                 : 
                                765                 :     /*
                                766                 :      * Ensure concurrentCons is sane.  If there are more connections than
  947 tgl                       767 ECB             :      * vacuumable relations, we don't need to use them all.
 1531 michael                   768                 :      */
  947 tgl                       769 GIC          46 :     if (concurrentCons > ntups)
  947 tgl                       770 LBC           0 :         concurrentCons = ntups;
  947 tgl                       771 GIC          46 :     if (concurrentCons <= 0)
  947 tgl                       772 LBC           0 :         concurrentCons = 1;
 2998 alvherre                  773 ECB             : 
                                774                 :     /*
  759 rhaas                     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                 :      */
  759 rhaas                     779 GIC          46 :     if (stage == ANALYZE_NO_STAGE)
                                780              37 :         initcmd = NULL;
                                781                 :     else
                                782                 :     {
  759 rhaas                     783 CBC           9 :         initcmd = stage_commands[stage];
  759 rhaas                     784 GIC           9 :         executeCommand(conn, initcmd, echo);
  759 rhaas                     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.
 2998 alvherre                  791                 :      */
  759 rhaas                     792 GIC          46 :     sa = ParallelSlotsSetup(concurrentCons, cparams, progname, echo, initcmd);
  759 rhaas                     793 CBC          46 :     ParallelSlotsAdoptConn(sa, conn);
 2998 alvherre                  794 ECB             : 
 1531 michael                   795 GIC          46 :     initPQExpBuffer(&sql);
 1531 michael                   796 ECB             : 
 1531 michael                   797 GIC          46 :     cell = dbtables.head;
                                798                 :     do
                                799                 :     {
                                800            2528 :         const char *tabname = cell->val;
                                801                 :         ParallelSlot *free_slot;
                                802                 : 
 2998 alvherre                  803            2528 :         if (CancelRequested)
                                804                 :         {
 2797 andres                    805 LBC           0 :             failed = true;
 2998 alvherre                  806 UIC           0 :             goto finish;
 2998 alvherre                  807 ECB             :         }
                                808                 : 
  759 rhaas                     809 GIC        2528 :         free_slot = ParallelSlotsGetIdle(sa, NULL);
 1360 michael                   810 CBC        2528 :         if (!free_slot)
                                811                 :         {
 1360 michael                   812 UIC           0 :             failed = true;
                                813               0 :             goto finish;
                                814                 :         }
                                815                 : 
 1531 michael                   816 GIC        2528 :         prepare_vacuum_command(&sql, PQserverVersion(free_slot->connection),
                                817                 :                                vacopts, tabname);
                                818                 : 
                                819                 :         /*
 1360 michael                   820 ECB             :          * Execute the vacuum.  All errors are handled in processQueryResult
                                821                 :          * through ParallelSlotsGetIdle.
 2939 alvherre                  822                 :          */
  793 rhaas                     823 GIC        2528 :         ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL);
 2998 alvherre                  824            2528 :         run_vacuum_command(free_slot->connection, sql.data,
                                825                 :                            echo, tabname);
                                826                 : 
 1531 michael                   827            2528 :         cell = cell->next;
 2998 alvherre                  828            2528 :     } while (cell != NULL);
 2998 alvherre                  829 ECB             : 
  759 rhaas                     830 GIC          46 :     if (!ParallelSlotsWaitCompletion(sa))
                                831                 :     {
 1360 michael                   832               2 :         failed = true;
   93 tgl                       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                 :         {
   93 tgl                       844 UNC           0 :             failed = true;
                                845               0 :             goto finish;
                                846                 :         }
                                847                 : 
   93 tgl                       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))
   93 tgl                       852 UNC           0 :             failed = true;
                                853                 :     }
 2998 alvherre                  854 ECB             : 
 2998 alvherre                  855 GIC          44 : finish:
  759 rhaas                     856 CBC          46 :     ParallelSlotsTerminate(sa);
  759 rhaas                     857 GIC          46 :     pg_free(sa);
                                858                 : 
 2998 alvherre                  859              46 :     termPQExpBuffer(&sql);
                                860                 : 
 2797 andres                    861              46 :     if (failed)
 2998 alvherre                  862               2 :         exit(1);
 2998 alvherre                  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                 :  */
 7038 tgl                       872                 : static void
  902 tgl                       873 CBC           5 : vacuum_all_databases(ConnParams *cparams,
  902 tgl                       874 ECB             :                      vacuumingOptions *vacopts,
                                875                 :                      bool analyze_in_stages,
                                876                 :                      int concurrentCons,
                                877                 :                      const char *progname, bool echo, bool quiet)
                                878                 : {
 7235 peter_e                   879                 :     PGconn     *conn;
 2998 alvherre                  880                 :     PGresult   *result;
                                881                 :     int         stage;
                                882                 :     int         i;
 7235 peter_e                   883                 : 
  902 tgl                       884 CBC           5 :     conn = connectMaintenanceDatabase(cparams, progname, echo);
 2998 alvherre                  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)
 2998 alvherre                  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                 :          */
 2998 alvherre                  900 GIC           4 :         for (stage = 0; stage < ANALYZE_NUM_STAGES; stage++)
 2998 alvherre                  901 ECB             :         {
 2998 alvherre                  902 CBC           9 :             for (i = 0; i < PQntuples(result); i++)
                                903                 :             {
  902 tgl                       904               6 :                 cparams->override_dbname = PQgetvalue(result, i, 0);
 2998 alvherre                  905 ECB             : 
  902 tgl                       906 GIC           6 :                 vacuum_one_database(cparams, vacopts,
                                907                 :                                     stage,
                                908                 :                                     NULL,
                                909                 :                                     concurrentCons,
                                910                 :                                     progname, echo, quiet);
 2998 alvherre                  911 ECB             :             }
 2998 alvherre                  912 EUB             :         }
 2998 alvherre                  913 ECB             :     }
 2998 alvherre                  914 EUB             :     else
                                915                 :     {
 2998 alvherre                  916 GIC          17 :         for (i = 0; i < PQntuples(result); i++)
                                917                 :         {
  902 tgl                       918              13 :             cparams->override_dbname = PQgetvalue(result, i, 0);
                                919                 : 
                                920              13 :             vacuum_one_database(cparams, vacopts,
 2998 alvherre                  921 ECB             :                                 ANALYZE_NO_STAGE,
                                922                 :                                 NULL,
                                923                 :                                 concurrentCons,
                                924                 :                                 progname, echo, quiet);
                                925                 :         }
                                926                 :     }
                                927                 : 
 2998 alvherre                  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.
 2998 alvherre                  934 ECB             :  *
 1531 michael                   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.
 2998 alvherre                  937                 :  */
                                938                 : static void
 1531 michael                   939 CBC        2528 : prepare_vacuum_command(PQExpBuffer sql, int serverVersion,
                                940                 :                        vacuumingOptions *vacopts, const char *table)
                                941                 : {
 1552                           942            2528 :     const char *paren = " (";
 1552 michael                   943 GIC        2528 :     const char *comma = ", ";
                                944            2528 :     const char *sep = paren;
 1552 michael                   945 ECB             : 
 2998 alvherre                  946 GIC        2528 :     resetPQExpBuffer(sql);
 2998 alvherre                  947 EUB             : 
 2998 alvherre                  948 GBC        2528 :     if (vacopts->analyze_only)
                                949                 :     {
 2998 alvherre                  950 GIC        1229 :         appendPQExpBufferStr(sql, "ANALYZE");
 1552 michael                   951 ECB             : 
                                952                 :         /* parenthesized grammar of ANALYZE is supported since v11 */
 1531 michael                   953 GIC        1229 :         if (serverVersion >= 110000)
 1552 michael                   954 EUB             :         {
 1552 michael                   955 GBC        1229 :             if (vacopts->skip_locked)
                                956                 :             {
                                957                 :                 /* SKIP_LOCKED is supported since v12 */
 1531 michael                   958 CBC          68 :                 Assert(serverVersion >= 120000);
 1552 michael                   959 GIC          68 :                 appendPQExpBuffer(sql, "%sSKIP_LOCKED", sep);
                                960              68 :                 sep = comma;
                                961                 :             }
                                962            1229 :             if (vacopts->verbose)
                                963                 :             {
 1552 michael                   964 UIC           0 :                 appendPQExpBuffer(sql, "%sVERBOSE", sep);
 1552 michael                   965 LBC           0 :                 sep = comma;
 1552 michael                   966 ECB             :             }
 1552 michael                   967 GIC        1229 :             if (sep != paren)
                                968              68 :                 appendPQExpBufferChar(sql, ')');
 1552 michael                   969 ECB             :         }
                                970                 :         else
                                971                 :         {
 1552 michael                   972 LBC           0 :             if (vacopts->verbose)
 1552 michael                   973 UIC           0 :                 appendPQExpBufferStr(sql, " VERBOSE");
 1552 michael                   974 ECB             :         }
 4841 itagaki.takahiro          975                 :     }
                                976                 :     else
                                977                 :     {
 2998 alvherre                  978 GIC        1299 :         appendPQExpBufferStr(sql, "VACUUM");
 1552 michael                   979 ECB             : 
                                980                 :         /* parenthesized grammar of VACUUM is supported since v9.0 */
 1531 michael                   981 CBC        1299 :         if (serverVersion >= 90000)
 4841 itagaki.takahiro          982 ECB             :         {
 1552 michael                   983 GIC        1299 :             if (vacopts->disable_page_skipping)
 1552 michael                   984 ECB             :             {
                                985                 :                 /* DISABLE_PAGE_SKIPPING is supported since v9.6 */
 1531 michael                   986 GBC          68 :                 Assert(serverVersion >= 90600);
 1552                           987              68 :                 appendPQExpBuffer(sql, "%sDISABLE_PAGE_SKIPPING", sep);
 1552 michael                   988 GIC          68 :                 sep = comma;
                                989                 :             }
  660 pg                        990 CBC        1299 :             if (vacopts->no_index_cleanup)
 1021 michael                   991 ECB             :             {
                                992                 :                 /* "INDEX_CLEANUP FALSE" has been supported since v12 */
 1021 michael                   993 CBC          68 :                 Assert(serverVersion >= 120000);
  660 pg                        994 GBC          68 :                 Assert(!vacopts->force_index_cleanup);
 1021 michael                   995 GIC          68 :                 appendPQExpBuffer(sql, "%sINDEX_CLEANUP FALSE", sep);
                                996              68 :                 sep = comma;
 1021 michael                   997 ECB             :             }
  660 pg                        998 CBC        1299 :             if (vacopts->force_index_cleanup)
  660 pg                        999 ECB             :             {
                               1000                 :                 /* "INDEX_CLEANUP TRUE" has been supported since v12 */
  660 pg                       1001 LBC           0 :                 Assert(serverVersion >= 120000);
  660 pg                       1002 UIC           0 :                 Assert(!vacopts->no_index_cleanup);
  660 pg                       1003 LBC           0 :                 appendPQExpBuffer(sql, "%sINDEX_CLEANUP TRUE", sep);
                               1004               0 :                 sep = comma;
                               1005                 :             }
 1021 michael                  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                 :             }
   34 michael                  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                 :             }
  789 michael                  1020 GIC        1299 :             if (!vacopts->process_toast)
                               1021                 :             {
  789 michael                  1022 ECB             :                 /* PROCESS_TOAST is supported since v14 */
  789 michael                  1023 GIC          68 :                 Assert(serverVersion >= 140000);
                               1024              68 :                 appendPQExpBuffer(sql, "%sPROCESS_TOAST FALSE", sep);
                               1025              68 :                 sep = comma;
                               1026                 :             }
   93 tgl                      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                 :             }
 1552 michael                  1034 GIC        1299 :             if (vacopts->skip_locked)
                               1035                 :             {
                               1036                 :                 /* SKIP_LOCKED is supported since v12 */
 1531                          1037              68 :                 Assert(serverVersion >= 120000);
 1552                          1038              68 :                 appendPQExpBuffer(sql, "%sSKIP_LOCKED", sep);
                               1039              68 :                 sep = comma;
 1552 michael                  1040 ECB             :             }
 2998 alvherre                 1041 CBC        1299 :             if (vacopts->full)
                               1042                 :             {
 2998 alvherre                 1043 GIC          68 :                 appendPQExpBuffer(sql, "%sFULL", sep);
 4841 itagaki.takahiro         1044 CBC          68 :                 sep = comma;
                               1045                 :             }
 2998 alvherre                 1046            1299 :             if (vacopts->freeze)
                               1047                 :             {
 2998 alvherre                 1048 GIC         204 :                 appendPQExpBuffer(sql, "%sFREEZE", sep);
 4841 itagaki.takahiro         1049             204 :                 sep = comma;
                               1050                 :             }
 2998 alvherre                 1051            1299 :             if (vacopts->verbose)
                               1052                 :             {
 2998 alvherre                 1053 UIC           0 :                 appendPQExpBuffer(sql, "%sVERBOSE", sep);
 4841 itagaki.takahiro         1054               0 :                 sep = comma;
                               1055                 :             }
 2998 alvherre                 1056 CBC        1299 :             if (vacopts->and_analyze)
                               1057                 :             {
                               1058             207 :                 appendPQExpBuffer(sql, "%sANALYZE", sep);
 4841 itagaki.takahiro         1059 GIC         207 :                 sep = comma;
 4841 itagaki.takahiro         1060 ECB             :             }
 1166 akapila                  1061 GIC        1299 :             if (vacopts->parallel_workers >= 0)
 1166 akapila                  1062 ECB             :             {
                               1063                 :                 /* PARALLEL is supported since v13 */
 1166 akapila                  1064 GIC         136 :                 Assert(serverVersion >= 130000);
                               1065             136 :                 appendPQExpBuffer(sql, "%sPARALLEL %d", sep,
                               1066                 :                                   vacopts->parallel_workers);
                               1067             136 :                 sep = comma;
                               1068                 :             }
    2 drowley                  1069 GNC        1299 :             if (vacopts->buffer_usage_limit)
                               1070                 :             {
    2 drowley                  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                 :             }
 4841 itagaki.takahiro         1076 GIC        1299 :             if (sep != paren)
 2838 heikki.linnakangas       1077            1299 :                 appendPQExpBufferChar(sql, ')');
                               1078                 :         }
 4841 itagaki.takahiro         1079 ECB             :         else
                               1080                 :         {
 2998 alvherre                 1081 LBC           0 :             if (vacopts->full)
 2998 alvherre                 1082 UIC           0 :                 appendPQExpBufferStr(sql, " FULL");
 2998 alvherre                 1083 LBC           0 :             if (vacopts->freeze)
 2998 alvherre                 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                 :     }
 2998 alvherre                 1091 ECB             : 
 1531 michael                  1092 CBC        2528 :     appendPQExpBuffer(sql, " %s;", table);
 2998 alvherre                 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
 2998 alvherre                 1102 CBC        2563 : run_vacuum_command(PGconn *conn, const char *sql, bool echo,
                               1103                 :                    const char *table)
                               1104                 : {
 2878 bruce                    1105 ECB             :     bool        status;
 2939 alvherre                 1106                 : 
 1360 michael                  1107 CBC        2563 :     if (echo)
 1360 michael                  1108 GIC         483 :         printf("%s\n", sql);
 2998 alvherre                 1109 ECB             : 
 1360 michael                  1110 GIC        2563 :     status = PQsendQuery(conn, sql) == 1;
 2939 alvherre                 1111 ECB             : 
 2939 alvherre                 1112 GIC        2563 :     if (!status)
 2998 alvherre                 1113 ECB             :     {
 2998 alvherre                 1114 UIC           0 :         if (table)
 1469 peter                    1115               0 :             pg_log_error("vacuuming of table \"%s\" in database \"%s\" failed: %s",
 1469 peter                    1116 ECB             :                          table, PQdb(conn), PQerrorMessage(conn));
                               1117                 :         else
 1469 peter                    1118 LBC           0 :             pg_log_error("vacuuming of database \"%s\" failed: %s",
                               1119                 :                          PQdb(conn), PQerrorMessage(conn));
                               1120                 :     }
 2998 alvherre                 1121 CBC        2563 : }
 2998 alvherre                 1122 ECB             : 
 7235 peter_e                  1123                 : static void
 7235 peter_e                  1124 GIC           1 : help(const char *progname)
 7235 peter_e                  1125 ECB             : {
 7235 peter_e                  1126 GIC           1 :     printf(_("%s cleans and analyzes a PostgreSQL database.\n\n"), progname);
 7235 peter_e                  1127 GBC           1 :     printf(_("Usage:\n"));
                               1128               1 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
 7235 peter_e                  1129 GIC           1 :     printf(_("\nOptions:\n"));
 7235 peter_e                  1130 CBC           1 :     printf(_("  -a, --all                       vacuum all databases\n"));
                               1131               1 :     printf(_("  -d, --dbname=DBNAME             database to vacuum\n"));
 1552 michael                  1132 GIC           1 :     printf(_("      --disable-page-skipping     disable all page-skipping behavior\n"));
 5156 peter_e                  1133               1 :     printf(_("  -e, --echo                      show the commands being sent to the server\n"));
 7235                          1134               1 :     printf(_("  -f, --full                      do full vacuuming\n"));
 5163 bruce                    1135 GBC           1 :     printf(_("  -F, --freeze                    freeze row transaction information\n"));
  653 peter                    1136               1 :     printf(_("      --force-index-cleanup       always remove index entries that point to dead tuples\n"));
 2762 peter_e                  1137 GIC           1 :     printf(_("  -j, --jobs=NUM                  use this many concurrent connections to vacuum\n"));
 1529 michael                  1138               1 :     printf(_("      --min-mxid-age=MXID_AGE     minimum multixact ID age of tables to vacuum\n"));
    2 drowley                  1139 GNC           1 :     printf(_("      --buffer-usage-limit=BUFSIZE size of ring buffer used for vacuum\n"));
 1529 michael                  1140 GIC           1 :     printf(_("      --min-xid-age=XID_AGE       minimum transaction ID age of tables to vacuum\n"));
 1021                          1141               1 :     printf(_("      --no-index-cleanup          don't remove index entries that point to dead tuples\n"));
   34 michael                  1142 GNC           1 :     printf(_("      --no-process-main           skip the main relation\n"));
  789 michael                  1143 CBC           1 :     printf(_("      --no-process-toast          skip the TOAST table associated with the table to vacuum\n"));
 1021 michael                  1144 GIC           1 :     printf(_("      --no-truncate               don't truncate empty pages at the end of the table\n"));
  252 andrew                   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"));
  684 akapila                  1147 GIC           1 :     printf(_("  -P, --parallel=PARALLEL_WORKERS use this many background workers for vacuum, if available\n"));
 7235 peter_e                  1148 CBC           1 :     printf(_("  -q, --quiet                     don't write any messages\n"));
 1552 michael                  1149 GIC           1 :     printf(_("      --skip-locked               skip relations that cannot be immediately locked\n"));
 3734 magnus                   1150 CBC           1 :     printf(_("  -t, --table='TABLE[(COLUMNS)]'  vacuum specific table(s) only\n"));
 7235 peter_e                  1151 GIC           1 :     printf(_("  -v, --verbose                   write a lot of output\n"));
 3947                          1152               1 :     printf(_("  -V, --version                   output version information, then exit\n"));
 4790 bruce                    1153 CBC           1 :     printf(_("  -z, --analyze                   update optimizer statistics\n"));
 2762 peter_e                  1154               1 :     printf(_("  -Z, --analyze-only              only update optimizer statistics; no vacuum\n"));
 3282                          1155               1 :     printf(_("      --analyze-in-stages         only update optimizer statistics, in multiple\n"
                               1156                 :              "                                  stages for faster results; no vacuum\n"));
 3947                          1157               1 :     printf(_("  -?, --help                      show this help, then exit\n"));
 7235 peter_e                  1158 GIC           1 :     printf(_("\nConnection options:\n"));
                               1159               1 :     printf(_("  -h, --host=HOSTNAME       database server host or socket directory\n"));
 7235 peter_e                  1160 CBC           1 :     printf(_("  -p, --port=PORT           database server port\n"));
                               1161               1 :     printf(_("  -U, --username=USERNAME   user name to connect as\n"));
 5155                          1162               1 :     printf(_("  -w, --no-password         never prompt for password\n"));
 5598 tgl                      1163               1 :     printf(_("  -W, --password            force password prompt\n"));
 4142 rhaas                    1164 GIC           1 :     printf(_("  --maintenance-db=DBNAME   alternate maintenance database\n"));
 7235 peter_e                  1165 CBC           1 :     printf(_("\nRead the description of the SQL command VACUUM for details.\n"));
 1136 peter                    1166 GIC           1 :     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
                               1167               1 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
 7235 peter_e                  1168 GBC           1 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a