Header And Logo

PostgreSQL
| The world's most advanced open source database.

vacuumdb.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * vacuumdb
00004  *
00005  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00006  * Portions Copyright (c) 1994, Regents of the University of California
00007  *
00008  * src/bin/scripts/vacuumdb.c
00009  *
00010  *-------------------------------------------------------------------------
00011  */
00012 
00013 #include "postgres_fe.h"
00014 #include "common.h"
00015 #include "dumputils.h"
00016 
00017 
00018 static void vacuum_one_database(const char *dbname, bool full, bool verbose,
00019                     bool and_analyze, bool analyze_only, bool freeze,
00020                     const char *table, const char *host, const char *port,
00021                     const char *username, enum trivalue prompt_password,
00022                     const char *progname, bool echo);
00023 static void vacuum_all_databases(bool full, bool verbose, bool and_analyze,
00024                      bool analyze_only, bool freeze,
00025                      const char *maintenance_db,
00026                      const char *host, const char *port,
00027                      const char *username, enum trivalue prompt_password,
00028                      const char *progname, bool echo, bool quiet);
00029 
00030 static void help(const char *progname);
00031 
00032 
00033 int
00034 main(int argc, char *argv[])
00035 {
00036     static struct option long_options[] = {
00037         {"host", required_argument, NULL, 'h'},
00038         {"port", required_argument, NULL, 'p'},
00039         {"username", required_argument, NULL, 'U'},
00040         {"no-password", no_argument, NULL, 'w'},
00041         {"password", no_argument, NULL, 'W'},
00042         {"echo", no_argument, NULL, 'e'},
00043         {"quiet", no_argument, NULL, 'q'},
00044         {"dbname", required_argument, NULL, 'd'},
00045         {"analyze", no_argument, NULL, 'z'},
00046         {"analyze-only", no_argument, NULL, 'Z'},
00047         {"freeze", no_argument, NULL, 'F'},
00048         {"all", no_argument, NULL, 'a'},
00049         {"table", required_argument, NULL, 't'},
00050         {"full", no_argument, NULL, 'f'},
00051         {"verbose", no_argument, NULL, 'v'},
00052         {"maintenance-db", required_argument, NULL, 2},
00053         {NULL, 0, NULL, 0}
00054     };
00055 
00056     const char *progname;
00057     int         optindex;
00058     int         c;
00059 
00060     const char *dbname = NULL;
00061     const char *maintenance_db = NULL;
00062     char       *host = NULL;
00063     char       *port = NULL;
00064     char       *username = NULL;
00065     enum trivalue prompt_password = TRI_DEFAULT;
00066     bool        echo = false;
00067     bool        quiet = false;
00068     bool        and_analyze = false;
00069     bool        analyze_only = false;
00070     bool        freeze = false;
00071     bool        alldb = false;
00072     bool        full = false;
00073     bool        verbose = false;
00074     SimpleStringList tables = {NULL, NULL};
00075 
00076     progname = get_progname(argv[0]);
00077     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
00078 
00079     handle_help_version_opts(argc, argv, "vacuumdb", help);
00080 
00081     while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:zZFat:fv", long_options, &optindex)) != -1)
00082     {
00083         switch (c)
00084         {
00085             case 'h':
00086                 host = pg_strdup(optarg);
00087                 break;
00088             case 'p':
00089                 port = pg_strdup(optarg);
00090                 break;
00091             case 'U':
00092                 username = pg_strdup(optarg);
00093                 break;
00094             case 'w':
00095                 prompt_password = TRI_NO;
00096                 break;
00097             case 'W':
00098                 prompt_password = TRI_YES;
00099                 break;
00100             case 'e':
00101                 echo = true;
00102                 break;
00103             case 'q':
00104                 quiet = true;
00105                 break;
00106             case 'd':
00107                 dbname = pg_strdup(optarg);
00108                 break;
00109             case 'z':
00110                 and_analyze = true;
00111                 break;
00112             case 'Z':
00113                 analyze_only = true;
00114                 break;
00115             case 'F':
00116                 freeze = true;
00117                 break;
00118             case 'a':
00119                 alldb = true;
00120                 break;
00121             case 't':
00122                 simple_string_list_append(&tables, optarg);
00123                 break;
00124             case 'f':
00125                 full = true;
00126                 break;
00127             case 'v':
00128                 verbose = true;
00129                 break;
00130             case 2:
00131                 maintenance_db = pg_strdup(optarg);
00132                 break;
00133             default:
00134                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
00135                 exit(1);
00136         }
00137     }
00138 
00139 
00140     /*
00141      * Non-option argument specifies database name as long as it wasn't
00142      * already specified with -d / --dbname
00143      */
00144     if (optind < argc && dbname == NULL)
00145     {
00146         dbname = argv[optind];
00147         optind++;
00148     }
00149 
00150     if (optind < argc)
00151     {
00152         fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
00153                 progname, argv[optind]);
00154         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
00155         exit(1);
00156     }
00157 
00158     if (analyze_only)
00159     {
00160         if (full)
00161         {
00162             fprintf(stderr, _("%s: cannot use the \"full\" option when performing only analyze\n"),
00163                     progname);
00164             exit(1);
00165         }
00166         if (freeze)
00167         {
00168             fprintf(stderr, _("%s: cannot use the \"freeze\" option when performing only analyze\n"),
00169                     progname);
00170             exit(1);
00171         }
00172         /* allow 'and_analyze' with 'analyze_only' */
00173     }
00174 
00175     setup_cancel_handler();
00176 
00177     if (alldb)
00178     {
00179         if (dbname)
00180         {
00181             fprintf(stderr, _("%s: cannot vacuum all databases and a specific one at the same time\n"),
00182                     progname);
00183             exit(1);
00184         }
00185         if (tables.head != NULL)
00186         {
00187             fprintf(stderr, _("%s: cannot vacuum specific table(s) in all databases\n"),
00188                     progname);
00189             exit(1);
00190         }
00191 
00192         vacuum_all_databases(full, verbose, and_analyze, analyze_only, freeze,
00193                              maintenance_db, host, port, username,
00194                              prompt_password, progname, echo, quiet);
00195     }
00196     else
00197     {
00198         if (dbname == NULL)
00199         {
00200             if (getenv("PGDATABASE"))
00201                 dbname = getenv("PGDATABASE");
00202             else if (getenv("PGUSER"))
00203                 dbname = getenv("PGUSER");
00204             else
00205                 dbname = get_user_name(progname);
00206         }
00207 
00208         if (tables.head != NULL)
00209         {
00210             SimpleStringListCell *cell;
00211 
00212             for (cell = tables.head; cell; cell = cell->next)
00213             {
00214                 vacuum_one_database(dbname, full, verbose, and_analyze,
00215                                     analyze_only,
00216                                     freeze, cell->val,
00217                                     host, port, username, prompt_password,
00218                                     progname, echo);
00219             }
00220         }
00221         else
00222             vacuum_one_database(dbname, full, verbose, and_analyze,
00223                                 analyze_only,
00224                                 freeze, NULL,
00225                                 host, port, username, prompt_password,
00226                                 progname, echo);
00227     }
00228 
00229     exit(0);
00230 }
00231 
00232 
00233 static void
00234 vacuum_one_database(const char *dbname, bool full, bool verbose, bool and_analyze,
00235                     bool analyze_only, bool freeze, const char *table,
00236                     const char *host, const char *port,
00237                     const char *username, enum trivalue prompt_password,
00238                     const char *progname, bool echo)
00239 {
00240     PQExpBufferData sql;
00241 
00242     PGconn     *conn;
00243 
00244     initPQExpBuffer(&sql);
00245 
00246     conn = connectDatabase(dbname, host, port, username, prompt_password,
00247                            progname, false);
00248 
00249     if (analyze_only)
00250     {
00251         appendPQExpBuffer(&sql, "ANALYZE");
00252         if (verbose)
00253             appendPQExpBuffer(&sql, " VERBOSE");
00254     }
00255     else
00256     {
00257         appendPQExpBuffer(&sql, "VACUUM");
00258         if (PQserverVersion(conn) >= 90000)
00259         {
00260             const char *paren = " (";
00261             const char *comma = ", ";
00262             const char *sep = paren;
00263 
00264             if (full)
00265             {
00266                 appendPQExpBuffer(&sql, "%sFULL", sep);
00267                 sep = comma;
00268             }
00269             if (freeze)
00270             {
00271                 appendPQExpBuffer(&sql, "%sFREEZE", sep);
00272                 sep = comma;
00273             }
00274             if (verbose)
00275             {
00276                 appendPQExpBuffer(&sql, "%sVERBOSE", sep);
00277                 sep = comma;
00278             }
00279             if (and_analyze)
00280             {
00281                 appendPQExpBuffer(&sql, "%sANALYZE", sep);
00282                 sep = comma;
00283             }
00284             if (sep != paren)
00285                 appendPQExpBuffer(&sql, ")");
00286         }
00287         else
00288         {
00289             if (full)
00290                 appendPQExpBuffer(&sql, " FULL");
00291             if (freeze)
00292                 appendPQExpBuffer(&sql, " FREEZE");
00293             if (verbose)
00294                 appendPQExpBuffer(&sql, " VERBOSE");
00295             if (and_analyze)
00296                 appendPQExpBuffer(&sql, " ANALYZE");
00297         }
00298     }
00299     if (table)
00300         appendPQExpBuffer(&sql, " %s", table);
00301     appendPQExpBuffer(&sql, ";\n");
00302 
00303     if (!executeMaintenanceCommand(conn, sql.data, echo))
00304     {
00305         if (table)
00306             fprintf(stderr, _("%s: vacuuming of table \"%s\" in database \"%s\" failed: %s"),
00307                     progname, table, dbname, PQerrorMessage(conn));
00308         else
00309             fprintf(stderr, _("%s: vacuuming of database \"%s\" failed: %s"),
00310                     progname, dbname, PQerrorMessage(conn));
00311         PQfinish(conn);
00312         exit(1);
00313     }
00314     PQfinish(conn);
00315     termPQExpBuffer(&sql);
00316 }
00317 
00318 
00319 static void
00320 vacuum_all_databases(bool full, bool verbose, bool and_analyze, bool analyze_only,
00321                      bool freeze, const char *maintenance_db,
00322                      const char *host, const char *port,
00323                      const char *username, enum trivalue prompt_password,
00324                      const char *progname, bool echo, bool quiet)
00325 {
00326     PGconn     *conn;
00327     PGresult   *result;
00328     int         i;
00329 
00330     conn = connectMaintenanceDatabase(maintenance_db, host, port,
00331                                       username, prompt_password, progname);
00332     result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo);
00333     PQfinish(conn);
00334 
00335     for (i = 0; i < PQntuples(result); i++)
00336     {
00337         char       *dbname = PQgetvalue(result, i, 0);
00338 
00339         if (!quiet)
00340         {
00341             printf(_("%s: vacuuming database \"%s\"\n"), progname, dbname);
00342             fflush(stdout);
00343         }
00344 
00345         vacuum_one_database(dbname, full, verbose, and_analyze, analyze_only,
00346                          freeze, NULL, host, port, username, prompt_password,
00347                             progname, echo);
00348     }
00349 
00350     PQclear(result);
00351 }
00352 
00353 
00354 static void
00355 help(const char *progname)
00356 {
00357     printf(_("%s cleans and analyzes a PostgreSQL database.\n\n"), progname);
00358     printf(_("Usage:\n"));
00359     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
00360     printf(_("\nOptions:\n"));
00361     printf(_("  -a, --all                       vacuum all databases\n"));
00362     printf(_("  -d, --dbname=DBNAME             database to vacuum\n"));
00363     printf(_("  -e, --echo                      show the commands being sent to the server\n"));
00364     printf(_("  -f, --full                      do full vacuuming\n"));
00365     printf(_("  -F, --freeze                    freeze row transaction information\n"));
00366     printf(_("  -q, --quiet                     don't write any messages\n"));
00367     printf(_("  -t, --table='TABLE[(COLUMNS)]'  vacuum specific table(s) only\n"));
00368     printf(_("  -v, --verbose                   write a lot of output\n"));
00369     printf(_("  -V, --version                   output version information, then exit\n"));
00370     printf(_("  -z, --analyze                   update optimizer statistics\n"));
00371     printf(_("  -Z, --analyze-only              only update optimizer statistics\n"));
00372     printf(_("  -?, --help                      show this help, then exit\n"));
00373     printf(_("\nConnection options:\n"));
00374     printf(_("  -h, --host=HOSTNAME       database server host or socket directory\n"));
00375     printf(_("  -p, --port=PORT           database server port\n"));
00376     printf(_("  -U, --username=USERNAME   user name to connect as\n"));
00377     printf(_("  -w, --no-password         never prompt for password\n"));
00378     printf(_("  -W, --password            force password prompt\n"));
00379     printf(_("  --maintenance-db=DBNAME   alternate maintenance database\n"));
00380     printf(_("\nRead the description of the SQL command VACUUM for details.\n"));
00381     printf(_("\nReport bugs to <[email protected]>.\n"));
00382 }