17 #include <unistd.h> /* for write() */
19 #include <io.h> /* for _write() */
23 #include <postgres_ext.h>
28 #include "variables.h"
34 #define popen(x,y) _popen(x,y)
35 #define pclose(x) _pclose(x)
36 #define write(a,b,c) _write(a,b,c)
43 * "Safe" wrapper around strdup()
44 * (Using this also avoids writing #ifdef HAVE_STRDUP in every file :)
47 xstrdup(const char *string)
53 fprintf(stderr, "xstrdup: Cannot duplicate null pointer.\n");
69 * -- handler for -o command line option and \o command
71 * Tries to open file fname (or pipe if fname starts with '|')
72 * and stores the file handle in pset)
73 * Upon failure, sets stdout and returns false.
76 setQFout(const char *fname, PsqlSettings *pset)
80 #ifdef USE_ASSERT_CHECKING
87 /* Close old file/pipe */
88 if (pset->queryFout && pset->queryFout != stdout && pset->queryFout != stderr)
90 if (pset->queryFoutPipe)
91 pclose(pset->queryFout);
93 fclose(pset->queryFout);
96 /* If no filename, set stdout */
97 if (!fname || fname[0] == '\0')
99 pset->queryFout = stdout;
100 pset->queryFoutPipe = false;
102 else if (*fname == '|')
104 const char *pipename = fname + 1;
108 pset->queryFout = popen(pipename, "w");
110 pset->queryFout = popen(pipename, "wb");
112 pset->queryFoutPipe = true;
117 pset->queryFout = fopen(fname, "w");
119 pset->queryFout = fopen(fname, "wb");
121 pset->queryFoutPipe = false;
124 if (!pset->queryFout)
127 pset->queryFout = stdout;
128 pset->queryFoutPipe = false;
133 if (pset->queryFoutPipe)
134 pqsignal(SIGPIPE, SIG_IGN);
136 pqsignal(SIGPIPE, SIG_DFL);
146 * Generalized function especially intended for reading in usernames and
147 * password interactively. Reads from stdin.
149 * prompt: The prompt to print
150 * maxlen: How many characters to accept
151 * echo: Set to false if you want to hide what is entered (for passwords)
153 * Returns a malloc()'ed string with the input (w/o trailing newline).
156 simple_prompt(const char *prompt, int maxlen, bool echo)
161 #ifdef HAVE_TERMIOS_H
162 struct termios t_orig,
167 destination = (char *) malloc(maxlen + 2);
171 fputs(prompt, stdout);
173 #ifdef HAVE_TERMIOS_H
179 tcsetattr(0, TCSADRAIN, &t);
183 fgets(destination, maxlen, stdin);
185 #ifdef HAVE_TERMIOS_H
188 tcsetattr(0, TCSADRAIN, &t_orig);
193 length = strlen(destination);
194 if (length > 0 && destination[length - 1] != '\n')
196 /* eat rest of the line */
201 fgets(buf, 512, stdin);
202 } while (buf[strlen(buf) - 1] != '\n');
205 if (length > 0 && destination[length - 1] == '\n')
206 /* remove trailing newline */
207 destination[length - 1] = '\0';
217 * The idea here is that certain variables have a "magic" meaning, such as
218 * LastOid. However, you can assign to those variables, but that will shadow
219 * the magic meaning, until you unset it. If nothing matches, the value of
220 * the environment variable is used.
222 * This function only returns NULL if you feed in NULL's (don't do that).
223 * Otherwise, the return value is ready for immediate consumption.
226 interpolate_var(const char *name, PsqlSettings *pset)
230 #ifdef USE_ASSERT_CHECKING
238 var = GetVariable(pset->vars, name);
242 /* otherwise return magic variable */
245 * (by convention these should be capitalized (but not all caps), to
246 * not be shadowed by regular vars or to shadow env vars)
248 if (strcmp(name, "Version") == 0)
249 return PG_VERSION_STR;
251 if (strcmp(name, "Database") == 0)
254 return PQdb(pset->db);
259 if (strcmp(name, "User") == 0)
261 if (PQuser(pset->db))
262 return PQuser(pset->db);
267 if (strcmp(name, "Host") == 0)
269 if (PQhost(pset->db))
270 return PQhost(pset->db);
275 if (strcmp(name, "Port") == 0)
277 if (PQport(pset->db))
278 return PQport(pset->db);
283 if (strcmp(name, "LastOid") == 0)
286 if (pset->lastOid == InvalidOid)
288 sprintf(buf, "%u", pset->lastOid);
293 if ((var = getenv(name)))
302 * Code to support query cancellation
304 * Before we start a query, we enable a SIGINT signal catcher that sends a
305 * cancel request to the backend. Note that sending the cancel directly from
306 * the signal handler is safe because PQrequestCancel() is written to make it
307 * so. We have to be very careful what else we do in the signal handler. This
308 * includes using write() for output.
311 static PGconn *cancelConn;
313 #define write_stderr(String) write(fileno(stderr), String, strlen(String))
316 handle_sigint(SIGNAL_ARGS)
318 if (cancelConn == NULL)
320 /* Try to send cancel request */
321 if (PQrequestCancel(cancelConn))
322 write_stderr("\nCancel request sent\n");
325 write_stderr("\nCould not send cancel request: ");
326 write_stderr(PQerrorMessage(cancelConn));
335 * This is the way to send "backdoor" queries (those not directly entered
336 * by the user). It is subject to -E (echo_secret) but not -e (echo).
339 PSQLexec(PsqlSettings *pset, const char *query)
346 fputs("You are currently not connected to a database.\n", stderr);
350 var = GetVariable(pset->vars, "echo_secret");
353 printf("********* QUERY *********\n%s\n*************************\n\n", query);
357 if (var && strcmp(var, "noexec") == 0)
360 cancelConn = pset->db;
361 pqsignal(SIGINT, handle_sigint); /* control-C => cancel */
363 res = PQexec(pset->db, query);
365 pqsignal(SIGINT, SIG_DFL); /* now control-C is back to normal */
367 if (PQstatus(pset->db) == CONNECTION_OK)
369 if (res && (PQresultStatus(res) == PGRES_COMMAND_OK ||
370 PQresultStatus(res) == PGRES_TUPLES_OK ||
371 PQresultStatus(res) == PGRES_COPY_IN ||
372 PQresultStatus(res) == PGRES_COPY_OUT)
374 return res; /* Normal success case... */
375 /* Normal failure case --- display error and return NULL */
376 fputs(PQerrorMessage(pset->db), pset->queryFout);
381 /* Lost connection. Report whatever libpq has to say,
382 * then consider recovery.
384 fputs(PQerrorMessage(pset->db), pset->queryFout);
386 if (!pset->cur_cmd_interactive)
388 fprintf(stderr, "%s: connection to server was lost\n",
392 fputs("The connection to the server was lost. Attempting reset: ", stderr);
395 if (PQstatus(pset->db) == CONNECTION_BAD)
397 fputs("Failed.\n", stderr);
402 fputs("Succeeded.\n", stderr);
409 * SendQuery: send the query string to the backend
410 * (and print out results)
412 * Note: This is the "front door" way to send a query. That is, use it to
413 * send queries actually entered by the user. These queries will be subject to
415 * To send "back door" queries (generated by slash commands, etc.) in a
416 * controlled way, use PSQLexec().
418 * Returns true if the query executed successfully, false otherwise.
421 SendQuery(PsqlSettings *pset, const char *query)
423 bool success = false;
429 fputs("You are currently not connected to a database.\n", stderr);
433 if (GetVariableBool(pset->vars, "singlestep"))
437 printf("***(Single step mode: Verify query)*********************************************\n"
439 "***(press return to proceed or enter x and return to cancel)********************\n",
442 fgets(buf, 3, stdin);
447 cancelConn = pset->db;
448 pqsignal(SIGINT, handle_sigint);
450 results = PQexec(pset->db, query);
452 pqsignal(SIGINT, SIG_DFL);
456 fputs(PQerrorMessage(pset->db), pset->queryFout);
461 switch (PQresultStatus(results))
463 case PGRES_TUPLES_OK:
466 PsqlSettings settings_copy = *pset;
468 settings_copy.queryFout = stdout;
469 if (!setQFout(pset->gfname, &settings_copy))
475 printQuery(results, &settings_copy.popt, settings_copy.queryFout);
477 /* close file/pipe */
478 setQFout(NULL, &settings_copy);
489 printQuery(results, &pset->popt, pset->queryFout);
492 case PGRES_EMPTY_QUERY:
495 case PGRES_COMMAND_OK:
497 pset->lastOid = PQoidValue(results);
498 if (!GetVariableBool(pset->vars, "quiet"))
499 fprintf(pset->queryFout, "%s\n", PQcmdStatus(results));
503 success = handleCopyOut(pset->db, pset->queryFout);
507 if (pset->cur_cmd_interactive && !GetVariable(pset->vars, "quiet"))
508 puts("Enter data to be copied followed by a newline.\n"
509 "End with a backslash and a period on a line by itself.");
511 success = handleCopyIn(pset->db, pset->cur_cmd_source,
512 pset->cur_cmd_interactive ? get_prompt(pset, PROMPT_COPY) : NULL);
515 case PGRES_NONFATAL_ERROR:
516 case PGRES_FATAL_ERROR:
517 case PGRES_BAD_RESPONSE:
519 fputs(PQerrorMessage(pset->db), stderr);
523 fflush(pset->queryFout);
525 if (PQstatus(pset->db) == CONNECTION_BAD)
527 if (!pset->cur_cmd_interactive)
529 fprintf(stderr, "%s: connection to server was lost\n",
533 fputs("The connection to the server was lost. Attempting reset: ", stderr);
536 if (PQstatus(pset->db) == CONNECTION_BAD)
538 fputs("Failed.\n", stderr);
545 fputs("Succeeded.\n", stderr);
548 /* check for asynchronous notification returns */
549 while ((notify = PQnotifies(pset->db)) != NULL)
551 fprintf(pset->queryFout, "Asynchronous NOTIFY '%s' from backend with pid '%d' received.\n",
552 notify->relname, notify->be_pid);
554 fflush(pset->queryFout);