1 /*-------------------------------------------------------------------------
4 * Common support routines for bin/scripts/
7 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/bin/scripts/common.c
12 *-------------------------------------------------------------------------
15 #include "postgres_fe.h"
23 static PGcancel *volatile cancelConn = NULL;
24 bool CancelRequested = false;
27 static CRITICAL_SECTION cancelConnLock;
31 * Provide strictly harmonized handling of --help and --version
35 handle_help_version_opts(int argc, char *argv[],
36 const char *fixed_progname, help_handler hlp)
40 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
42 hlp(get_progname(argv[0]));
45 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
47 printf("%s (PostgreSQL) " PG_VERSION "\n", fixed_progname);
55 * Make a database connection with the given parameters.
57 * An interactive password prompt is automatically issued if needed and
58 * allowed by prompt_password.
60 * If allow_password_reuse is true, we will try to re-use any password
61 * given during previous calls to this routine. (Callers should not pass
62 * allow_password_reuse=true unless reconnecting to the same database+user
63 * as before, else we might create password exposure hazards.)
66 connectDatabase(const char *dbname, const char *pghost, const char *pgport,
67 const char *pguser, enum trivalue prompt_password,
68 const char *progname, bool fail_ok, bool allow_password_reuse)
72 static bool have_password = false;
73 static char password[100];
75 if (!allow_password_reuse)
76 have_password = false;
78 if (!have_password && prompt_password == TRI_YES)
80 simple_prompt("Password: ", password, sizeof(password), false);
85 * Start the connection. Loop until we have a password if requested by
90 const char *keywords[7];
91 const char *values[7];
99 keywords[3] = "password";
100 values[3] = have_password ? password : NULL;
101 keywords[4] = "dbname";
103 keywords[5] = "fallback_application_name";
104 values[5] = progname;
109 conn = PQconnectdbParams(keywords, values, true);
113 fprintf(stderr, _("%s: could not connect to database %s: out of memory\n"),
119 * No luck? Trying asking (again) for a password.
121 if (PQstatus(conn) == CONNECTION_BAD &&
122 PQconnectionNeedsPassword(conn) &&
123 prompt_password != TRI_NO)
126 simple_prompt("Password: ", password, sizeof(password), false);
127 have_password = true;
132 /* check to see that the backend connection was successfully made */
133 if (PQstatus(conn) == CONNECTION_BAD)
140 fprintf(stderr, _("%s: could not connect to database %s: %s"),
141 progname, dbname, PQerrorMessage(conn));
149 * Try to connect to the appropriate maintenance database.
152 connectMaintenanceDatabase(const char *maintenance_db, const char *pghost,
153 const char *pgport, const char *pguser,
154 enum trivalue prompt_password,
155 const char *progname)
159 /* If a maintenance database name was specified, just connect to it. */
161 return connectDatabase(maintenance_db, pghost, pgport, pguser,
162 prompt_password, progname, false, false);
164 /* Otherwise, try postgres first and then template1. */
165 conn = connectDatabase("postgres", pghost, pgport, pguser, prompt_password,
166 progname, true, false);
168 conn = connectDatabase("template1", pghost, pgport, pguser,
169 prompt_password, progname, false, false);
175 * Run a query, return the results, exit program on failure.
178 executeQuery(PGconn *conn, const char *query, const char *progname, bool echo)
183 printf("%s\n", query);
185 res = PQexec(conn, query);
187 PQresultStatus(res) != PGRES_TUPLES_OK)
189 fprintf(stderr, _("%s: query failed: %s"),
190 progname, PQerrorMessage(conn));
191 fprintf(stderr, _("%s: query was: %s\n"),
202 * As above for a SQL command (which returns nothing).
205 executeCommand(PGconn *conn, const char *query,
206 const char *progname, bool echo)
211 printf("%s\n", query);
213 res = PQexec(conn, query);
215 PQresultStatus(res) != PGRES_COMMAND_OK)
217 fprintf(stderr, _("%s: query failed: %s"),
218 progname, PQerrorMessage(conn));
219 fprintf(stderr, _("%s: query was: %s\n"),
230 * As above for a SQL maintenance command (returns command success).
231 * Command is executed with a cancel handler set, so Ctrl-C can
235 executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
241 printf("%s\n", query);
244 res = PQexec(conn, query);
247 r = (res && PQresultStatus(res) == PGRES_COMMAND_OK);
256 * Check yes/no answer in a localized way. 1=yes, 0=no, -1=neither.
259 /* translator: abbreviation for "yes" */
260 #define PG_YESLETTER gettext_noop("y")
261 /* translator: abbreviation for "no" */
262 #define PG_NOLETTER gettext_noop("n")
265 yesno_prompt(const char *question)
270 translator: This is a question followed by the translated options for
272 snprintf(prompt, sizeof(prompt), _("%s (%s/%s) "),
273 _(question), _(PG_YESLETTER), _(PG_NOLETTER));
279 simple_prompt(prompt, resp, sizeof(resp), true);
281 if (strcmp(resp, _(PG_YESLETTER)) == 0)
283 if (strcmp(resp, _(PG_NOLETTER)) == 0)
286 printf(_("Please answer \"%s\" or \"%s\".\n"),
287 _(PG_YESLETTER), _(PG_NOLETTER));
294 * Set cancelConn to point to the current database connection.
297 SetCancelConn(PGconn *conn)
299 PGcancel *oldCancelConn;
302 EnterCriticalSection(&cancelConnLock);
305 /* Free the old one if we have one */
306 oldCancelConn = cancelConn;
308 /* be sure handle_sigint doesn't use pointer while freeing */
311 if (oldCancelConn != NULL)
312 PQfreeCancel(oldCancelConn);
314 cancelConn = PQgetCancel(conn);
317 LeaveCriticalSection(&cancelConnLock);
324 * Free the current cancel connection, if any, and set to NULL.
327 ResetCancelConn(void)
329 PGcancel *oldCancelConn;
332 EnterCriticalSection(&cancelConnLock);
335 oldCancelConn = cancelConn;
337 /* be sure handle_sigint doesn't use pointer while freeing */
340 if (oldCancelConn != NULL)
341 PQfreeCancel(oldCancelConn);
344 LeaveCriticalSection(&cancelConnLock);
350 * Handle interrupt signals by canceling the current command, if a cancelConn
354 handle_sigint(SIGNAL_ARGS)
356 int save_errno = errno;
359 /* Send QueryCancel if we are processing a database query */
360 if (cancelConn != NULL)
362 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
364 CancelRequested = true;
365 fprintf(stderr, _("Cancel request sent\n"));
368 fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
371 CancelRequested = true;
373 errno = save_errno; /* just in case the write changed it */
377 setup_cancel_handler(void)
379 pqsignal(SIGINT, handle_sigint);
384 * Console control handler for Win32. Note that the control handler will
385 * execute on a *different thread* than the main one, so we need to do
386 * proper locking around those structures.
389 consoleHandler(DWORD dwCtrlType)
393 if (dwCtrlType == CTRL_C_EVENT ||
394 dwCtrlType == CTRL_BREAK_EVENT)
396 /* Send QueryCancel if we are processing a database query */
397 EnterCriticalSection(&cancelConnLock);
398 if (cancelConn != NULL)
400 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
402 fprintf(stderr, _("Cancel request sent\n"));
403 CancelRequested = true;
406 fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
409 CancelRequested = true;
411 LeaveCriticalSection(&cancelConnLock);
416 /* Return FALSE for any signals not being handled */
421 setup_cancel_handler(void)
423 InitializeCriticalSection(&cancelConnLock);
425 SetConsoleCtrlHandler(consoleHandler, TRUE);