PostgreSQL Source Code  git master
common.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * common.c
4  * Common support routines for bin/scripts/
5  *
6  *
7  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * src/bin/scripts/common.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 
15 #include "postgres_fe.h"
16 
17 #include <signal.h>
18 #include <unistd.h>
19 
20 #include "common.h"
21 #include "common/logging.h"
22 #include "fe_utils/connect.h"
23 #include "fe_utils/string_utils.h"
24 
25 #define ERRCODE_UNDEFINED_TABLE "42P01"
26 
27 
28 static PGcancel *volatile cancelConn = NULL;
29 bool CancelRequested = false;
30 
31 #ifdef WIN32
32 static CRITICAL_SECTION cancelConnLock;
33 #endif
34 
35 /*
36  * Provide strictly harmonized handling of --help and --version
37  * options.
38  */
39 void
40 handle_help_version_opts(int argc, char *argv[],
41  const char *fixed_progname, help_handler hlp)
42 {
43  if (argc > 1)
44  {
45  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
46  {
47  hlp(get_progname(argv[0]));
48  exit(0);
49  }
50  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
51  {
52  printf("%s (PostgreSQL) " PG_VERSION "\n", fixed_progname);
53  exit(0);
54  }
55  }
56 }
57 
58 
59 /*
60  * Make a database connection with the given parameters.
61  *
62  * An interactive password prompt is automatically issued if needed and
63  * allowed by prompt_password.
64  *
65  * If allow_password_reuse is true, we will try to re-use any password
66  * given during previous calls to this routine. (Callers should not pass
67  * allow_password_reuse=true unless reconnecting to the same database+user
68  * as before, else we might create password exposure hazards.)
69  */
70 PGconn *
71 connectDatabase(const char *dbname, const char *pghost,
72  const char *pgport, const char *pguser,
73  enum trivalue prompt_password, const char *progname,
74  bool echo, bool fail_ok, bool allow_password_reuse)
75 {
76  PGconn *conn;
77  bool new_pass;
78  static bool have_password = false;
79  static char password[100];
80 
81  if (!allow_password_reuse)
82  have_password = false;
83 
84  if (!have_password && prompt_password == TRI_YES)
85  {
86  simple_prompt("Password: ", password, sizeof(password), false);
87  have_password = true;
88  }
89 
90  /*
91  * Start the connection. Loop until we have a password if requested by
92  * backend.
93  */
94  do
95  {
96  const char *keywords[7];
97  const char *values[7];
98 
99  keywords[0] = "host";
100  values[0] = pghost;
101  keywords[1] = "port";
102  values[1] = pgport;
103  keywords[2] = "user";
104  values[2] = pguser;
105  keywords[3] = "password";
106  values[3] = have_password ? password : NULL;
107  keywords[4] = "dbname";
108  values[4] = dbname;
109  keywords[5] = "fallback_application_name";
110  values[5] = progname;
111  keywords[6] = NULL;
112  values[6] = NULL;
113 
114  new_pass = false;
115  conn = PQconnectdbParams(keywords, values, true);
116 
117  if (!conn)
118  {
119  pg_log_error("could not connect to database %s: out of memory",
120  dbname);
121  exit(1);
122  }
123 
124  /*
125  * No luck? Trying asking (again) for a password.
126  */
127  if (PQstatus(conn) == CONNECTION_BAD &&
129  prompt_password != TRI_NO)
130  {
131  PQfinish(conn);
132  simple_prompt("Password: ", password, sizeof(password), false);
133  have_password = true;
134  new_pass = true;
135  }
136  } while (new_pass);
137 
138  /* check to see that the backend connection was successfully made */
139  if (PQstatus(conn) == CONNECTION_BAD)
140  {
141  if (fail_ok)
142  {
143  PQfinish(conn);
144  return NULL;
145  }
146  pg_log_error("could not connect to database %s: %s",
147  dbname, PQerrorMessage(conn));
148  exit(1);
149  }
150 
152 
153  return conn;
154 }
155 
156 /*
157  * Try to connect to the appropriate maintenance database.
158  */
159 PGconn *
160 connectMaintenanceDatabase(const char *maintenance_db,
161  const char *pghost, const char *pgport,
162  const char *pguser, enum trivalue prompt_password,
163  const char *progname, bool echo)
164 {
165  PGconn *conn;
166 
167  /* If a maintenance database name was specified, just connect to it. */
168  if (maintenance_db)
169  return connectDatabase(maintenance_db, pghost, pgport, pguser,
170  prompt_password, progname, echo, false, false);
171 
172  /* Otherwise, try postgres first and then template1. */
173  conn = connectDatabase("postgres", pghost, pgport, pguser, prompt_password,
174  progname, echo, true, false);
175  if (!conn)
176  conn = connectDatabase("template1", pghost, pgport, pguser,
177  prompt_password, progname, echo, false, false);
178 
179  return conn;
180 }
181 
182 /*
183  * Disconnect the given connection, canceling any statement if one is active.
184  */
185 void
187 {
188  char errbuf[256];
189 
190  Assert(conn != NULL);
191 
192  if (PQtransactionStatus(conn) == PQTRANS_ACTIVE)
193  {
194  PGcancel *cancel;
195 
196  if ((cancel = PQgetCancel(conn)))
197  {
198  (void) PQcancel(cancel, errbuf, sizeof(errbuf));
199  PQfreeCancel(cancel);
200  }
201  }
202 
203  PQfinish(conn);
204 }
205 
206 /*
207  * Run a query, return the results, exit program on failure.
208  */
209 PGresult *
210 executeQuery(PGconn *conn, const char *query, bool echo)
211 {
212  PGresult *res;
213 
214  if (echo)
215  printf("%s\n", query);
216 
217  res = PQexec(conn, query);
218  if (!res ||
220  {
221  pg_log_error("query failed: %s", PQerrorMessage(conn));
222  pg_log_info("query was: %s", query);
223  PQfinish(conn);
224  exit(1);
225  }
226 
227  return res;
228 }
229 
230 
231 /*
232  * As above for a SQL command (which returns nothing).
233  */
234 void
235 executeCommand(PGconn *conn, const char *query, bool echo)
236 {
237  PGresult *res;
238 
239  if (echo)
240  printf("%s\n", query);
241 
242  res = PQexec(conn, query);
243  if (!res ||
245  {
246  pg_log_error("query failed: %s", PQerrorMessage(conn));
247  pg_log_info("query was: %s", query);
248  PQfinish(conn);
249  exit(1);
250  }
251 
252  PQclear(res);
253 }
254 
255 
256 /*
257  * As above for a SQL maintenance command (returns command success).
258  * Command is executed with a cancel handler set, so Ctrl-C can
259  * interrupt it.
260  */
261 bool
262 executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
263 {
264  PGresult *res;
265  bool r;
266 
267  if (echo)
268  printf("%s\n", query);
269 
270  SetCancelConn(conn);
271  res = PQexec(conn, query);
272  ResetCancelConn();
273 
274  r = (res && PQresultStatus(res) == PGRES_COMMAND_OK);
275 
276  if (res)
277  PQclear(res);
278 
279  return r;
280 }
281 
282 /*
283  * Consume all the results generated for the given connection until
284  * nothing remains. If at least one error is encountered, return false.
285  * Note that this will block if the connection is busy.
286  */
287 bool
289 {
290  bool ok = true;
291  PGresult *result;
292 
293  SetCancelConn(conn);
294  while ((result = PQgetResult(conn)) != NULL)
295  {
296  if (!processQueryResult(conn, result))
297  ok = false;
298  }
299  ResetCancelConn();
300  return ok;
301 }
302 
303 /*
304  * Process (and delete) a query result. Returns true if there's no error,
305  * false otherwise -- but errors about trying to work on a missing relation
306  * are reported and subsequently ignored.
307  */
308 bool
310 {
311  /*
312  * If it's an error, report it. Errors about a missing table are harmless
313  * so we continue processing; but die for other errors.
314  */
315  if (PQresultStatus(result) != PGRES_COMMAND_OK)
316  {
317  char *sqlState = PQresultErrorField(result, PG_DIAG_SQLSTATE);
318 
319  pg_log_error("processing of database \"%s\" failed: %s",
320  PQdb(conn), PQerrorMessage(conn));
321 
322  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) != 0)
323  {
324  PQclear(result);
325  return false;
326  }
327  }
328 
329  PQclear(result);
330  return true;
331 }
332 
333 
334 /*
335  * Split TABLE[(COLUMNS)] into TABLE and [(COLUMNS)] portions. When you
336  * finish using them, pg_free(*table). *columns is a pointer into "spec",
337  * possibly to its NUL terminator.
338  */
339 void
340 splitTableColumnsSpec(const char *spec, int encoding,
341  char **table, const char **columns)
342 {
343  bool inquotes = false;
344  const char *cp = spec;
345 
346  /*
347  * Find the first '(' not identifier-quoted. Based on
348  * dequote_downcase_identifier().
349  */
350  while (*cp && (*cp != '(' || inquotes))
351  {
352  if (*cp == '"')
353  {
354  if (inquotes && cp[1] == '"')
355  cp++; /* pair does not affect quoting */
356  else
357  inquotes = !inquotes;
358  cp++;
359  }
360  else
361  cp += PQmblen(cp, encoding);
362  }
363  *table = pg_strdup(spec);
364  (*table)[cp - spec] = '\0'; /* no strndup */
365  *columns = cp;
366 }
367 
368 /*
369  * Break apart TABLE[(COLUMNS)] of "spec". With the reset_val of search_path
370  * in effect, have regclassin() interpret the TABLE portion. Append to "buf"
371  * the qualified name of TABLE, followed by any (COLUMNS). Exit on failure.
372  * We use this to interpret --table=foo under the search path psql would get,
373  * in advance of "ANALYZE public.foo" under the always-secure search path.
374  */
375 void
377  PGconn *conn, bool echo)
378 {
379  char *table;
380  const char *columns;
381  PQExpBufferData sql;
382  PGresult *res;
383  int ntups;
384 
385  splitTableColumnsSpec(spec, PQclientEncoding(conn), &table, &columns);
386 
387  /*
388  * Query must remain ABSOLUTELY devoid of unqualified names. This would
389  * be unnecessary given a regclassin() variant taking a search_path
390  * argument.
391  */
392  initPQExpBuffer(&sql);
394  "SELECT c.relname, ns.nspname\n"
395  " FROM pg_catalog.pg_class c,"
396  " pg_catalog.pg_namespace ns\n"
397  " WHERE c.relnamespace OPERATOR(pg_catalog.=) ns.oid\n"
398  " AND c.oid OPERATOR(pg_catalog.=) ");
399  appendStringLiteralConn(&sql, table, conn);
400  appendPQExpBufferStr(&sql, "::pg_catalog.regclass;");
401 
402  executeCommand(conn, "RESET search_path;", echo);
403 
404  /*
405  * One row is a typical result, as is a nonexistent relation ERROR.
406  * regclassin() unconditionally accepts all-digits input as an OID; if no
407  * relation has that OID; this query returns no rows. Catalog corruption
408  * might elicit other row counts.
409  */
410  res = executeQuery(conn, sql.data, echo);
411  ntups = PQntuples(res);
412  if (ntups != 1)
413  {
414  pg_log_error(ngettext("query returned %d row instead of one: %s",
415  "query returned %d rows instead of one: %s",
416  ntups),
417  ntups, sql.data);
418  PQfinish(conn);
419  exit(1);
420  }
422  fmtQualifiedId(PQgetvalue(res, 0, 1),
423  PQgetvalue(res, 0, 0)));
424  appendPQExpBufferStr(buf, columns);
425  PQclear(res);
426  termPQExpBuffer(&sql);
427  pg_free(table);
428 
430 }
431 
432 
433 /*
434  * Check yes/no answer in a localized way. 1=yes, 0=no, -1=neither.
435  */
436 
437 /* translator: abbreviation for "yes" */
438 #define PG_YESLETTER gettext_noop("y")
439 /* translator: abbreviation for "no" */
440 #define PG_NOLETTER gettext_noop("n")
441 
442 bool
443 yesno_prompt(const char *question)
444 {
445  char prompt[256];
446 
447  /*------
448  translator: This is a question followed by the translated options for
449  "yes" and "no". */
450  snprintf(prompt, sizeof(prompt), _("%s (%s/%s) "),
451  _(question), _(PG_YESLETTER), _(PG_NOLETTER));
452 
453  for (;;)
454  {
455  char resp[10];
456 
457  simple_prompt(prompt, resp, sizeof(resp), true);
458 
459  if (strcmp(resp, _(PG_YESLETTER)) == 0)
460  return true;
461  if (strcmp(resp, _(PG_NOLETTER)) == 0)
462  return false;
463 
464  printf(_("Please answer \"%s\" or \"%s\".\n"),
466  }
467 }
468 
469 /*
470  * SetCancelConn
471  *
472  * Set cancelConn to point to the current database connection.
473  */
474 void
476 {
477  PGcancel *oldCancelConn;
478 
479 #ifdef WIN32
480  EnterCriticalSection(&cancelConnLock);
481 #endif
482 
483  /* Free the old one if we have one */
484  oldCancelConn = cancelConn;
485 
486  /* be sure handle_sigint doesn't use pointer while freeing */
487  cancelConn = NULL;
488 
489  if (oldCancelConn != NULL)
490  PQfreeCancel(oldCancelConn);
491 
492  cancelConn = PQgetCancel(conn);
493 
494 #ifdef WIN32
495  LeaveCriticalSection(&cancelConnLock);
496 #endif
497 }
498 
499 /*
500  * ResetCancelConn
501  *
502  * Free the current cancel connection, if any, and set to NULL.
503  */
504 void
506 {
507  PGcancel *oldCancelConn;
508 
509 #ifdef WIN32
510  EnterCriticalSection(&cancelConnLock);
511 #endif
512 
513  oldCancelConn = cancelConn;
514 
515  /* be sure handle_sigint doesn't use pointer while freeing */
516  cancelConn = NULL;
517 
518  if (oldCancelConn != NULL)
519  PQfreeCancel(oldCancelConn);
520 
521 #ifdef WIN32
522  LeaveCriticalSection(&cancelConnLock);
523 #endif
524 }
525 
526 #ifndef WIN32
527 /*
528  * Handle interrupt signals by canceling the current command, if a cancelConn
529  * is set.
530  */
531 static void
533 {
534  int save_errno = errno;
535  char errbuf[256];
536 
537  /* Send QueryCancel if we are processing a database query */
538  if (cancelConn != NULL)
539  {
540  if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
541  {
542  CancelRequested = true;
543  fprintf(stderr, _("Cancel request sent\n"));
544  }
545  else
546  fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
547  }
548  else
549  CancelRequested = true;
550 
551  errno = save_errno; /* just in case the write changed it */
552 }
553 
554 void
556 {
557  pqsignal(SIGINT, handle_sigint);
558 }
559 #else /* WIN32 */
560 
561 /*
562  * Console control handler for Win32. Note that the control handler will
563  * execute on a *different thread* than the main one, so we need to do
564  * proper locking around those structures.
565  */
566 static BOOL WINAPI
567 consoleHandler(DWORD dwCtrlType)
568 {
569  char errbuf[256];
570 
571  if (dwCtrlType == CTRL_C_EVENT ||
572  dwCtrlType == CTRL_BREAK_EVENT)
573  {
574  /* Send QueryCancel if we are processing a database query */
575  EnterCriticalSection(&cancelConnLock);
576  if (cancelConn != NULL)
577  {
578  if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
579  {
580  fprintf(stderr, _("Cancel request sent\n"));
581  CancelRequested = true;
582  }
583  else
584  fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
585  }
586  else
587  CancelRequested = true;
588 
589  LeaveCriticalSection(&cancelConnLock);
590 
591  return TRUE;
592  }
593  else
594  /* Return FALSE for any signals not being handled */
595  return FALSE;
596 }
597 
598 void
600 {
601  InitializeCriticalSection(&cancelConnLock);
602 
603  SetConsoleCtrlHandler(consoleHandler, TRUE);
604 }
605 
606 #endif /* WIN32 */
PGconn * connectMaintenanceDatabase(const char *maintenance_db, const char *pghost, const char *pgport, const char *pguser, enum trivalue prompt_password, const char *progname, bool echo)
Definition: common.c:160
static char password[100]
Definition: streamutil.c:55
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6596
#define TRUE
Definition: ecpglib.h:35
#define PG_YESLETTER
Definition: common.c:438
bool yesno_prompt(const char *question)
Definition: common.c:443
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3164
PGresult * executeQuery(PGconn *conn, const char *query, bool echo)
Definition: common.c:210
void executeCommand(PGconn *conn, const char *query, bool echo)
Definition: common.c:235
bool processQueryResult(PGconn *conn, PGresult *result)
Definition: common.c:309
const char * get_progname(const char *argv0)
Definition: path.c:453
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
#define pg_log_error(...)
Definition: logging.h:79
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
void PQfreeCancel(PGcancel *cancel)
Definition: fe-connect.c:4242
#define FALSE
Definition: ecpglib.h:39
bool consumeQueryResult(PGconn *conn)
Definition: common.c:288
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4098
#define printf(...)
Definition: port.h:198
#define PG_NOLETTER
Definition: common.c:440
const char * progname
Definition: pg_standby.c:37
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2770
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
#define fprintf
Definition: port.h:196
int PQclientEncoding(const PGconn *conn)
Definition: fe-connect.c:6656
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2693
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:622
PGconn * conn
Definition: streamutil.c:56
static char * buf
Definition: pg_test_fsync.c:68
bool executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
Definition: common.c:262
void simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo)
Definition: sprompt.c:37
PGcancel * PQgetCancel(PGconn *conn)
Definition: fe-connect.c:4219
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void SetCancelConn(void)
Definition: common.c:439
void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
Definition: common.c:40
void setup_cancel_handler(void)
Definition: common.c:311
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:6551
char * pghost
Definition: pgbench.c:240
trivalue
Definition: vacuumlo.c:34
#define ngettext(s, p, n)
Definition: c.h:1103
void disconnectDatabase(PGconn *conn)
Definition: common.c:186
#define ERRCODE_UNDEFINED_TABLE
Definition: common.c:25
static void handle_sigint(SIGNAL_ARGS)
Definition: common.c:532
void PQclear(PGresult *res)
Definition: fe-exec.c:695
void(* help_handler)(const char *progname)
Definition: common.h:26
pqsigfunc pqsignal(int signum, pqsigfunc handler)
Definition: signal.c:170
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6446
static bool have_password
Definition: streamutil.c:54
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:2755
#define SIGNAL_ARGS
Definition: c.h:1259
#define Assert(condition)
Definition: c.h:732
PGconn * connectDatabase(const char *dbname, const char *pghost, const char *pgport, const char *pguser, enum trivalue prompt_password, const char *progname, bool echo, bool fail_ok, bool allow_password_reuse)
Definition: common.c:71
char * dbname
Definition: streamutil.c:52
const char * fmtQualifiedId(const char *schema, const char *id)
Definition: string_utils.c:147
void pg_free(void *ptr)
Definition: fe_memutils.c:105
#define ALWAYS_SECURE_SEARCH_PATH_SQL
Definition: connect.h:25
int32 encoding
Definition: pg_database.h:41
void appendQualifiedRelation(PQExpBuffer buf, const char *spec, PGconn *conn, bool echo)
Definition: common.c:376
static Datum values[MAXATTR]
Definition: bootstrap.c:167
static PGcancel *volatile cancelConn
Definition: common.c:28
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
Definition: fe-connect.c:4374
bool CancelRequested
Definition: common.c:29
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
Definition: string_utils.c:295
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6630
void splitTableColumnsSpec(const char *spec, int encoding, char **table, const char **columns)
Definition: common.c:340
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1940
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6543
int PQmblen(const char *s, int encoding)
Definition: fe-misc.c:1217
#define snprintf
Definition: port.h:192
void ResetCancelConn(void)
Definition: common.c:469
#define _(x)
Definition: elog.c:84
char * pgport
Definition: pgbench.c:241
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1779
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
#define pg_log_info(...)
Definition: logging.h:87