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/cancel.h"
23 #include "fe_utils/connect.h"
24 #include "fe_utils/string_utils.h"
25 
26 #define ERRCODE_UNDEFINED_TABLE "42P01"
27 
28 /*
29  * Provide strictly harmonized handling of --help and --version
30  * options.
31  */
32 void
33 handle_help_version_opts(int argc, char *argv[],
34  const char *fixed_progname, help_handler hlp)
35 {
36  if (argc > 1)
37  {
38  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
39  {
40  hlp(get_progname(argv[0]));
41  exit(0);
42  }
43  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
44  {
45  printf("%s (PostgreSQL) " PG_VERSION "\n", fixed_progname);
46  exit(0);
47  }
48  }
49 }
50 
51 
52 /*
53  * Make a database connection with the given parameters.
54  *
55  * An interactive password prompt is automatically issued if needed and
56  * allowed by prompt_password.
57  *
58  * If allow_password_reuse is true, we will try to re-use any password
59  * given during previous calls to this routine. (Callers should not pass
60  * allow_password_reuse=true unless reconnecting to the same database+user
61  * as before, else we might create password exposure hazards.)
62  */
63 PGconn *
64 connectDatabase(const char *dbname, const char *pghost,
65  const char *pgport, const char *pguser,
66  enum trivalue prompt_password, const char *progname,
67  bool echo, bool fail_ok, bool allow_password_reuse)
68 {
69  PGconn *conn;
70  bool new_pass;
71  static bool have_password = false;
72  static char password[100];
73 
74  if (!allow_password_reuse)
75  have_password = false;
76 
77  if (!have_password && prompt_password == TRI_YES)
78  {
79  simple_prompt("Password: ", password, sizeof(password), false);
80  have_password = true;
81  }
82 
83  /*
84  * Start the connection. Loop until we have a password if requested by
85  * backend.
86  */
87  do
88  {
89  const char *keywords[7];
90  const char *values[7];
91 
92  keywords[0] = "host";
93  values[0] = pghost;
94  keywords[1] = "port";
95  values[1] = pgport;
96  keywords[2] = "user";
97  values[2] = pguser;
98  keywords[3] = "password";
99  values[3] = have_password ? password : NULL;
100  keywords[4] = "dbname";
101  values[4] = dbname;
102  keywords[5] = "fallback_application_name";
103  values[5] = progname;
104  keywords[6] = NULL;
105  values[6] = NULL;
106 
107  new_pass = false;
108  conn = PQconnectdbParams(keywords, values, true);
109 
110  if (!conn)
111  {
112  pg_log_error("could not connect to database %s: out of memory",
113  dbname);
114  exit(1);
115  }
116 
117  /*
118  * No luck? Trying asking (again) for a password.
119  */
120  if (PQstatus(conn) == CONNECTION_BAD &&
122  prompt_password != TRI_NO)
123  {
124  PQfinish(conn);
125  simple_prompt("Password: ", password, sizeof(password), false);
126  have_password = true;
127  new_pass = true;
128  }
129  } while (new_pass);
130 
131  /* check to see that the backend connection was successfully made */
132  if (PQstatus(conn) == CONNECTION_BAD)
133  {
134  if (fail_ok)
135  {
136  PQfinish(conn);
137  return NULL;
138  }
139  pg_log_error("could not connect to database %s: %s",
140  dbname, PQerrorMessage(conn));
141  exit(1);
142  }
143 
145 
146  return conn;
147 }
148 
149 /*
150  * Try to connect to the appropriate maintenance database.
151  */
152 PGconn *
153 connectMaintenanceDatabase(const char *maintenance_db,
154  const char *pghost, const char *pgport,
155  const char *pguser, enum trivalue prompt_password,
156  const char *progname, bool echo)
157 {
158  PGconn *conn;
159 
160  /* If a maintenance database name was specified, just connect to it. */
161  if (maintenance_db)
162  return connectDatabase(maintenance_db, pghost, pgport, pguser,
163  prompt_password, progname, echo, false, false);
164 
165  /* Otherwise, try postgres first and then template1. */
166  conn = connectDatabase("postgres", pghost, pgport, pguser, prompt_password,
167  progname, echo, true, false);
168  if (!conn)
169  conn = connectDatabase("template1", pghost, pgport, pguser,
170  prompt_password, progname, echo, false, false);
171 
172  return conn;
173 }
174 
175 /*
176  * Disconnect the given connection, canceling any statement if one is active.
177  */
178 void
180 {
181  char errbuf[256];
182 
183  Assert(conn != NULL);
184 
185  if (PQtransactionStatus(conn) == PQTRANS_ACTIVE)
186  {
187  PGcancel *cancel;
188 
189  if ((cancel = PQgetCancel(conn)))
190  {
191  (void) PQcancel(cancel, errbuf, sizeof(errbuf));
192  PQfreeCancel(cancel);
193  }
194  }
195 
196  PQfinish(conn);
197 }
198 
199 /*
200  * Run a query, return the results, exit program on failure.
201  */
202 PGresult *
203 executeQuery(PGconn *conn, const char *query, bool echo)
204 {
205  PGresult *res;
206 
207  if (echo)
208  printf("%s\n", query);
209 
210  res = PQexec(conn, query);
211  if (!res ||
213  {
214  pg_log_error("query failed: %s", PQerrorMessage(conn));
215  pg_log_info("query was: %s", query);
216  PQfinish(conn);
217  exit(1);
218  }
219 
220  return res;
221 }
222 
223 
224 /*
225  * As above for a SQL command (which returns nothing).
226  */
227 void
228 executeCommand(PGconn *conn, const char *query, bool echo)
229 {
230  PGresult *res;
231 
232  if (echo)
233  printf("%s\n", query);
234 
235  res = PQexec(conn, query);
236  if (!res ||
238  {
239  pg_log_error("query failed: %s", PQerrorMessage(conn));
240  pg_log_info("query was: %s", query);
241  PQfinish(conn);
242  exit(1);
243  }
244 
245  PQclear(res);
246 }
247 
248 
249 /*
250  * As above for a SQL maintenance command (returns command success).
251  * Command is executed with a cancel handler set, so Ctrl-C can
252  * interrupt it.
253  */
254 bool
255 executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
256 {
257  PGresult *res;
258  bool r;
259 
260  if (echo)
261  printf("%s\n", query);
262 
263  SetCancelConn(conn);
264  res = PQexec(conn, query);
265  ResetCancelConn();
266 
267  r = (res && PQresultStatus(res) == PGRES_COMMAND_OK);
268 
269  if (res)
270  PQclear(res);
271 
272  return r;
273 }
274 
275 /*
276  * Consume all the results generated for the given connection until
277  * nothing remains. If at least one error is encountered, return false.
278  * Note that this will block if the connection is busy.
279  */
280 bool
282 {
283  bool ok = true;
284  PGresult *result;
285 
286  SetCancelConn(conn);
287  while ((result = PQgetResult(conn)) != NULL)
288  {
289  if (!processQueryResult(conn, result))
290  ok = false;
291  }
292  ResetCancelConn();
293  return ok;
294 }
295 
296 /*
297  * Process (and delete) a query result. Returns true if there's no error,
298  * false otherwise -- but errors about trying to work on a missing relation
299  * are reported and subsequently ignored.
300  */
301 bool
303 {
304  /*
305  * If it's an error, report it. Errors about a missing table are harmless
306  * so we continue processing; but die for other errors.
307  */
308  if (PQresultStatus(result) != PGRES_COMMAND_OK)
309  {
310  char *sqlState = PQresultErrorField(result, PG_DIAG_SQLSTATE);
311 
312  pg_log_error("processing of database \"%s\" failed: %s",
313  PQdb(conn), PQerrorMessage(conn));
314 
315  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) != 0)
316  {
317  PQclear(result);
318  return false;
319  }
320  }
321 
322  PQclear(result);
323  return true;
324 }
325 
326 
327 /*
328  * Split TABLE[(COLUMNS)] into TABLE and [(COLUMNS)] portions. When you
329  * finish using them, pg_free(*table). *columns is a pointer into "spec",
330  * possibly to its NUL terminator.
331  */
332 void
333 splitTableColumnsSpec(const char *spec, int encoding,
334  char **table, const char **columns)
335 {
336  bool inquotes = false;
337  const char *cp = spec;
338 
339  /*
340  * Find the first '(' not identifier-quoted. Based on
341  * dequote_downcase_identifier().
342  */
343  while (*cp && (*cp != '(' || inquotes))
344  {
345  if (*cp == '"')
346  {
347  if (inquotes && cp[1] == '"')
348  cp++; /* pair does not affect quoting */
349  else
350  inquotes = !inquotes;
351  cp++;
352  }
353  else
354  cp += PQmblen(cp, encoding);
355  }
356  *table = pnstrdup(spec, cp - spec);
357  *columns = cp;
358 }
359 
360 /*
361  * Break apart TABLE[(COLUMNS)] of "spec". With the reset_val of search_path
362  * in effect, have regclassin() interpret the TABLE portion. Append to "buf"
363  * the qualified name of TABLE, followed by any (COLUMNS). Exit on failure.
364  * We use this to interpret --table=foo under the search path psql would get,
365  * in advance of "ANALYZE public.foo" under the always-secure search path.
366  */
367 void
369  PGconn *conn, bool echo)
370 {
371  char *table;
372  const char *columns;
373  PQExpBufferData sql;
374  PGresult *res;
375  int ntups;
376 
377  splitTableColumnsSpec(spec, PQclientEncoding(conn), &table, &columns);
378 
379  /*
380  * Query must remain ABSOLUTELY devoid of unqualified names. This would
381  * be unnecessary given a regclassin() variant taking a search_path
382  * argument.
383  */
384  initPQExpBuffer(&sql);
386  "SELECT c.relname, ns.nspname\n"
387  " FROM pg_catalog.pg_class c,"
388  " pg_catalog.pg_namespace ns\n"
389  " WHERE c.relnamespace OPERATOR(pg_catalog.=) ns.oid\n"
390  " AND c.oid OPERATOR(pg_catalog.=) ");
391  appendStringLiteralConn(&sql, table, conn);
392  appendPQExpBufferStr(&sql, "::pg_catalog.regclass;");
393 
394  executeCommand(conn, "RESET search_path;", echo);
395 
396  /*
397  * One row is a typical result, as is a nonexistent relation ERROR.
398  * regclassin() unconditionally accepts all-digits input as an OID; if no
399  * relation has that OID; this query returns no rows. Catalog corruption
400  * might elicit other row counts.
401  */
402  res = executeQuery(conn, sql.data, echo);
403  ntups = PQntuples(res);
404  if (ntups != 1)
405  {
406  pg_log_error(ngettext("query returned %d row instead of one: %s",
407  "query returned %d rows instead of one: %s",
408  ntups),
409  ntups, sql.data);
410  PQfinish(conn);
411  exit(1);
412  }
414  fmtQualifiedId(PQgetvalue(res, 0, 1),
415  PQgetvalue(res, 0, 0)));
416  appendPQExpBufferStr(buf, columns);
417  PQclear(res);
418  termPQExpBuffer(&sql);
419  pg_free(table);
420 
422 }
423 
424 
425 /*
426  * Check yes/no answer in a localized way. 1=yes, 0=no, -1=neither.
427  */
428 
429 /* translator: abbreviation for "yes" */
430 #define PG_YESLETTER gettext_noop("y")
431 /* translator: abbreviation for "no" */
432 #define PG_NOLETTER gettext_noop("n")
433 
434 bool
435 yesno_prompt(const char *question)
436 {
437  char prompt[256];
438 
439  /*------
440  translator: This is a question followed by the translated options for
441  "yes" and "no". */
442  snprintf(prompt, sizeof(prompt), _("%s (%s/%s) "),
443  _(question), _(PG_YESLETTER), _(PG_NOLETTER));
444 
445  for (;;)
446  {
447  char resp[10];
448 
449  simple_prompt(prompt, resp, sizeof(resp), true);
450 
451  if (strcmp(resp, _(PG_YESLETTER)) == 0)
452  return true;
453  if (strcmp(resp, _(PG_NOLETTER)) == 0)
454  return false;
455 
456  printf(_("Please answer \"%s\" or \"%s\".\n"),
458  }
459 }
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:153
static char password[100]
Definition: streamutil.c:53
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6631
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1197
#define PG_YESLETTER
Definition: common.c:430
bool yesno_prompt(const char *question)
Definition: common.c:435
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3163
PGresult * executeQuery(PGconn *conn, const char *query, bool echo)
Definition: common.c:203
void executeCommand(PGconn *conn, const char *query, bool echo)
Definition: common.c:228
bool processQueryResult(PGconn *conn, PGresult *result)
Definition: common.c:302
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 ResetCancelConn(void)
Definition: cancel.c:89
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
void PQfreeCancel(PGcancel *cancel)
Definition: fe-connect.c:4269
bool consumeQueryResult(PGconn *conn)
Definition: common.c:281
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4125
#define printf(...)
Definition: port.h:198
#define PG_NOLETTER
Definition: common.c:432
const char * progname
Definition: pg_standby.c:36
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2769
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
int PQclientEncoding(const PGconn *conn)
Definition: fe-connect.c:6691
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:624
PGconn * conn
Definition: streamutil.c:54
static char * buf
Definition: pg_test_fsync.c:67
bool executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
Definition: common.c:255
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:4246
void SetCancelConn(PGconn *conn)
Definition: cancel.c:59
void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
Definition: common.c:33
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:6586
char * pghost
Definition: pgbench.c:243
trivalue
Definition: vacuumlo.c:33
#define ngettext(s, p, n)
Definition: c.h:1134
void disconnectDatabase(PGconn *conn)
Definition: common.c:179
#define ERRCODE_UNDEFINED_TABLE
Definition: common.c:26
void PQclear(PGresult *res)
Definition: fe-exec.c:694
void(* help_handler)(const char *progname)
Definition: common.h:24
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6473
static bool have_password
Definition: streamutil.c:52
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:2754
#define Assert(condition)
Definition: c.h:739
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:64
char * dbname
Definition: streamutil.c:50
const char * fmtQualifiedId(const char *schema, const char *id)
Definition: string_utils.c:145
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:368
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
Definition: fe-connect.c:4401
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
Definition: string_utils.c:293
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6665
void splitTableColumnsSpec(const char *spec, int encoding, char **table, const char **columns)
Definition: common.c:333
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1939
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6578
int PQmblen(const char *s, int encoding)
Definition: fe-misc.c:1216
#define snprintf
Definition: port.h:192
#define _(x)
Definition: elog.c:87
char * pgport
Definition: pgbench.c:244
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:1778
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
#define pg_log_info(...)
Definition: logging.h:87