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