LCOV - code coverage report
Current view: top level - src/bin/scripts - reindexdb.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta1 Lines: 155 213 72.8 %
Date: 2019-06-16 14:06:46 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * reindexdb
       4             :  *
       5             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       6             :  *
       7             :  * src/bin/scripts/reindexdb.c
       8             :  *
       9             :  *-------------------------------------------------------------------------
      10             :  */
      11             : 
      12             : #include "postgres_fe.h"
      13             : #include "common.h"
      14             : #include "common/logging.h"
      15             : #include "fe_utils/simple_list.h"
      16             : #include "fe_utils/string_utils.h"
      17             : 
      18             : 
      19             : static void reindex_one_database(const char *name, const char *dbname,
      20             :                                  const char *type, const char *host,
      21             :                                  const char *port, const char *username,
      22             :                                  enum trivalue prompt_password, const char *progname,
      23             :                                  bool echo, bool verbose, bool concurrently);
      24             : static void reindex_all_databases(const char *maintenance_db,
      25             :                                   const char *host, const char *port,
      26             :                                   const char *username, enum trivalue prompt_password,
      27             :                                   const char *progname, bool echo,
      28             :                                   bool quiet, bool verbose, bool concurrently);
      29             : static void reindex_system_catalogs(const char *dbname,
      30             :                                     const char *host, const char *port,
      31             :                                     const char *username, enum trivalue prompt_password,
      32             :                                     const char *progname, bool echo, bool verbose,
      33             :                                     bool concurrently);
      34             : static void help(const char *progname);
      35             : 
      36             : int
      37          40 : main(int argc, char *argv[])
      38             : {
      39             :     static struct option long_options[] = {
      40             :         {"host", required_argument, NULL, 'h'},
      41             :         {"port", required_argument, NULL, 'p'},
      42             :         {"username", required_argument, NULL, 'U'},
      43             :         {"no-password", no_argument, NULL, 'w'},
      44             :         {"password", no_argument, NULL, 'W'},
      45             :         {"echo", no_argument, NULL, 'e'},
      46             :         {"quiet", no_argument, NULL, 'q'},
      47             :         {"schema", required_argument, NULL, 'S'},
      48             :         {"dbname", required_argument, NULL, 'd'},
      49             :         {"all", no_argument, NULL, 'a'},
      50             :         {"system", no_argument, NULL, 's'},
      51             :         {"table", required_argument, NULL, 't'},
      52             :         {"index", required_argument, NULL, 'i'},
      53             :         {"verbose", no_argument, NULL, 'v'},
      54             :         {"concurrently", no_argument, NULL, 1},
      55             :         {"maintenance-db", required_argument, NULL, 2},
      56             :         {NULL, 0, NULL, 0}
      57             :     };
      58             : 
      59             :     const char *progname;
      60             :     int         optindex;
      61             :     int         c;
      62             : 
      63          40 :     const char *dbname = NULL;
      64          40 :     const char *maintenance_db = NULL;
      65          40 :     const char *host = NULL;
      66          40 :     const char *port = NULL;
      67          40 :     const char *username = NULL;
      68          40 :     enum trivalue prompt_password = TRI_DEFAULT;
      69          40 :     bool        syscatalog = false;
      70          40 :     bool        alldb = false;
      71          40 :     bool        echo = false;
      72          40 :     bool        quiet = false;
      73          40 :     bool        verbose = false;
      74          40 :     bool        concurrently = false;
      75          40 :     SimpleStringList indexes = {NULL, NULL};
      76          40 :     SimpleStringList tables = {NULL, NULL};
      77          40 :     SimpleStringList schemas = {NULL, NULL};
      78             : 
      79          40 :     pg_logging_init(argv[0]);
      80          40 :     progname = get_progname(argv[0]);
      81          40 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
      82             : 
      83          40 :     handle_help_version_opts(argc, argv, "reindexdb", help);
      84             : 
      85             :     /* process command-line options */
      86          36 :     while ((c = getopt_long(argc, argv, "h:p:U:wWeqS:d:ast:i:v", long_options, &optindex)) != -1)
      87             :     {
      88          52 :         switch (c)
      89             :         {
      90             :             case 'h':
      91           0 :                 host = pg_strdup(optarg);
      92           0 :                 break;
      93             :             case 'p':
      94           0 :                 port = pg_strdup(optarg);
      95           0 :                 break;
      96             :             case 'U':
      97           0 :                 username = pg_strdup(optarg);
      98           0 :                 break;
      99             :             case 'w':
     100           0 :                 prompt_password = TRI_NO;
     101           0 :                 break;
     102             :             case 'W':
     103           0 :                 prompt_password = TRI_YES;
     104           0 :                 break;
     105             :             case 'e':
     106           8 :                 echo = true;
     107           8 :                 break;
     108             :             case 'q':
     109           0 :                 quiet = true;
     110           0 :                 break;
     111             :             case 'S':
     112           4 :                 simple_string_list_append(&schemas, optarg);
     113           4 :                 break;
     114             :             case 'd':
     115           0 :                 dbname = pg_strdup(optarg);
     116           0 :                 break;
     117             :             case 'a':
     118           4 :                 alldb = true;
     119           4 :                 break;
     120             :             case 's':
     121           6 :                 syscatalog = true;
     122           6 :                 break;
     123             :             case 't':
     124          10 :                 simple_string_list_append(&tables, optarg);
     125          10 :                 break;
     126             :             case 'i':
     127           4 :                 simple_string_list_append(&indexes, optarg);
     128           4 :                 break;
     129             :             case 'v':
     130           4 :                 verbose = true;
     131           4 :                 break;
     132             :             case 1:
     133          10 :                 concurrently = true;
     134          10 :                 break;
     135             :             case 2:
     136           0 :                 maintenance_db = pg_strdup(optarg);
     137           0 :                 break;
     138             :             default:
     139           2 :                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     140           2 :                 exit(1);
     141             :         }
     142             :     }
     143             : 
     144             :     /*
     145             :      * Non-option argument specifies database name as long as it wasn't
     146             :      * already specified with -d / --dbname
     147             :      */
     148          34 :     if (optind < argc && dbname == NULL)
     149             :     {
     150          30 :         dbname = argv[optind];
     151          30 :         optind++;
     152             :     }
     153             : 
     154          34 :     if (optind < argc)
     155             :     {
     156           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     157             :                      argv[optind]);
     158           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     159           0 :         exit(1);
     160             :     }
     161             : 
     162          34 :     setup_cancel_handler();
     163             : 
     164          34 :     if (alldb)
     165             :     {
     166           4 :         if (dbname)
     167             :         {
     168           0 :             pg_log_error("cannot reindex all databases and a specific one at the same time");
     169           0 :             exit(1);
     170             :         }
     171           4 :         if (syscatalog)
     172             :         {
     173           0 :             pg_log_error("cannot reindex all databases and system catalogs at the same time");
     174           0 :             exit(1);
     175             :         }
     176           4 :         if (schemas.head != NULL)
     177             :         {
     178           0 :             pg_log_error("cannot reindex specific schema(s) in all databases");
     179           0 :             exit(1);
     180             :         }
     181           4 :         if (tables.head != NULL)
     182             :         {
     183           0 :             pg_log_error("cannot reindex specific table(s) in all databases");
     184           0 :             exit(1);
     185             :         }
     186           4 :         if (indexes.head != NULL)
     187             :         {
     188           0 :             pg_log_error("cannot reindex specific index(es) in all databases");
     189           0 :             exit(1);
     190             :         }
     191             : 
     192           4 :         reindex_all_databases(maintenance_db, host, port, username,
     193             :                               prompt_password, progname, echo, quiet, verbose, concurrently);
     194             :     }
     195          30 :     else if (syscatalog)
     196             :     {
     197           6 :         if (schemas.head != NULL)
     198             :         {
     199           0 :             pg_log_error("cannot reindex specific schema(s) and system catalogs at the same time");
     200           0 :             exit(1);
     201             :         }
     202           6 :         if (tables.head != NULL)
     203             :         {
     204           0 :             pg_log_error("cannot reindex specific table(s) and system catalogs at the same time");
     205           0 :             exit(1);
     206             :         }
     207           6 :         if (indexes.head != NULL)
     208             :         {
     209           0 :             pg_log_error("cannot reindex specific index(es) and system catalogs at the same time");
     210           0 :             exit(1);
     211             :         }
     212             : 
     213           6 :         if (dbname == NULL)
     214             :         {
     215           0 :             if (getenv("PGDATABASE"))
     216           0 :                 dbname = getenv("PGDATABASE");
     217           0 :             else if (getenv("PGUSER"))
     218           0 :                 dbname = getenv("PGUSER");
     219             :             else
     220           0 :                 dbname = get_user_name_or_exit(progname);
     221             :         }
     222             : 
     223           6 :         reindex_system_catalogs(dbname, host, port, username, prompt_password,
     224             :                                 progname, echo, verbose, concurrently);
     225             :     }
     226             :     else
     227             :     {
     228          24 :         if (dbname == NULL)
     229             :         {
     230           0 :             if (getenv("PGDATABASE"))
     231           0 :                 dbname = getenv("PGDATABASE");
     232           0 :             else if (getenv("PGUSER"))
     233           0 :                 dbname = getenv("PGUSER");
     234             :             else
     235           0 :                 dbname = get_user_name_or_exit(progname);
     236             :         }
     237             : 
     238          24 :         if (schemas.head != NULL)
     239             :         {
     240             :             SimpleStringListCell *cell;
     241             : 
     242           8 :             for (cell = schemas.head; cell; cell = cell->next)
     243             :             {
     244           4 :                 reindex_one_database(cell->val, dbname, "SCHEMA", host, port,
     245             :                                      username, prompt_password, progname, echo, verbose, concurrently);
     246             :             }
     247             :         }
     248             : 
     249          24 :         if (indexes.head != NULL)
     250             :         {
     251             :             SimpleStringListCell *cell;
     252             : 
     253           8 :             for (cell = indexes.head; cell; cell = cell->next)
     254             :             {
     255           4 :                 reindex_one_database(cell->val, dbname, "INDEX", host, port,
     256             :                                      username, prompt_password, progname, echo, verbose, concurrently);
     257             :             }
     258             :         }
     259          24 :         if (tables.head != NULL)
     260             :         {
     261             :             SimpleStringListCell *cell;
     262             : 
     263          20 :             for (cell = tables.head; cell; cell = cell->next)
     264             :             {
     265          10 :                 reindex_one_database(cell->val, dbname, "TABLE", host, port,
     266             :                                      username, prompt_password, progname, echo, verbose, concurrently);
     267             :             }
     268             :         }
     269             : 
     270             :         /*
     271             :          * reindex database only if neither index nor table nor schema is
     272             :          * specified
     273             :          */
     274          24 :         if (indexes.head == NULL && tables.head == NULL && schemas.head == NULL)
     275           6 :             reindex_one_database(NULL, dbname, "DATABASE", host, port,
     276             :                                  username, prompt_password, progname, echo, verbose, concurrently);
     277             :     }
     278             : 
     279          32 :     exit(0);
     280             : }
     281             : 
     282             : static void
     283          42 : reindex_one_database(const char *name, const char *dbname, const char *type,
     284             :                      const char *host, const char *port, const char *username,
     285             :                      enum trivalue prompt_password, const char *progname, bool echo,
     286             :                      bool verbose, bool concurrently)
     287             : {
     288             :     PQExpBufferData sql;
     289             : 
     290             :     PGconn     *conn;
     291             : 
     292          42 :     conn = connectDatabase(dbname, host, port, username, prompt_password,
     293             :                            progname, echo, false, false);
     294             : 
     295          42 :     if (concurrently && PQserverVersion(conn) < 120000)
     296             :     {
     297           0 :         PQfinish(conn);
     298           0 :         pg_log_error("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
     299             :                      "concurrently", "12");
     300           0 :         exit(1);
     301             :     }
     302             : 
     303          42 :     initPQExpBuffer(&sql);
     304             : 
     305          42 :     appendPQExpBufferStr(&sql, "REINDEX ");
     306             : 
     307          42 :     if (verbose)
     308           4 :         appendPQExpBufferStr(&sql, "(VERBOSE) ");
     309             : 
     310          42 :     appendPQExpBufferStr(&sql, type);
     311          42 :     appendPQExpBufferChar(&sql, ' ');
     312          42 :     if (concurrently)
     313           8 :         appendPQExpBufferStr(&sql, "CONCURRENTLY ");
     314          74 :     if (strcmp(type, "TABLE") == 0 ||
     315          32 :         strcmp(type, "INDEX") == 0)
     316          14 :         appendQualifiedRelation(&sql, name, conn, progname, echo);
     317          28 :     else if (strcmp(type, "SCHEMA") == 0)
     318           4 :         appendPQExpBufferStr(&sql, name);
     319          24 :     else if (strcmp(type, "DATABASE") == 0)
     320          24 :         appendPQExpBufferStr(&sql, fmtId(PQdb(conn)));
     321          42 :     appendPQExpBufferChar(&sql, ';');
     322             : 
     323          42 :     if (!executeMaintenanceCommand(conn, sql.data, echo))
     324             :     {
     325           0 :         if (strcmp(type, "TABLE") == 0)
     326           0 :             pg_log_error("reindexing of table \"%s\" in database \"%s\" failed: %s",
     327             :                          name, PQdb(conn), PQerrorMessage(conn));
     328           0 :         else if (strcmp(type, "INDEX") == 0)
     329           0 :             pg_log_error("reindexing of index \"%s\" in database \"%s\" failed: %s",
     330             :                          name, PQdb(conn), PQerrorMessage(conn));
     331           0 :         else if (strcmp(type, "SCHEMA") == 0)
     332           0 :             pg_log_error("reindexing of schema \"%s\" in database \"%s\" failed: %s",
     333             :                          name, PQdb(conn), PQerrorMessage(conn));
     334             :         else
     335           0 :             pg_log_error("reindexing of database \"%s\" failed: %s",
     336             :                          PQdb(conn), PQerrorMessage(conn));
     337           0 :         PQfinish(conn);
     338           0 :         exit(1);
     339             :     }
     340             : 
     341          42 :     PQfinish(conn);
     342          42 :     termPQExpBuffer(&sql);
     343          42 : }
     344             : 
     345             : static void
     346           4 : reindex_all_databases(const char *maintenance_db,
     347             :                       const char *host, const char *port,
     348             :                       const char *username, enum trivalue prompt_password,
     349             :                       const char *progname, bool echo, bool quiet, bool verbose,
     350             :                       bool concurrently)
     351             : {
     352             :     PGconn     *conn;
     353             :     PGresult   *result;
     354             :     PQExpBufferData connstr;
     355             :     int         i;
     356             : 
     357           4 :     conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
     358             :                                       prompt_password, progname, echo);
     359           4 :     result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo);
     360           4 :     PQfinish(conn);
     361             : 
     362           4 :     initPQExpBuffer(&connstr);
     363          22 :     for (i = 0; i < PQntuples(result); i++)
     364             :     {
     365          18 :         char       *dbname = PQgetvalue(result, i, 0);
     366             : 
     367          18 :         if (!quiet)
     368             :         {
     369          18 :             printf(_("%s: reindexing database \"%s\"\n"), progname, dbname);
     370          18 :             fflush(stdout);
     371             :         }
     372             : 
     373          18 :         resetPQExpBuffer(&connstr);
     374          18 :         appendPQExpBuffer(&connstr, "dbname=");
     375          18 :         appendConnStrVal(&connstr, dbname);
     376             : 
     377          18 :         reindex_one_database(NULL, connstr.data, "DATABASE", host,
     378             :                              port, username, prompt_password,
     379             :                              progname, echo, verbose, concurrently);
     380             :     }
     381           4 :     termPQExpBuffer(&connstr);
     382             : 
     383           4 :     PQclear(result);
     384           4 : }
     385             : 
     386             : static void
     387           6 : reindex_system_catalogs(const char *dbname, const char *host, const char *port,
     388             :                         const char *username, enum trivalue prompt_password,
     389             :                         const char *progname, bool echo, bool verbose, bool concurrently)
     390             : {
     391             :     PGconn     *conn;
     392             :     PQExpBufferData sql;
     393             : 
     394           6 :     conn = connectDatabase(dbname, host, port, username, prompt_password,
     395             :                            progname, echo, false, false);
     396             : 
     397           6 :     initPQExpBuffer(&sql);
     398             : 
     399           6 :     appendPQExpBuffer(&sql, "REINDEX");
     400             : 
     401           6 :     if (verbose)
     402           0 :         appendPQExpBuffer(&sql, " (VERBOSE)");
     403             : 
     404           6 :     appendPQExpBufferStr(&sql, " SYSTEM ");
     405           6 :     if (concurrently)
     406           2 :         appendPQExpBuffer(&sql, "CONCURRENTLY ");
     407           6 :     appendPQExpBufferStr(&sql, fmtId(PQdb(conn)));
     408           6 :     appendPQExpBufferChar(&sql, ';');
     409             : 
     410           6 :     if (!executeMaintenanceCommand(conn, sql.data, echo))
     411             :     {
     412           2 :         pg_log_error("reindexing of system catalogs failed: %s",
     413             :                      PQerrorMessage(conn));
     414           2 :         PQfinish(conn);
     415           2 :         exit(1);
     416             :     }
     417           4 :     PQfinish(conn);
     418           4 :     termPQExpBuffer(&sql);
     419           4 : }
     420             : 
     421             : static void
     422           2 : help(const char *progname)
     423             : {
     424           2 :     printf(_("%s reindexes a PostgreSQL database.\n\n"), progname);
     425           2 :     printf(_("Usage:\n"));
     426           2 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
     427           2 :     printf(_("\nOptions:\n"));
     428           2 :     printf(_("  -a, --all                 reindex all databases\n"));
     429           2 :     printf(_("      --concurrently        reindex concurrently\n"));
     430           2 :     printf(_("  -d, --dbname=DBNAME       database to reindex\n"));
     431           2 :     printf(_("  -e, --echo                show the commands being sent to the server\n"));
     432           2 :     printf(_("  -i, --index=INDEX         recreate specific index(es) only\n"));
     433           2 :     printf(_("  -q, --quiet               don't write any messages\n"));
     434           2 :     printf(_("  -s, --system              reindex system catalogs\n"));
     435           2 :     printf(_("  -S, --schema=SCHEMA       reindex specific schema(s) only\n"));
     436           2 :     printf(_("  -t, --table=TABLE         reindex specific table(s) only\n"));
     437           2 :     printf(_("  -v, --verbose             write a lot of output\n"));
     438           2 :     printf(_("  -V, --version             output version information, then exit\n"));
     439           2 :     printf(_("  -?, --help                show this help, then exit\n"));
     440           2 :     printf(_("\nConnection options:\n"));
     441           2 :     printf(_("  -h, --host=HOSTNAME       database server host or socket directory\n"));
     442           2 :     printf(_("  -p, --port=PORT           database server port\n"));
     443           2 :     printf(_("  -U, --username=USERNAME   user name to connect as\n"));
     444           2 :     printf(_("  -w, --no-password         never prompt for password\n"));
     445           2 :     printf(_("  -W, --password            force password prompt\n"));
     446           2 :     printf(_("  --maintenance-db=DBNAME   alternate maintenance database\n"));
     447           2 :     printf(_("\nRead the description of the SQL command REINDEX for details.\n"));
     448           2 :     printf(_("\nReport bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
     449           2 : }

Generated by: LCOV version 1.13