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

Generated by: LCOV version 1.13