LCOV - code coverage report
Current view: top level - src/bin/scripts - reindexdb.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 274 357 76.8 %
Date: 2020-06-01 09:07:10 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * reindexdb
       4             :  *
       5             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
       6             :  *
       7             :  * src/bin/scripts/reindexdb.c
       8             :  *
       9             :  *-------------------------------------------------------------------------
      10             :  */
      11             : 
      12             : #include "postgres_fe.h"
      13             : 
      14             : #include "catalog/pg_class_d.h"
      15             : #include "common.h"
      16             : #include "common/logging.h"
      17             : #include "fe_utils/cancel.h"
      18             : #include "fe_utils/connect.h"
      19             : #include "fe_utils/simple_list.h"
      20             : #include "fe_utils/string_utils.h"
      21             : #include "scripts_parallel.h"
      22             : 
      23             : typedef enum ReindexType
      24             : {
      25             :     REINDEX_DATABASE,
      26             :     REINDEX_INDEX,
      27             :     REINDEX_SCHEMA,
      28             :     REINDEX_SYSTEM,
      29             :     REINDEX_TABLE
      30             : } ReindexType;
      31             : 
      32             : 
      33             : static SimpleStringList *get_parallel_object_list(PGconn *conn,
      34             :                                                   ReindexType type,
      35             :                                                   SimpleStringList *user_list,
      36             :                                                   bool echo);
      37             : static void reindex_one_database(const char *dbname, ReindexType type,
      38             :                                  SimpleStringList *user_list, const char *host,
      39             :                                  const char *port, const char *username,
      40             :                                  enum trivalue prompt_password, const char *progname,
      41             :                                  bool echo, bool verbose, bool concurrently,
      42             :                                  int concurrentCons);
      43             : static void reindex_all_databases(const char *maintenance_db,
      44             :                                   const char *host, const char *port,
      45             :                                   const char *username, enum trivalue prompt_password,
      46             :                                   const char *progname, bool echo,
      47             :                                   bool quiet, bool verbose, bool concurrently,
      48             :                                   int concurrentCons);
      49             : static void run_reindex_command(PGconn *conn, ReindexType type,
      50             :                                 const char *name, bool echo, bool verbose,
      51             :                                 bool concurrently, bool async);
      52             : 
      53             : static void help(const char *progname);
      54             : 
      55             : int
      56          52 : main(int argc, char *argv[])
      57             : {
      58             :     static struct option long_options[] = {
      59             :         {"host", required_argument, NULL, 'h'},
      60             :         {"port", required_argument, NULL, 'p'},
      61             :         {"username", required_argument, NULL, 'U'},
      62             :         {"no-password", no_argument, NULL, 'w'},
      63             :         {"password", no_argument, NULL, 'W'},
      64             :         {"echo", no_argument, NULL, 'e'},
      65             :         {"quiet", no_argument, NULL, 'q'},
      66             :         {"schema", required_argument, NULL, 'S'},
      67             :         {"dbname", required_argument, NULL, 'd'},
      68             :         {"all", no_argument, NULL, 'a'},
      69             :         {"system", no_argument, NULL, 's'},
      70             :         {"table", required_argument, NULL, 't'},
      71             :         {"index", required_argument, NULL, 'i'},
      72             :         {"jobs", required_argument, NULL, 'j'},
      73             :         {"verbose", no_argument, NULL, 'v'},
      74             :         {"concurrently", no_argument, NULL, 1},
      75             :         {"maintenance-db", required_argument, NULL, 2},
      76             :         {NULL, 0, NULL, 0}
      77             :     };
      78             : 
      79             :     const char *progname;
      80             :     int         optindex;
      81             :     int         c;
      82             : 
      83          52 :     const char *dbname = NULL;
      84          52 :     const char *maintenance_db = NULL;
      85          52 :     const char *host = NULL;
      86          52 :     const char *port = NULL;
      87          52 :     const char *username = NULL;
      88          52 :     enum trivalue prompt_password = TRI_DEFAULT;
      89          52 :     bool        syscatalog = false;
      90          52 :     bool        alldb = false;
      91          52 :     bool        echo = false;
      92          52 :     bool        quiet = false;
      93          52 :     bool        verbose = false;
      94          52 :     bool        concurrently = false;
      95          52 :     SimpleStringList indexes = {NULL, NULL};
      96          52 :     SimpleStringList tables = {NULL, NULL};
      97          52 :     SimpleStringList schemas = {NULL, NULL};
      98          52 :     int         concurrentCons = 1;
      99             : 
     100          52 :     pg_logging_init(argv[0]);
     101          52 :     progname = get_progname(argv[0]);
     102          52 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
     103             : 
     104          52 :     handle_help_version_opts(argc, argv, "reindexdb", help);
     105             : 
     106             :     /* process command-line options */
     107         124 :     while ((c = getopt_long(argc, argv, "h:p:U:wWeqS:d:ast:i:j:v", long_options, &optindex)) != -1)
     108             :     {
     109          78 :         switch (c)
     110             :         {
     111           0 :             case 'h':
     112           0 :                 host = pg_strdup(optarg);
     113           0 :                 break;
     114           0 :             case 'p':
     115           0 :                 port = pg_strdup(optarg);
     116           0 :                 break;
     117           0 :             case 'U':
     118           0 :                 username = pg_strdup(optarg);
     119           0 :                 break;
     120           0 :             case 'w':
     121           0 :                 prompt_password = TRI_NO;
     122           0 :                 break;
     123           0 :             case 'W':
     124           0 :                 prompt_password = TRI_YES;
     125           0 :                 break;
     126           8 :             case 'e':
     127           8 :                 echo = true;
     128           8 :                 break;
     129           0 :             case 'q':
     130           0 :                 quiet = true;
     131           0 :                 break;
     132          10 :             case 'S':
     133          10 :                 simple_string_list_append(&schemas, optarg);
     134          10 :                 break;
     135           2 :             case 'd':
     136           2 :                 dbname = pg_strdup(optarg);
     137           2 :                 break;
     138           4 :             case 'a':
     139           4 :                 alldb = true;
     140           4 :                 break;
     141           8 :             case 's':
     142           8 :                 syscatalog = true;
     143           8 :                 break;
     144          10 :             case 't':
     145          10 :                 simple_string_list_append(&tables, optarg);
     146          10 :                 break;
     147           6 :             case 'i':
     148           6 :                 simple_string_list_append(&indexes, optarg);
     149           6 :                 break;
     150          12 :             case 'j':
     151          12 :                 concurrentCons = atoi(optarg);
     152          12 :                 if (concurrentCons <= 0)
     153             :                 {
     154           0 :                     pg_log_error("number of parallel jobs must be at least 1");
     155           0 :                     exit(1);
     156             :                 }
     157          12 :                 break;
     158           4 :             case 'v':
     159           4 :                 verbose = true;
     160           4 :                 break;
     161          12 :             case 1:
     162          12 :                 concurrently = true;
     163          12 :                 break;
     164           0 :             case 2:
     165           0 :                 maintenance_db = pg_strdup(optarg);
     166           0 :                 break;
     167           2 :             default:
     168           2 :                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     169           2 :                 exit(1);
     170             :         }
     171             :     }
     172             : 
     173             :     /*
     174             :      * Non-option argument specifies database name as long as it wasn't
     175             :      * already specified with -d / --dbname
     176             :      */
     177          46 :     if (optind < argc && dbname == NULL)
     178             :     {
     179          38 :         dbname = argv[optind];
     180          38 :         optind++;
     181             :     }
     182             : 
     183          46 :     if (optind < argc)
     184             :     {
     185           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     186             :                      argv[optind]);
     187           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     188           0 :         exit(1);
     189             :     }
     190             : 
     191          46 :     setup_cancel_handler(NULL);
     192             : 
     193          46 :     if (alldb)
     194             :     {
     195           4 :         if (dbname)
     196             :         {
     197           0 :             pg_log_error("cannot reindex all databases and a specific one at the same time");
     198           0 :             exit(1);
     199             :         }
     200           4 :         if (syscatalog)
     201             :         {
     202           0 :             pg_log_error("cannot reindex all databases and system catalogs at the same time");
     203           0 :             exit(1);
     204             :         }
     205           4 :         if (schemas.head != NULL)
     206             :         {
     207           0 :             pg_log_error("cannot reindex specific schema(s) in all databases");
     208           0 :             exit(1);
     209             :         }
     210           4 :         if (tables.head != NULL)
     211             :         {
     212           0 :             pg_log_error("cannot reindex specific table(s) in all databases");
     213           0 :             exit(1);
     214             :         }
     215           4 :         if (indexes.head != NULL)
     216             :         {
     217           0 :             pg_log_error("cannot reindex specific index(es) in all databases");
     218           0 :             exit(1);
     219             :         }
     220             : 
     221           4 :         reindex_all_databases(maintenance_db, host, port, username,
     222             :                               prompt_password, progname, echo, quiet, verbose,
     223             :                               concurrently, concurrentCons);
     224             :     }
     225          42 :     else if (syscatalog)
     226             :     {
     227           8 :         if (schemas.head != NULL)
     228             :         {
     229           0 :             pg_log_error("cannot reindex specific schema(s) and system catalogs at the same time");
     230           0 :             exit(1);
     231             :         }
     232           8 :         if (tables.head != NULL)
     233             :         {
     234           0 :             pg_log_error("cannot reindex specific table(s) and system catalogs at the same time");
     235           0 :             exit(1);
     236             :         }
     237           8 :         if (indexes.head != NULL)
     238             :         {
     239           0 :             pg_log_error("cannot reindex specific index(es) and system catalogs at the same time");
     240           0 :             exit(1);
     241             :         }
     242             : 
     243           8 :         if (concurrentCons > 1)
     244             :         {
     245           2 :             pg_log_error("cannot use multiple jobs to reindex system catalogs");
     246           2 :             exit(1);
     247             :         }
     248             : 
     249           6 :         if (dbname == NULL)
     250             :         {
     251           0 :             if (getenv("PGDATABASE"))
     252           0 :                 dbname = getenv("PGDATABASE");
     253           0 :             else if (getenv("PGUSER"))
     254           0 :                 dbname = getenv("PGUSER");
     255             :             else
     256           0 :                 dbname = get_user_name_or_exit(progname);
     257             :         }
     258             : 
     259           6 :         reindex_one_database(dbname, REINDEX_SYSTEM, NULL, host,
     260             :                              port, username, prompt_password, progname,
     261             :                              echo, verbose, concurrently, 1);
     262             :     }
     263             :     else
     264             :     {
     265             :         /*
     266             :          * Index-level REINDEX is not supported with multiple jobs as we
     267             :          * cannot control the concurrent processing of multiple indexes
     268             :          * depending on the same relation.
     269             :          */
     270          34 :         if (concurrentCons > 1 && indexes.head != NULL)
     271             :         {
     272           2 :             pg_log_error("cannot use multiple jobs to reindex indexes");
     273           2 :             exit(1);
     274             :         }
     275             : 
     276          32 :         if (dbname == NULL)
     277             :         {
     278           2 :             if (getenv("PGDATABASE"))
     279           2 :                 dbname = getenv("PGDATABASE");
     280           0 :             else if (getenv("PGUSER"))
     281           0 :                 dbname = getenv("PGUSER");
     282             :             else
     283           0 :                 dbname = get_user_name_or_exit(progname);
     284             :         }
     285             : 
     286          32 :         if (schemas.head != NULL)
     287           8 :             reindex_one_database(dbname, REINDEX_SCHEMA, &schemas, host,
     288             :                                  port, username, prompt_password, progname,
     289             :                                  echo, verbose, concurrently, concurrentCons);
     290             : 
     291          32 :         if (indexes.head != NULL)
     292           4 :             reindex_one_database(dbname, REINDEX_INDEX, &indexes, host,
     293             :                                  port, username, prompt_password, progname,
     294             :                                  echo, verbose, concurrently, 1);
     295             : 
     296          32 :         if (tables.head != NULL)
     297          10 :             reindex_one_database(dbname, REINDEX_TABLE, &tables, host,
     298             :                                  port, username, prompt_password, progname,
     299             :                                  echo, verbose, concurrently,
     300             :                                  concurrentCons);
     301             : 
     302             :         /*
     303             :          * reindex database only if neither index nor table nor schema is
     304             :          * specified
     305             :          */
     306          32 :         if (indexes.head == NULL && tables.head == NULL && schemas.head == NULL)
     307          10 :             reindex_one_database(dbname, REINDEX_DATABASE, NULL, host,
     308             :                                  port, username, prompt_password, progname,
     309             :                                  echo, verbose, concurrently, concurrentCons);
     310             :     }
     311             : 
     312          40 :     exit(0);
     313             : }
     314             : 
     315             : static void
     316          56 : reindex_one_database(const char *dbname, ReindexType type,
     317             :                      SimpleStringList *user_list, const char *host,
     318             :                      const char *port, const char *username,
     319             :                      enum trivalue prompt_password, const char *progname, bool echo,
     320             :                      bool verbose, bool concurrently, int concurrentCons)
     321             : {
     322             :     PGconn     *conn;
     323             :     SimpleStringListCell *cell;
     324          56 :     bool        parallel = concurrentCons > 1;
     325          56 :     SimpleStringList *process_list = user_list;
     326          56 :     ReindexType process_type = type;
     327             :     ParallelSlot *slots;
     328          56 :     bool        failed = false;
     329          56 :     int         items_count = 0;
     330             : 
     331          56 :     conn = connectDatabase(dbname, host, port, username, prompt_password,
     332             :                            progname, echo, false, false);
     333             : 
     334          56 :     if (concurrently && PQserverVersion(conn) < 120000)
     335             :     {
     336           0 :         PQfinish(conn);
     337           0 :         pg_log_error("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
     338             :                      "concurrently", "12");
     339           0 :         exit(1);
     340             :     }
     341             : 
     342          56 :     if (!parallel)
     343             :     {
     344          48 :         switch (process_type)
     345             :         {
     346          30 :             case REINDEX_DATABASE:
     347             :             case REINDEX_SYSTEM:
     348             : 
     349             :                 /*
     350             :                  * Database and system reindexes only need to work on the
     351             :                  * database itself, so build a list with a single entry.
     352             :                  */
     353             :                 Assert(user_list == NULL);
     354          30 :                 process_list = pg_malloc0(sizeof(SimpleStringList));
     355          30 :                 simple_string_list_append(process_list, PQdb(conn));
     356          30 :                 break;
     357             : 
     358          18 :             case REINDEX_INDEX:
     359             :             case REINDEX_SCHEMA:
     360             :             case REINDEX_TABLE:
     361             :                 Assert(user_list != NULL);
     362          18 :                 break;
     363             :         }
     364          48 :     }
     365             :     else
     366             :     {
     367           8 :         switch (process_type)
     368             :         {
     369           4 :             case REINDEX_DATABASE:
     370             : 
     371             :                 /*
     372             :                  * Database-wide parallel reindex requires special processing.
     373             :                  * If multiple jobs were asked, we have to reindex system
     374             :                  * catalogs first as they cannot be processed in parallel.
     375             :                  */
     376           4 :                 if (concurrently)
     377           2 :                     pg_log_warning("cannot reindex system catalogs concurrently, skipping all");
     378             :                 else
     379           2 :                     run_reindex_command(conn, REINDEX_SYSTEM, PQdb(conn), echo,
     380             :                                         verbose, concurrently, false);
     381             : 
     382             :                 /* Build a list of relations from the database */
     383           4 :                 process_list = get_parallel_object_list(conn, process_type,
     384             :                                                         user_list, echo);
     385           4 :                 process_type = REINDEX_TABLE;
     386             : 
     387             :                 /* Bail out if nothing to process */
     388           4 :                 if (process_list == NULL)
     389           0 :                     return;
     390           4 :                 break;
     391             : 
     392           4 :             case REINDEX_SCHEMA:
     393             :                 Assert(user_list != NULL);
     394             : 
     395             :                 /* Build a list of relations from all the schemas */
     396           4 :                 process_list = get_parallel_object_list(conn, process_type,
     397             :                                                         user_list, echo);
     398           4 :                 process_type = REINDEX_TABLE;
     399             : 
     400             :                 /* Bail out if nothing to process */
     401           4 :                 if (process_list == NULL)
     402           2 :                     return;
     403           2 :                 break;
     404             : 
     405           0 :             case REINDEX_SYSTEM:
     406             :             case REINDEX_INDEX:
     407             :                 /* not supported */
     408             :                 Assert(false);
     409           0 :                 break;
     410             : 
     411           0 :             case REINDEX_TABLE:
     412             : 
     413             :                 /*
     414             :                  * Fall through.  The list of items for tables is already
     415             :                  * created.
     416             :                  */
     417           0 :                 break;
     418             :         }
     419          54 :     }
     420             : 
     421             :     /*
     422             :      * Adjust the number of concurrent connections depending on the items in
     423             :      * the list.  We choose the minimum between the number of concurrent
     424             :      * connections and the number of items in the list.
     425             :      */
     426          60 :     for (cell = process_list->head; cell; cell = cell->next)
     427             :     {
     428          60 :         items_count++;
     429             : 
     430             :         /* no need to continue if there are more elements than jobs */
     431          60 :         if (items_count >= concurrentCons)
     432          54 :             break;
     433             :     }
     434          54 :     concurrentCons = Min(concurrentCons, items_count);
     435             :     Assert(concurrentCons > 0);
     436             : 
     437             :     Assert(process_list != NULL);
     438             : 
     439          54 :     slots = ParallelSlotsSetup(dbname, host, port, username, prompt_password,
     440             :                                progname, echo, conn, concurrentCons);
     441             : 
     442          54 :     cell = process_list->head;
     443             :     do
     444             :     {
     445          80 :         const char *objname = cell->val;
     446          80 :         ParallelSlot *free_slot = NULL;
     447             : 
     448          80 :         if (CancelRequested)
     449             :         {
     450           0 :             failed = true;
     451           0 :             goto finish;
     452             :         }
     453             : 
     454          80 :         free_slot = ParallelSlotsGetIdle(slots, concurrentCons);
     455          80 :         if (!free_slot)
     456             :         {
     457           0 :             failed = true;
     458           0 :             goto finish;
     459             :         }
     460             : 
     461          80 :         run_reindex_command(free_slot->connection, process_type, objname,
     462             :                             echo, verbose, concurrently, true);
     463             : 
     464          80 :         cell = cell->next;
     465          80 :     } while (cell != NULL);
     466             : 
     467          54 :     if (!ParallelSlotsWaitCompletion(slots, concurrentCons))
     468           2 :         failed = true;
     469             : 
     470          52 : finish:
     471          54 :     if (process_list != user_list)
     472             :     {
     473          36 :         simple_string_list_destroy(process_list);
     474          36 :         pg_free(process_list);
     475             :     }
     476             : 
     477          54 :     ParallelSlotsTerminate(slots, concurrentCons);
     478          54 :     pfree(slots);
     479             : 
     480          54 :     if (failed)
     481           2 :         exit(1);
     482             : }
     483             : 
     484             : static void
     485          82 : run_reindex_command(PGconn *conn, ReindexType type, const char *name,
     486             :                     bool echo, bool verbose, bool concurrently, bool async)
     487             : {
     488             :     PQExpBufferData sql;
     489             :     bool        status;
     490             : 
     491             :     Assert(name);
     492             : 
     493             :     /* build the REINDEX query */
     494          82 :     initPQExpBuffer(&sql);
     495             : 
     496          82 :     appendPQExpBufferStr(&sql, "REINDEX ");
     497             : 
     498          82 :     if (verbose)
     499           4 :         appendPQExpBufferStr(&sql, "(VERBOSE) ");
     500             : 
     501             :     /* object type */
     502          82 :     switch (type)
     503             :     {
     504          24 :         case REINDEX_DATABASE:
     505          24 :             appendPQExpBufferStr(&sql, "DATABASE ");
     506          24 :             break;
     507           4 :         case REINDEX_INDEX:
     508           4 :             appendPQExpBufferStr(&sql, "INDEX ");
     509           4 :             break;
     510           4 :         case REINDEX_SCHEMA:
     511           4 :             appendPQExpBufferStr(&sql, "SCHEMA ");
     512           4 :             break;
     513           8 :         case REINDEX_SYSTEM:
     514           8 :             appendPQExpBufferStr(&sql, "SYSTEM ");
     515           8 :             break;
     516          42 :         case REINDEX_TABLE:
     517          42 :             appendPQExpBufferStr(&sql, "TABLE ");
     518          42 :             break;
     519             :     }
     520             : 
     521          82 :     if (concurrently)
     522          24 :         appendPQExpBufferStr(&sql, "CONCURRENTLY ");
     523             : 
     524             :     /* object name */
     525          82 :     switch (type)
     526             :     {
     527          32 :         case REINDEX_DATABASE:
     528             :         case REINDEX_SYSTEM:
     529          32 :             appendPQExpBufferStr(&sql, fmtId(name));
     530          32 :             break;
     531          46 :         case REINDEX_INDEX:
     532             :         case REINDEX_TABLE:
     533          46 :             appendQualifiedRelation(&sql, name, conn, echo);
     534          46 :             break;
     535           4 :         case REINDEX_SCHEMA:
     536           4 :             appendPQExpBufferStr(&sql, name);
     537           4 :             break;
     538             :     }
     539             : 
     540             :     /* finish the query */
     541          82 :     appendPQExpBufferChar(&sql, ';');
     542             : 
     543          82 :     if (async)
     544             :     {
     545          80 :         if (echo)
     546          20 :             printf("%s\n", sql.data);
     547             : 
     548          80 :         status = PQsendQuery(conn, sql.data) == 1;
     549             :     }
     550             :     else
     551           2 :         status = executeMaintenanceCommand(conn, sql.data, echo);
     552             : 
     553          82 :     if (!status)
     554             :     {
     555           0 :         switch (type)
     556             :         {
     557           0 :             case REINDEX_DATABASE:
     558           0 :                 pg_log_error("reindexing of database \"%s\" failed: %s",
     559             :                              PQdb(conn), PQerrorMessage(conn));
     560           0 :                 break;
     561           0 :             case REINDEX_INDEX:
     562           0 :                 pg_log_error("reindexing of index \"%s\" in database \"%s\" failed: %s",
     563             :                              name, PQdb(conn), PQerrorMessage(conn));
     564           0 :                 break;
     565           0 :             case REINDEX_SCHEMA:
     566           0 :                 pg_log_error("reindexing of schema \"%s\" in database \"%s\" failed: %s",
     567             :                              name, PQdb(conn), PQerrorMessage(conn));
     568           0 :                 break;
     569           0 :             case REINDEX_SYSTEM:
     570           0 :                 pg_log_error("reindexing of system catalogs in database \"%s\" failed: %s",
     571             :                              PQdb(conn), PQerrorMessage(conn));
     572           0 :                 break;
     573           0 :             case REINDEX_TABLE:
     574           0 :                 pg_log_error("reindexing of table \"%s\" in database \"%s\" failed: %s",
     575             :                              name, PQdb(conn), PQerrorMessage(conn));
     576           0 :                 break;
     577             :         }
     578           0 :         if (!async)
     579             :         {
     580           0 :             PQfinish(conn);
     581           0 :             exit(1);
     582             :         }
     583             :     }
     584             : 
     585          82 :     termPQExpBuffer(&sql);
     586          82 : }
     587             : 
     588             : /*
     589             :  * Prepare the list of objects to process by querying the catalogs.
     590             :  *
     591             :  * This function will return a SimpleStringList object containing the entire
     592             :  * list of tables in the given database that should be processed by a parallel
     593             :  * database-wide reindex (excluding system tables), or NULL if there's no such
     594             :  * table.
     595             :  */
     596             : static SimpleStringList *
     597           8 : get_parallel_object_list(PGconn *conn, ReindexType type,
     598             :                          SimpleStringList *user_list, bool echo)
     599             : {
     600             :     PQExpBufferData catalog_query;
     601             :     PQExpBufferData buf;
     602             :     PGresult   *res;
     603             :     SimpleStringList *tables;
     604             :     int         ntups,
     605             :                 i;
     606             : 
     607           8 :     initPQExpBuffer(&catalog_query);
     608             : 
     609             :     /*
     610             :      * The queries here are using a safe search_path, so there's no need to
     611             :      * fully qualify everything.
     612             :      */
     613           8 :     switch (type)
     614             :     {
     615           4 :         case REINDEX_DATABASE:
     616             :             Assert(user_list == NULL);
     617           4 :             appendPQExpBuffer(&catalog_query,
     618             :                               "SELECT c.relname, ns.nspname\n"
     619             :                               " FROM pg_catalog.pg_class c\n"
     620             :                               " JOIN pg_catalog.pg_namespace ns"
     621             :                               " ON c.relnamespace = ns.oid\n"
     622             :                               " WHERE ns.nspname != 'pg_catalog'\n"
     623             :                               "   AND c.relkind IN ("
     624             :                               CppAsString2(RELKIND_RELATION) ", "
     625             :                               CppAsString2(RELKIND_MATVIEW) ")\n"
     626             :                               " ORDER BY c.relpages DESC;");
     627           4 :             break;
     628             : 
     629           4 :         case REINDEX_SCHEMA:
     630             :             {
     631             :                 SimpleStringListCell *cell;
     632           4 :                 bool        nsp_listed = false;
     633             : 
     634             :                 Assert(user_list != NULL);
     635             : 
     636             :                 /*
     637             :                  * All the tables from all the listed schemas are grabbed at
     638             :                  * once.
     639             :                  */
     640           4 :                 appendPQExpBuffer(&catalog_query,
     641             :                                   "SELECT c.relname, ns.nspname\n"
     642             :                                   " FROM pg_catalog.pg_class c\n"
     643             :                                   " JOIN pg_catalog.pg_namespace ns"
     644             :                                   " ON c.relnamespace = ns.oid\n"
     645             :                                   " WHERE c.relkind IN ("
     646             :                                   CppAsString2(RELKIND_RELATION) ", "
     647             :                                   CppAsString2(RELKIND_MATVIEW) ")\n"
     648             :                                   " AND ns.nspname IN (");
     649             : 
     650          10 :                 for (cell = user_list->head; cell; cell = cell->next)
     651             :                 {
     652           6 :                     const char *nspname = cell->val;
     653             : 
     654           6 :                     if (nsp_listed)
     655           2 :                         appendPQExpBuffer(&catalog_query, ", ");
     656             :                     else
     657           4 :                         nsp_listed = true;
     658             : 
     659           6 :                     appendStringLiteralConn(&catalog_query, nspname, conn);
     660             :                 }
     661             : 
     662           4 :                 appendPQExpBuffer(&catalog_query, ")\n"
     663             :                                   " ORDER BY c.relpages DESC;");
     664             :             }
     665           4 :             break;
     666             : 
     667           0 :         case REINDEX_SYSTEM:
     668             :         case REINDEX_INDEX:
     669             :         case REINDEX_TABLE:
     670             :             Assert(false);
     671           0 :             break;
     672             :     }
     673             : 
     674           8 :     res = executeQuery(conn, catalog_query.data, echo);
     675           8 :     termPQExpBuffer(&catalog_query);
     676             : 
     677             :     /*
     678             :      * If no rows are returned, there are no matching tables, so we are done.
     679             :      */
     680           8 :     ntups = PQntuples(res);
     681           8 :     if (ntups == 0)
     682             :     {
     683           2 :         PQclear(res);
     684           2 :         PQfinish(conn);
     685           2 :         return NULL;
     686             :     }
     687             : 
     688           6 :     tables = pg_malloc0(sizeof(SimpleStringList));
     689             : 
     690             :     /* Build qualified identifiers for each table */
     691           6 :     initPQExpBuffer(&buf);
     692          38 :     for (i = 0; i < ntups; i++)
     693             :     {
     694          32 :         appendPQExpBufferStr(&buf,
     695          32 :                              fmtQualifiedId(PQgetvalue(res, i, 1),
     696          32 :                                             PQgetvalue(res, i, 0)));
     697             : 
     698          32 :         simple_string_list_append(tables, buf.data);
     699          32 :         resetPQExpBuffer(&buf);
     700             :     }
     701           6 :     termPQExpBuffer(&buf);
     702           6 :     PQclear(res);
     703             : 
     704           6 :     return tables;
     705             : }
     706             : 
     707             : static void
     708           4 : reindex_all_databases(const char *maintenance_db,
     709             :                       const char *host, const char *port,
     710             :                       const char *username, enum trivalue prompt_password,
     711             :                       const char *progname, bool echo, bool quiet, bool verbose,
     712             :                       bool concurrently, int concurrentCons)
     713             : {
     714             :     PGconn     *conn;
     715             :     PGresult   *result;
     716             :     PQExpBufferData connstr;
     717             :     int         i;
     718             : 
     719           4 :     conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
     720             :                                       prompt_password, progname, echo);
     721           4 :     result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", echo);
     722           4 :     PQfinish(conn);
     723             : 
     724           4 :     initPQExpBuffer(&connstr);
     725          22 :     for (i = 0; i < PQntuples(result); i++)
     726             :     {
     727          18 :         char       *dbname = PQgetvalue(result, i, 0);
     728             : 
     729          18 :         if (!quiet)
     730             :         {
     731          18 :             printf(_("%s: reindexing database \"%s\"\n"), progname, dbname);
     732          18 :             fflush(stdout);
     733             :         }
     734             : 
     735          18 :         resetPQExpBuffer(&connstr);
     736          18 :         appendPQExpBufferStr(&connstr, "dbname=");
     737          18 :         appendConnStrVal(&connstr, dbname);
     738             : 
     739          18 :         reindex_one_database(connstr.data, REINDEX_DATABASE, NULL, host,
     740             :                              port, username, prompt_password,
     741             :                              progname, echo, verbose, concurrently,
     742             :                              concurrentCons);
     743             :     }
     744           4 :     termPQExpBuffer(&connstr);
     745             : 
     746           4 :     PQclear(result);
     747           4 : }
     748             : 
     749             : static void
     750           2 : help(const char *progname)
     751             : {
     752           2 :     printf(_("%s reindexes a PostgreSQL database.\n\n"), progname);
     753           2 :     printf(_("Usage:\n"));
     754           2 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
     755           2 :     printf(_("\nOptions:\n"));
     756           2 :     printf(_("  -a, --all                 reindex all databases\n"));
     757           2 :     printf(_("      --concurrently        reindex concurrently\n"));
     758           2 :     printf(_("  -d, --dbname=DBNAME       database to reindex\n"));
     759           2 :     printf(_("  -e, --echo                show the commands being sent to the server\n"));
     760           2 :     printf(_("  -i, --index=INDEX         recreate specific index(es) only\n"));
     761           2 :     printf(_("  -j, --jobs=NUM            use this many concurrent connections to reindex\n"));
     762           2 :     printf(_("  -q, --quiet               don't write any messages\n"));
     763           2 :     printf(_("  -s, --system              reindex system catalogs\n"));
     764           2 :     printf(_("  -S, --schema=SCHEMA       reindex specific schema(s) only\n"));
     765           2 :     printf(_("  -t, --table=TABLE         reindex specific table(s) only\n"));
     766           2 :     printf(_("  -v, --verbose             write a lot of output\n"));
     767           2 :     printf(_("  -V, --version             output version information, then exit\n"));
     768           2 :     printf(_("  -?, --help                show this help, then exit\n"));
     769           2 :     printf(_("\nConnection options:\n"));
     770           2 :     printf(_("  -h, --host=HOSTNAME       database server host or socket directory\n"));
     771           2 :     printf(_("  -p, --port=PORT           database server port\n"));
     772           2 :     printf(_("  -U, --username=USERNAME   user name to connect as\n"));
     773           2 :     printf(_("  -w, --no-password         never prompt for password\n"));
     774           2 :     printf(_("  -W, --password            force password prompt\n"));
     775           2 :     printf(_("  --maintenance-db=DBNAME   alternate maintenance database\n"));
     776           2 :     printf(_("\nRead the description of the SQL command REINDEX for details.\n"));
     777           2 :     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     778           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
     779           2 : }

Generated by: LCOV version 1.13