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

Generated by: LCOV version 1.13