PostgreSQL Source Code  git master
reindexdb.c File Reference
#include "postgres_fe.h"
#include <limits.h>
#include "catalog/pg_class_d.h"
#include "common.h"
#include "common/connect.h"
#include "common/logging.h"
#include "fe_utils/cancel.h"
#include "fe_utils/option_utils.h"
#include "fe_utils/parallel_slot.h"
#include "fe_utils/query_utils.h"
#include "fe_utils/simple_list.h"
#include "fe_utils/string_utils.h"
Include dependency graph for reindexdb.c:

Go to the source code of this file.

Typedefs

typedef enum ReindexType ReindexType
 

Enumerations

enum  ReindexType {
  REINDEX_DATABASE , REINDEX_INDEX , REINDEX_SCHEMA , REINDEX_SYSTEM ,
  REINDEX_TABLE
}
 

Functions

static SimpleStringListget_parallel_object_list (PGconn *conn, ReindexType type, SimpleStringList *user_list, bool echo)
 
static void reindex_one_database (ConnParams *cparams, ReindexType type, SimpleStringList *user_list, const char *progname, bool echo, bool verbose, bool concurrently, int concurrentCons, const char *tablespace)
 
static void reindex_all_databases (ConnParams *cparams, const char *progname, bool echo, bool quiet, bool verbose, bool concurrently, int concurrentCons, const char *tablespace, bool syscatalog, SimpleStringList *schemas, SimpleStringList *tables, SimpleStringList *indexes)
 
static void run_reindex_command (PGconn *conn, ReindexType type, const char *name, bool echo, bool verbose, bool concurrently, bool async, const char *tablespace)
 
static void help (const char *progname)
 
int main (int argc, char *argv[])
 

Typedef Documentation

◆ ReindexType

typedef enum ReindexType ReindexType

Enumeration Type Documentation

◆ ReindexType

Enumerator
REINDEX_DATABASE 
REINDEX_INDEX 
REINDEX_SCHEMA 
REINDEX_SYSTEM 
REINDEX_TABLE 

Definition at line 27 of file reindexdb.c.

28 {
34 } ReindexType;
ReindexType
Definition: reindexdb.c:28
@ REINDEX_SYSTEM
Definition: reindexdb.c:32
@ REINDEX_DATABASE
Definition: reindexdb.c:29
@ REINDEX_INDEX
Definition: reindexdb.c:30
@ REINDEX_SCHEMA
Definition: reindexdb.c:31
@ REINDEX_TABLE
Definition: reindexdb.c:33

Function Documentation

◆ get_parallel_object_list()

static SimpleStringList * get_parallel_object_list ( PGconn conn,
ReindexType  type,
SimpleStringList user_list,
bool  echo 
)
static

Definition at line 623 of file reindexdb.c.

625 {
626  PQExpBufferData catalog_query;
628  PGresult *res;
629  SimpleStringList *tables;
630  int ntups,
631  i;
632 
633  initPQExpBuffer(&catalog_query);
634 
635  /*
636  * The queries here are using a safe search_path, so there's no need to
637  * fully qualify everything.
638  */
639  switch (type)
640  {
641  case REINDEX_DATABASE:
642  Assert(user_list == NULL);
643  appendPQExpBufferStr(&catalog_query,
644  "SELECT c.relname, ns.nspname\n"
645  " FROM pg_catalog.pg_class c\n"
646  " JOIN pg_catalog.pg_namespace ns"
647  " ON c.relnamespace = ns.oid\n"
648  " WHERE ns.nspname != 'pg_catalog'\n"
649  " AND c.relkind IN ("
650  CppAsString2(RELKIND_RELATION) ", "
651  CppAsString2(RELKIND_MATVIEW) ")\n"
652  " ORDER BY c.relpages DESC;");
653  break;
654 
655  case REINDEX_SCHEMA:
656  {
657  SimpleStringListCell *cell;
658  bool nsp_listed = false;
659 
660  Assert(user_list != NULL);
661 
662  /*
663  * All the tables from all the listed schemas are grabbed at
664  * once.
665  */
666  appendPQExpBufferStr(&catalog_query,
667  "SELECT c.relname, ns.nspname\n"
668  " FROM pg_catalog.pg_class c\n"
669  " JOIN pg_catalog.pg_namespace ns"
670  " ON c.relnamespace = ns.oid\n"
671  " WHERE c.relkind IN ("
672  CppAsString2(RELKIND_RELATION) ", "
673  CppAsString2(RELKIND_MATVIEW) ")\n"
674  " AND ns.nspname IN (");
675 
676  for (cell = user_list->head; cell; cell = cell->next)
677  {
678  const char *nspname = cell->val;
679 
680  if (nsp_listed)
681  appendPQExpBufferStr(&catalog_query, ", ");
682  else
683  nsp_listed = true;
684 
685  appendStringLiteralConn(&catalog_query, nspname, conn);
686  }
687 
688  appendPQExpBufferStr(&catalog_query, ")\n"
689  " ORDER BY c.relpages DESC;");
690  }
691  break;
692 
693  case REINDEX_INDEX:
694  {
695  SimpleStringListCell *cell;
696 
697  Assert(user_list != NULL);
698 
699  /*
700  * Straight-forward index-level REINDEX is not supported with
701  * multiple jobs as we cannot control the concurrent
702  * processing of multiple indexes depending on the same
703  * relation. But we can extract the appropriate table name
704  * for the index and put REINDEX INDEX commands into different
705  * jobs, according to the parent tables.
706  *
707  * We will order the results to group the same tables
708  * together. We fetch index names as well to build a new list
709  * of them with matching order.
710  */
711  appendPQExpBufferStr(&catalog_query,
712  "SELECT t.relname, n.nspname, i.relname\n"
713  "FROM pg_catalog.pg_index x\n"
714  "JOIN pg_catalog.pg_class t ON t.oid = x.indrelid\n"
715  "JOIN pg_catalog.pg_class i ON i.oid = x.indexrelid\n"
716  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.relnamespace\n"
717  "WHERE x.indexrelid OPERATOR(pg_catalog.=) ANY(ARRAY['");
718 
719  for (cell = user_list->head; cell; cell = cell->next)
720  {
721  if (cell != user_list->head)
722  appendPQExpBufferStr(&catalog_query, "', '");
723 
724  appendQualifiedRelation(&catalog_query, cell->val, conn, echo);
725  }
726 
727  /*
728  * Order tables by the size of its greatest index. Within the
729  * table, order indexes by their sizes.
730  */
731  appendPQExpBufferStr(&catalog_query,
732  "']::pg_catalog.regclass[])\n"
733  "ORDER BY max(i.relpages) OVER \n"
734  " (PARTITION BY n.nspname, t.relname),\n"
735  " n.nspname, t.relname, i.relpages;\n");
736 
737  /*
738  * We're going to re-order the user_list to match the order of
739  * tables. So, empty the user_list to fill it from the query
740  * result.
741  */
742  simple_string_list_destroy(user_list);
743  user_list->head = user_list->tail = NULL;
744  }
745  break;
746 
747  case REINDEX_SYSTEM:
748  case REINDEX_TABLE:
749  Assert(false);
750  break;
751  }
752 
753  res = executeQuery(conn, catalog_query.data, echo);
754  termPQExpBuffer(&catalog_query);
755 
756  /*
757  * If no rows are returned, there are no matching tables, so we are done.
758  */
759  ntups = PQntuples(res);
760  if (ntups == 0)
761  {
762  PQclear(res);
763  PQfinish(conn);
764  return NULL;
765  }
766 
767  tables = pg_malloc0(sizeof(SimpleStringList));
768 
769  /* Build qualified identifiers for each table */
771  for (i = 0; i < ntups; i++)
772  {
775  PQgetvalue(res, i, 0)));
776 
777  simple_string_list_append(tables, buf.data);
779 
780  if (type == REINDEX_INDEX)
781  {
782  /*
783  * For index-level REINDEX, rebuild the list of indexes to match
784  * the order of tables list.
785  */
788  PQgetvalue(res, i, 2)));
789 
790  simple_string_list_append(user_list, buf.data);
792  }
793  }
795  PQclear(res);
796 
797  return tables;
798 }
void appendQualifiedRelation(PQExpBuffer buf, const char *spec, PGconn *conn, bool echo)
Definition: common.c:69
#define Assert(condition)
Definition: c.h:858
#define CppAsString2(x)
Definition: c.h:327
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4868
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3481
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3876
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
int i
Definition: isn.c:73
static PGresult * executeQuery(PGconn *conn, const char *query)
Definition: pg_dumpall.c:1883
static char * buf
Definition: pg_test_fsync.c:73
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
void simple_string_list_append(SimpleStringList *list, const char *val)
Definition: simple_list.c:63
void simple_string_list_destroy(SimpleStringList *list)
Definition: simple_list.c:125
PGconn * conn
Definition: streamutil.c:55
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
Definition: string_utils.c:293
const char * fmtQualifiedId(const char *schema, const char *id)
Definition: string_utils.c:145
char val[FLEXIBLE_ARRAY_MEMBER]
Definition: simple_list.h:37
struct SimpleStringListCell * next
Definition: simple_list.h:34
SimpleStringListCell * head
Definition: simple_list.h:42
SimpleStringListCell * tail
Definition: simple_list.h:43
const char * type

References appendPQExpBufferStr(), appendQualifiedRelation(), appendStringLiteralConn(), Assert, buf, conn, CppAsString2, PQExpBufferData::data, executeQuery(), fmtQualifiedId(), SimpleStringList::head, i, initPQExpBuffer(), SimpleStringListCell::next, pg_malloc0(), PQclear(), PQfinish(), PQgetvalue(), PQntuples(), REINDEX_DATABASE, REINDEX_INDEX, REINDEX_SCHEMA, REINDEX_SYSTEM, REINDEX_TABLE, res, resetPQExpBuffer(), simple_string_list_append(), simple_string_list_destroy(), SimpleStringList::tail, termPQExpBuffer(), type, and SimpleStringListCell::val.

Referenced by reindex_one_database().

◆ help()

static void help ( const char *  progname)
static

Definition at line 865 of file reindexdb.c.

866 {
867  printf(_("%s reindexes a PostgreSQL database.\n\n"), progname);
868  printf(_("Usage:\n"));
869  printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
870  printf(_("\nOptions:\n"));
871  printf(_(" -a, --all reindex all databases\n"));
872  printf(_(" --concurrently reindex concurrently\n"));
873  printf(_(" -d, --dbname=DBNAME database to reindex\n"));
874  printf(_(" -e, --echo show the commands being sent to the server\n"));
875  printf(_(" -i, --index=INDEX recreate specific index(es) only\n"));
876  printf(_(" -j, --jobs=NUM use this many concurrent connections to reindex\n"));
877  printf(_(" -q, --quiet don't write any messages\n"));
878  printf(_(" -s, --system reindex system catalogs only\n"));
879  printf(_(" -S, --schema=SCHEMA reindex specific schema(s) only\n"));
880  printf(_(" -t, --table=TABLE reindex specific table(s) only\n"));
881  printf(_(" --tablespace=TABLESPACE tablespace where indexes are rebuilt\n"));
882  printf(_(" -v, --verbose write a lot of output\n"));
883  printf(_(" -V, --version output version information, then exit\n"));
884  printf(_(" -?, --help show this help, then exit\n"));
885  printf(_("\nConnection options:\n"));
886  printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
887  printf(_(" -p, --port=PORT database server port\n"));
888  printf(_(" -U, --username=USERNAME user name to connect as\n"));
889  printf(_(" -w, --no-password never prompt for password\n"));
890  printf(_(" -W, --password force password prompt\n"));
891  printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
892  printf(_("\nRead the description of the SQL command REINDEX for details.\n"));
893  printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
894  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
895 }
#define _(x)
Definition: elog.c:90
const char * progname
Definition: main.c:44
#define printf(...)
Definition: port.h:244

References _, printf, and progname.

Referenced by main().

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 61 of file reindexdb.c.

62 {
63  static struct option long_options[] = {
64  {"host", required_argument, NULL, 'h'},
65  {"port", required_argument, NULL, 'p'},
66  {"username", required_argument, NULL, 'U'},
67  {"no-password", no_argument, NULL, 'w'},
68  {"password", no_argument, NULL, 'W'},
69  {"echo", no_argument, NULL, 'e'},
70  {"quiet", no_argument, NULL, 'q'},
71  {"schema", required_argument, NULL, 'S'},
72  {"dbname", required_argument, NULL, 'd'},
73  {"all", no_argument, NULL, 'a'},
74  {"system", no_argument, NULL, 's'},
75  {"table", required_argument, NULL, 't'},
76  {"index", required_argument, NULL, 'i'},
77  {"jobs", required_argument, NULL, 'j'},
78  {"verbose", no_argument, NULL, 'v'},
79  {"concurrently", no_argument, NULL, 1},
80  {"maintenance-db", required_argument, NULL, 2},
81  {"tablespace", required_argument, NULL, 3},
82  {NULL, 0, NULL, 0}
83  };
84 
85  const char *progname;
86  int optindex;
87  int c;
88 
89  const char *dbname = NULL;
90  const char *maintenance_db = NULL;
91  const char *host = NULL;
92  const char *port = NULL;
93  const char *username = NULL;
94  const char *tablespace = NULL;
95  enum trivalue prompt_password = TRI_DEFAULT;
96  ConnParams cparams;
97  bool syscatalog = false;
98  bool alldb = false;
99  bool echo = false;
100  bool quiet = false;
101  bool verbose = false;
102  bool concurrently = false;
103  SimpleStringList indexes = {NULL, NULL};
104  SimpleStringList tables = {NULL, NULL};
105  SimpleStringList schemas = {NULL, NULL};
106  int concurrentCons = 1;
107 
108  pg_logging_init(argv[0]);
109  progname = get_progname(argv[0]);
110  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
111 
112  handle_help_version_opts(argc, argv, "reindexdb", help);
113 
114  /* process command-line options */
115  while ((c = getopt_long(argc, argv, "ad:eh:i:j:qp:sS:t:U:vwW", long_options, &optindex)) != -1)
116  {
117  switch (c)
118  {
119  case 'a':
120  alldb = true;
121  break;
122  case 'd':
124  break;
125  case 'e':
126  echo = true;
127  break;
128  case 'h':
129  host = pg_strdup(optarg);
130  break;
131  case 'i':
133  break;
134  case 'j':
135  if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
136  &concurrentCons))
137  exit(1);
138  break;
139  case 'q':
140  quiet = true;
141  break;
142  case 'p':
143  port = pg_strdup(optarg);
144  break;
145  case 's':
146  syscatalog = true;
147  break;
148  case 'S':
150  break;
151  case 't':
153  break;
154  case 'U':
156  break;
157  case 'v':
158  verbose = true;
159  break;
160  case 'w':
161  prompt_password = TRI_NO;
162  break;
163  case 'W':
164  prompt_password = TRI_YES;
165  break;
166  case 1:
167  concurrently = true;
168  break;
169  case 2:
170  maintenance_db = pg_strdup(optarg);
171  break;
172  case 3:
174  break;
175  default:
176  /* getopt_long already emitted a complaint */
177  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
178  exit(1);
179  }
180  }
181 
182  /*
183  * Non-option argument specifies database name as long as it wasn't
184  * already specified with -d / --dbname
185  */
186  if (optind < argc && dbname == NULL)
187  {
188  dbname = argv[optind];
189  optind++;
190  }
191 
192  if (optind < argc)
193  {
194  pg_log_error("too many command-line arguments (first is \"%s\")",
195  argv[optind]);
196  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
197  exit(1);
198  }
199 
200  /* fill cparams except for dbname, which is set below */
201  cparams.pghost = host;
202  cparams.pgport = port;
203  cparams.pguser = username;
204  cparams.prompt_password = prompt_password;
205  cparams.override_dbname = NULL;
206 
207  setup_cancel_handler(NULL);
208 
209  if (concurrentCons > 1 && syscatalog)
210  pg_fatal("cannot use multiple jobs to reindex system catalogs");
211 
212  if (alldb)
213  {
214  if (dbname)
215  pg_fatal("cannot reindex all databases and a specific one at the same time");
216 
217  cparams.dbname = maintenance_db;
218 
219  reindex_all_databases(&cparams, progname, echo, quiet, verbose,
220  concurrently, concurrentCons, tablespace,
221  syscatalog, &schemas, &tables, &indexes);
222  }
223  else
224  {
225  if (dbname == NULL)
226  {
227  if (getenv("PGDATABASE"))
228  dbname = getenv("PGDATABASE");
229  else if (getenv("PGUSER"))
230  dbname = getenv("PGUSER");
231  else
233  }
234 
235  cparams.dbname = dbname;
236 
237  if (syscatalog)
238  reindex_one_database(&cparams, REINDEX_SYSTEM, NULL,
239  progname, echo, verbose,
240  concurrently, 1, tablespace);
241 
242  if (schemas.head != NULL)
243  reindex_one_database(&cparams, REINDEX_SCHEMA, &schemas,
244  progname, echo, verbose,
245  concurrently, concurrentCons, tablespace);
246 
247  if (indexes.head != NULL)
248  reindex_one_database(&cparams, REINDEX_INDEX, &indexes,
249  progname, echo, verbose,
250  concurrently, concurrentCons, tablespace);
251 
252  if (tables.head != NULL)
253  reindex_one_database(&cparams, REINDEX_TABLE, &tables,
254  progname, echo, verbose,
255  concurrently, concurrentCons, tablespace);
256 
257  /*
258  * reindex database only if neither index nor table nor schema nor
259  * system catalogs is specified
260  */
261  if (!syscatalog && indexes.head == NULL &&
262  tables.head == NULL && schemas.head == NULL)
263  reindex_one_database(&cparams, REINDEX_DATABASE, NULL,
264  progname, echo, verbose,
265  concurrently, concurrentCons, tablespace);
266  }
267 
268  exit(0);
269 }
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1214
void setup_cancel_handler(void(*query_cancel_callback)(void))
Definition: cancel.c:183
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:448
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define no_argument
Definition: getopt_long.h:24
#define required_argument
Definition: getopt_long.h:25
int verbose
exit(1)
void pg_logging_init(const char *argv0)
Definition: logging.c:83
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_error_hint(...)
Definition: logging.h:112
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
Definition: option_utils.c:50
void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
Definition: option_utils.c:24
#define pg_fatal(...)
PGDLLIMPORT int optind
Definition: getopt.c:50
PGDLLIMPORT char * optarg
Definition: getopt.c:52
static int port
Definition: pg_regress.c:116
const char * username
Definition: pgbench.c:296
char * tablespace
Definition: pgbench.c:216
const char * get_progname(const char *argv0)
Definition: path.c:574
char * c
static void reindex_all_databases(ConnParams *cparams, const char *progname, bool echo, bool quiet, bool verbose, bool concurrently, int concurrentCons, const char *tablespace, bool syscatalog, SimpleStringList *schemas, SimpleStringList *tables, SimpleStringList *indexes)
Definition: reindexdb.c:801
static void help(const char *progname)
Definition: reindexdb.c:865
static void reindex_one_database(ConnParams *cparams, ReindexType type, SimpleStringList *user_list, const char *progname, bool echo, bool verbose, bool concurrently, int concurrentCons, const char *tablespace)
Definition: reindexdb.c:272
char * dbname
Definition: streamutil.c:52
const char * pguser
Definition: connect_utils.h:31
char * override_dbname
Definition: pg_backup.h:91
char * pgport
Definition: pg_backup.h:85
char * pghost
Definition: pg_backup.h:86
char * dbname
Definition: pg_backup.h:84
enum trivalue prompt_password
Definition: connect_utils.h:32
const char * get_user_name_or_exit(const char *progname)
Definition: username.c:74
trivalue
Definition: vacuumlo.c:35
@ TRI_YES
Definition: vacuumlo.c:38
@ TRI_DEFAULT
Definition: vacuumlo.c:36
@ TRI_NO
Definition: vacuumlo.c:37

References dbname, _connParams::dbname, exit(), get_progname(), get_user_name_or_exit(), getopt_long(), handle_help_version_opts(), SimpleStringList::head, help(), no_argument, optarg, optind, option_parse_int(), _connParams::override_dbname, pg_fatal, pg_log_error, pg_log_error_hint, pg_logging_init(), pg_strdup(), PG_TEXTDOMAIN, _connParams::pghost, _connParams::pgport, _connParams::pguser, port, progname, _connParams::prompt_password, reindex_all_databases(), REINDEX_DATABASE, REINDEX_INDEX, reindex_one_database(), REINDEX_SCHEMA, REINDEX_SYSTEM, REINDEX_TABLE, required_argument, set_pglocale_pgservice(), setup_cancel_handler(), simple_string_list_append(), tablespace, TRI_DEFAULT, TRI_NO, TRI_YES, username, and verbose.

◆ reindex_all_databases()

static void reindex_all_databases ( ConnParams cparams,
const char *  progname,
bool  echo,
bool  quiet,
bool  verbose,
bool  concurrently,
int  concurrentCons,
const char *  tablespace,
bool  syscatalog,
SimpleStringList schemas,
SimpleStringList tables,
SimpleStringList indexes 
)
static

Definition at line 801 of file reindexdb.c.

807 {
808  PGconn *conn;
809  PGresult *result;
810  int i;
811 
812  conn = connectMaintenanceDatabase(cparams, progname, echo);
813  result = executeQuery(conn,
814  "SELECT datname FROM pg_database WHERE datallowconn AND datconnlimit <> -2 ORDER BY 1;",
815  echo);
816  PQfinish(conn);
817 
818  for (i = 0; i < PQntuples(result); i++)
819  {
820  char *dbname = PQgetvalue(result, i, 0);
821 
822  if (!quiet)
823  {
824  printf(_("%s: reindexing database \"%s\"\n"), progname, dbname);
825  fflush(stdout);
826  }
827 
828  cparams->override_dbname = dbname;
829 
830  if (syscatalog)
831  reindex_one_database(cparams, REINDEX_SYSTEM, NULL,
832  progname, echo, verbose,
833  concurrently, 1, tablespace);
834 
835  if (schemas->head != NULL)
836  reindex_one_database(cparams, REINDEX_SCHEMA, schemas,
837  progname, echo, verbose,
838  concurrently, concurrentCons, tablespace);
839 
840  if (indexes->head != NULL)
841  reindex_one_database(cparams, REINDEX_INDEX, indexes,
842  progname, echo, verbose,
843  concurrently, 1, tablespace);
844 
845  if (tables->head != NULL)
846  reindex_one_database(cparams, REINDEX_TABLE, tables,
847  progname, echo, verbose,
848  concurrently, concurrentCons, tablespace);
849 
850  /*
851  * reindex database only if neither index nor table nor schema nor
852  * system catalogs is specified
853  */
854  if (!syscatalog && indexes->head == NULL &&
855  tables->head == NULL && schemas->head == NULL)
856  reindex_one_database(cparams, REINDEX_DATABASE, NULL,
857  progname, echo, verbose,
858  concurrently, concurrentCons, tablespace);
859  }
860 
861  PQclear(result);
862 }
PGconn * connectMaintenanceDatabase(ConnParams *cparams, const char *progname, bool echo)
static void const char fflush(stdout)

References _, conn, connectMaintenanceDatabase(), dbname, executeQuery(), fflush(), SimpleStringList::head, i, _connParams::override_dbname, PQclear(), PQfinish(), PQgetvalue(), PQntuples(), printf, progname, REINDEX_DATABASE, REINDEX_INDEX, reindex_one_database(), REINDEX_SCHEMA, REINDEX_SYSTEM, REINDEX_TABLE, generate_unaccent_rules::stdout, tablespace, and verbose.

Referenced by main().

◆ reindex_one_database()

static void reindex_one_database ( ConnParams cparams,
ReindexType  type,
SimpleStringList user_list,
const char *  progname,
bool  echo,
bool  verbose,
bool  concurrently,
int  concurrentCons,
const char *  tablespace 
)
static

Definition at line 272 of file reindexdb.c.

277 {
278  PGconn *conn;
279  SimpleStringListCell *cell;
280  SimpleStringListCell *indices_tables_cell = NULL;
281  bool parallel = concurrentCons > 1;
282  SimpleStringList *process_list = user_list;
283  SimpleStringList *indices_tables_list = NULL;
284  ReindexType process_type = type;
286  bool failed = false;
287  int items_count = 0;
288  char *prev_index_table_name = NULL;
289  ParallelSlot *free_slot = NULL;
290 
291  conn = connectDatabase(cparams, progname, echo, false, true);
292 
293  if (concurrently && PQserverVersion(conn) < 120000)
294  {
295  PQfinish(conn);
296  pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
297  "concurrently", "12");
298  }
299 
300  if (tablespace && PQserverVersion(conn) < 140000)
301  {
302  PQfinish(conn);
303  pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
304  "tablespace", "14");
305  }
306 
307  if (!parallel)
308  {
309  switch (process_type)
310  {
311  case REINDEX_DATABASE:
312  case REINDEX_SYSTEM:
313 
314  /*
315  * Database and system reindexes only need to work on the
316  * database itself, so build a list with a single entry.
317  */
318  Assert(user_list == NULL);
319  process_list = pg_malloc0(sizeof(SimpleStringList));
320  simple_string_list_append(process_list, PQdb(conn));
321  break;
322 
323  case REINDEX_INDEX:
324  case REINDEX_SCHEMA:
325  case REINDEX_TABLE:
326  Assert(user_list != NULL);
327  break;
328  }
329  }
330  else
331  {
332  switch (process_type)
333  {
334  case REINDEX_DATABASE:
335 
336  /* Build a list of relations from the database */
337  process_list = get_parallel_object_list(conn, process_type,
338  user_list, echo);
339  process_type = REINDEX_TABLE;
340 
341  /* Bail out if nothing to process */
342  if (process_list == NULL)
343  return;
344  break;
345 
346  case REINDEX_SCHEMA:
347  Assert(user_list != NULL);
348 
349  /* Build a list of relations from all the schemas */
350  process_list = get_parallel_object_list(conn, process_type,
351  user_list, echo);
352  process_type = REINDEX_TABLE;
353 
354  /* Bail out if nothing to process */
355  if (process_list == NULL)
356  return;
357  break;
358 
359  case REINDEX_INDEX:
360  Assert(user_list != NULL);
361 
362  /*
363  * Build a list of relations from the indices. This will
364  * accordingly reorder the list of indices too.
365  */
366  indices_tables_list = get_parallel_object_list(conn, process_type,
367  user_list, echo);
368 
369  /*
370  * Bail out if nothing to process. 'user_list' was modified
371  * in-place, so check if it has at least one cell.
372  */
373  if (user_list->head == NULL)
374  return;
375 
376  /*
377  * Assuming 'user_list' is not empty, 'indices_tables_list'
378  * shouldn't be empty as well.
379  */
380  Assert(indices_tables_list != NULL);
381  indices_tables_cell = indices_tables_list->head;
382 
383  break;
384 
385  case REINDEX_SYSTEM:
386  /* not supported */
387  Assert(false);
388  break;
389 
390  case REINDEX_TABLE:
391 
392  /*
393  * Fall through. The list of items for tables is already
394  * created.
395  */
396  break;
397  }
398  }
399 
400  /*
401  * Adjust the number of concurrent connections depending on the items in
402  * the list. We choose the minimum between the number of concurrent
403  * connections and the number of items in the list.
404  */
405  for (cell = process_list->head; cell; cell = cell->next)
406  {
407  items_count++;
408 
409  /* no need to continue if there are more elements than jobs */
410  if (items_count >= concurrentCons)
411  break;
412  }
413  concurrentCons = Min(concurrentCons, items_count);
414  Assert(concurrentCons > 0);
415 
416  Assert(process_list != NULL);
417 
418  sa = ParallelSlotsSetup(concurrentCons, cparams, progname, echo, NULL);
420 
421  cell = process_list->head;
422  do
423  {
424  const char *objname = cell->val;
425  bool need_new_slot = true;
426 
427  if (CancelRequested)
428  {
429  failed = true;
430  goto finish;
431  }
432 
433  /*
434  * For parallel index-level REINDEX, the indices of the same table are
435  * ordered together and they are to be processed by the same job. So,
436  * we don't switch the job as soon as the index belongs to the same
437  * table as the previous one.
438  */
439  if (parallel && process_type == REINDEX_INDEX)
440  {
441  if (prev_index_table_name != NULL &&
442  strcmp(prev_index_table_name, indices_tables_cell->val) == 0)
443  need_new_slot = false;
444  prev_index_table_name = indices_tables_cell->val;
445  indices_tables_cell = indices_tables_cell->next;
446  }
447 
448  if (need_new_slot)
449  {
450  free_slot = ParallelSlotsGetIdle(sa, NULL);
451  if (!free_slot)
452  {
453  failed = true;
454  goto finish;
455  }
456 
458  }
459 
460  run_reindex_command(free_slot->connection, process_type, objname,
461  echo, verbose, concurrently, true, tablespace);
462 
463  cell = cell->next;
464  } while (cell != NULL);
465 
467  failed = true;
468 
469 finish:
470  if (process_list != user_list)
471  {
472  simple_string_list_destroy(process_list);
473  pg_free(process_list);
474  }
475 
476  if (indices_tables_list)
477  {
478  simple_string_list_destroy(indices_tables_list);
479  pg_free(indices_tables_list);
480  }
481 
483  pfree(sa);
484 
485  if (failed)
486  exit(1);
487 }
#define Min(x, y)
Definition: c.h:1004
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:7137
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6993
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void pfree(void *pointer)
Definition: mcxt.c:1520
ParallelSlot * ParallelSlotsGetIdle(ParallelSlotArray *sa, const char *dbname)
bool ParallelSlotsWaitCompletion(ParallelSlotArray *sa)
ParallelSlotArray * ParallelSlotsSetup(int numslots, ConnParams *cparams, const char *progname, bool echo, const char *initcmd)
bool TableCommandResultHandler(PGresult *res, PGconn *conn, void *context)
void ParallelSlotsTerminate(ParallelSlotArray *sa)
void ParallelSlotsAdoptConn(ParallelSlotArray *sa, PGconn *conn)
static void ParallelSlotSetHandler(ParallelSlot *slot, ParallelSlotResultHandler handler, void *context)
Definition: parallel_slot.h:47
static PGconn * connectDatabase(const char *dbname, const char *connection_string, const char *pghost, const char *pgport, const char *pguser, trivalue prompt_password, bool fail_on_error)
Definition: pg_dumpall.c:1663
static SimpleStringList * get_parallel_object_list(PGconn *conn, ReindexType type, SimpleStringList *user_list, bool echo)
Definition: reindexdb.c:623
static void run_reindex_command(PGconn *conn, ReindexType type, const char *name, bool echo, bool verbose, bool concurrently, bool async, const char *tablespace)
Definition: reindexdb.c:490
PGconn * connection
Definition: parallel_slot.h:23

References Assert, CancelRequested, conn, connectDatabase(), ParallelSlot::connection, exit(), get_parallel_object_list(), SimpleStringList::head, Min, SimpleStringListCell::next, ParallelSlotsAdoptConn(), ParallelSlotSetHandler(), ParallelSlotsGetIdle(), ParallelSlotsSetup(), ParallelSlotsTerminate(), ParallelSlotsWaitCompletion(), pfree(), pg_fatal, pg_free(), pg_malloc0(), PQdb(), PQfinish(), PQserverVersion(), progname, REINDEX_DATABASE, REINDEX_INDEX, REINDEX_SCHEMA, REINDEX_SYSTEM, REINDEX_TABLE, run_reindex_command(), simple_string_list_append(), simple_string_list_destroy(), TableCommandResultHandler(), tablespace, type, SimpleStringListCell::val, and verbose.

Referenced by main(), and reindex_all_databases().

◆ run_reindex_command()

static void run_reindex_command ( PGconn conn,
ReindexType  type,
const char *  name,
bool  echo,
bool  verbose,
bool  concurrently,
bool  async,
const char *  tablespace 
)
static

Definition at line 490 of file reindexdb.c.

493 {
494  const char *paren = "(";
495  const char *comma = ", ";
496  const char *sep = paren;
497  PQExpBufferData sql;
498  bool status;
499 
500  Assert(name);
501 
502  /* build the REINDEX query */
503  initPQExpBuffer(&sql);
504 
505  appendPQExpBufferStr(&sql, "REINDEX ");
506 
507  if (verbose)
508  {
509  appendPQExpBuffer(&sql, "%sVERBOSE", sep);
510  sep = comma;
511  }
512 
513  if (tablespace)
514  {
515  appendPQExpBuffer(&sql, "%sTABLESPACE %s", sep, fmtId(tablespace));
516  sep = comma;
517  }
518 
519  if (sep != paren)
520  appendPQExpBufferStr(&sql, ") ");
521 
522  /* object type */
523  switch (type)
524  {
525  case REINDEX_DATABASE:
526  appendPQExpBufferStr(&sql, "DATABASE ");
527  break;
528  case REINDEX_INDEX:
529  appendPQExpBufferStr(&sql, "INDEX ");
530  break;
531  case REINDEX_SCHEMA:
532  appendPQExpBufferStr(&sql, "SCHEMA ");
533  break;
534  case REINDEX_SYSTEM:
535  appendPQExpBufferStr(&sql, "SYSTEM ");
536  break;
537  case REINDEX_TABLE:
538  appendPQExpBufferStr(&sql, "TABLE ");
539  break;
540  }
541 
542  /*
543  * Parenthesized grammar is only supported for CONCURRENTLY since
544  * PostgreSQL 14. Since 12, CONCURRENTLY can be specified after the
545  * object type.
546  */
547  if (concurrently)
548  appendPQExpBufferStr(&sql, "CONCURRENTLY ");
549 
550  /* object name */
551  switch (type)
552  {
553  case REINDEX_DATABASE:
554  case REINDEX_SYSTEM:
556  break;
557  case REINDEX_INDEX:
558  case REINDEX_TABLE:
559  appendQualifiedRelation(&sql, name, conn, echo);
560  break;
561  case REINDEX_SCHEMA:
562  appendPQExpBufferStr(&sql, name);
563  break;
564  }
565 
566  /* finish the query */
567  appendPQExpBufferChar(&sql, ';');
568 
569  if (async)
570  {
571  if (echo)
572  printf("%s\n", sql.data);
573 
574  status = PQsendQuery(conn, sql.data) == 1;
575  }
576  else
577  status = executeMaintenanceCommand(conn, sql.data, echo);
578 
579  if (!status)
580  {
581  switch (type)
582  {
583  case REINDEX_DATABASE:
584  pg_log_error("reindexing of database \"%s\" failed: %s",
586  break;
587  case REINDEX_INDEX:
588  pg_log_error("reindexing of index \"%s\" in database \"%s\" failed: %s",
590  break;
591  case REINDEX_SCHEMA:
592  pg_log_error("reindexing of schema \"%s\" in database \"%s\" failed: %s",
594  break;
595  case REINDEX_SYSTEM:
596  pg_log_error("reindexing of system catalogs in database \"%s\" failed: %s",
598  break;
599  case REINDEX_TABLE:
600  pg_log_error("reindexing of table \"%s\" in database \"%s\" failed: %s",
602  break;
603  }
604  if (!async)
605  {
606  PQfinish(conn);
607  exit(1);
608  }
609  }
610 
611  termPQExpBuffer(&sql);
612 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7147
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1416
#define comma
Definition: indent_codes.h:48
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
bool executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
Definition: query_utils.c:74
const char * fmtId(const char *rawid)
Definition: string_utils.c:64
const char * name

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), appendQualifiedRelation(), Assert, comma, conn, PQExpBufferData::data, executeMaintenanceCommand(), exit(), fmtId(), initPQExpBuffer(), name, pg_log_error, PQdb(), PQerrorMessage(), PQfinish(), PQsendQuery(), printf, REINDEX_DATABASE, REINDEX_INDEX, REINDEX_SCHEMA, REINDEX_SYSTEM, REINDEX_TABLE, tablespace, termPQExpBuffer(), type, and verbose.

Referenced by reindex_one_database().