2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2003, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.79 2004/01/09 21:12:20 momjian Exp $
8 #include "postgres_fe.h"
18 #include <unistd.h> /* for write() */
21 #include <io.h> /* for _write() */
23 #include <sys/timeb.h> /* for _ftime() */
30 #include "variables.h"
36 #include "mb/pg_wchar.h"
39 /* Workarounds for Windows */
40 /* Probably to be moved up the source tree in the future, perhaps to be replaced by
41 * more specific checks like configure-style HAVE_GETTIMEOFDAY macros.
45 typedef struct timeval TimevalStruct;
47 #define GETTIMEOFDAY(T) gettimeofday(T, NULL)
48 #define DIFF_MSEC(T, U) \
49 ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
50 ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
54 typedef struct _timeb TimevalStruct;
56 #define GETTIMEOFDAY(T) _ftime(T)
57 #define DIFF_MSEC(T, U) \
58 (((T)->time - (U)->time) * 1000.0 + \
59 ((T)->millitm - (U)->millitm))
63 extern bool prompt_state;
66 static bool is_transact_command(const char *query);
70 * "Safe" wrapper around strdup()
73 xstrdup(const char *string)
79 fprintf(stderr, gettext("%s: xstrdup: cannot duplicate null pointer (internal error)\n"),
86 psql_error("out of memory\n");
96 * -- handler for -o command line option and \o command
98 * Tries to open file fname (or pipe if fname starts with '|')
99 * and stores the file handle in pset)
100 * Upon failure, sets stdout and returns false.
103 setQFout(const char *fname)
107 /* Close old file/pipe */
108 if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
110 if (pset.queryFoutPipe)
111 pclose(pset.queryFout);
113 fclose(pset.queryFout);
116 /* If no filename, set stdout */
117 if (!fname || fname[0] == '\0')
119 pset.queryFout = stdout;
120 pset.queryFoutPipe = false;
122 else if (*fname == '|')
124 pset.queryFout = popen(fname + 1, "w");
125 pset.queryFoutPipe = true;
129 pset.queryFout = fopen(fname, "w");
130 pset.queryFoutPipe = false;
133 if (!(pset.queryFout))
135 psql_error("%s: %s\n", fname, strerror(errno));
136 pset.queryFout = stdout;
137 pset.queryFoutPipe = false;
143 pqsignal(SIGPIPE, pset.queryFoutPipe ? SIG_IGN : SIG_DFL);
152 * Error reporting for scripts. Errors should look like
153 * psql:filename:lineno: message
157 psql_error(const char *fmt,...)
162 if (pset.queryFout != stdout)
163 fflush(pset.queryFout);
166 fprintf(stderr, "%s:%s:%u: ", pset.progname, pset.inputfile, pset.lineno);
168 vfprintf(stderr, gettext(fmt), ap);
175 * for backend Notice messages (INFO, WARNING, etc)
178 NoticeProcessor(void *arg, const char *message)
180 (void) arg; /* not used */
181 psql_error("%s", message);
187 * Code to support query cancellation
189 * Before we start a query, we enable a SIGINT signal catcher that sends a
190 * cancel request to the backend. Note that sending the cancel directly from
191 * the signal handler is safe because PQrequestCancel() is written to make it
192 * so. We use write() to print to stdout because it's better to use simple
193 * facilities in a signal handler.
195 static PGconn *volatile cancelConn = NULL;
197 volatile bool cancel_pressed = false;
202 #define write_stderr(String) write(fileno(stderr), String, strlen(String))
205 handle_sigint(SIGNAL_ARGS)
207 int save_errno = errno;
209 /* Don't muck around if prompting for a password. */
213 if (cancelConn == NULL)
214 siglongjmp(main_loop_jmp, 1);
216 cancel_pressed = true;
218 if (PQrequestCancel(cancelConn))
219 write_stderr("Cancel request sent\n");
222 write_stderr("Could not send cancel request: ");
223 write_stderr(PQerrorMessage(cancelConn));
225 errno = save_errno; /* just in case the write changed it */
227 #endif /* not WIN32 */
233 * Returns whether our backend connection is still there.
238 return PQstatus(pset.db) != CONNECTION_BAD;
245 * Verify that we still have a good connection to the backend, and if not,
246 * see if it can be restored.
248 * Returns true if either the connection was still there, or it could be
249 * restored successfully; false otherwise. If, however, there was no
250 * connection and the session is non-interactive, this will exit the program
251 * with a code of EXIT_BADCONN.
254 CheckConnection(void)
261 if (!pset.cur_cmd_interactive)
263 psql_error("connection to server was lost\n");
267 fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr);
272 fputs(gettext("Failed.\n"), stderr);
279 fputs(gettext("Succeeded.\n"), stderr);
290 * Set cancelConn to point to the current database connection.
295 cancelConn = pset.db;
302 * Set cancelConn to NULL. I don't know what this means exactly, but it saves
303 * having to export the variable.
306 ResetCancelConn(void)
315 * Checks whether a result is valid, giving an error message if necessary;
316 * resets cancelConn as needed, and ensures that the connection to the backend
319 * Returns true for valid result, false for error state.
322 AcceptResult(const PGresult *result)
331 switch (PQresultStatus(result))
333 case PGRES_COMMAND_OK:
334 case PGRES_TUPLES_OK:
335 case PGRES_EMPTY_QUERY:
337 /* Fine, do nothing */
341 /* keep cancel connection for copy out state */
352 psql_error("%s", PQerrorMessage(pset.db));
364 * This is the way to send "backdoor" queries (those not directly entered
365 * by the user). It is subject to -E but not -e.
367 * In autocommit-off mode, a new transaction block is started if start_xact
368 * is true; nothing special is done when start_xact is false. Typically,
369 * start_xact = false is used for SELECTs and explicit BEGIN/COMMIT commands.
371 * Note: we don't bother to check PQclientEncoding; it is assumed that no
372 * caller uses this path to issue "SET CLIENT_ENCODING".
375 PSQLexec(const char *query, bool start_xact)
382 psql_error("You are currently not connected to a database.\n");
386 echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
387 if (echo_hidden != VAR_NOTSET)
389 printf("********* QUERY **********\n"
391 "**************************\n\n", query);
394 if (echo_hidden == 1) /* noexec? */
400 if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
401 !GetVariableBool(pset.vars, "AUTOCOMMIT"))
403 res = PQexec(pset.db, "BEGIN");
404 if (PQresultStatus(res) != PGRES_COMMAND_OK)
406 psql_error("%s", PQerrorMessage(pset.db));
414 res = PQexec(pset.db, query);
416 if (!AcceptResult(res) && res)
428 * PrintNotifications: check for asynchronous notifications, and print them out
431 PrintNotifications(void)
435 while ((notify = PQnotifies(pset.db)))
437 fprintf(pset.queryFout, gettext("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
438 notify->relname, notify->be_pid);
439 fflush(pset.queryFout);
446 * PrintQueryTuples: assuming query result is OK, print its tuples
448 * Returns true if successful, false otherwise.
451 PrintQueryTuples(const PGresult *results)
453 /* write output to \g argument, if any */
456 FILE *queryFout_copy = pset.queryFout;
457 bool queryFoutPipe_copy = pset.queryFoutPipe;
459 pset.queryFout = stdout; /* so it doesn't get closed */
462 if (!setQFout(pset.gfname))
464 pset.queryFout = queryFout_copy;
465 pset.queryFoutPipe = queryFoutPipe_copy;
469 printQuery(results, &pset.popt, pset.queryFout);
471 /* close file/pipe, restore old setting */
474 pset.queryFout = queryFout_copy;
475 pset.queryFoutPipe = queryFoutPipe_copy;
481 printQuery(results, &pset.popt, pset.queryFout);
488 * ProcessCopyResult: if command was a COPY FROM STDIN/TO STDOUT, handle it
490 * Note: Utility function for use by SendQuery() only.
492 * Returns true if the query executed successfully, false otherwise.
495 ProcessCopyResult(PGresult *results)
497 bool success = false;
502 switch (PQresultStatus(results))
504 case PGRES_TUPLES_OK:
505 case PGRES_COMMAND_OK:
506 case PGRES_EMPTY_QUERY:
507 /* nothing to do here */
512 success = handleCopyOut(pset.db, pset.queryFout);
516 if (pset.cur_cmd_interactive && !QUIET())
517 puts(gettext("Enter data to be copied followed by a newline.\n"
518 "End with a backslash and a period on a line by itself."));
520 success = handleCopyIn(pset.db, pset.cur_cmd_source,
521 pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL);
528 /* may need this to recover from conn loss during COPY */
529 if (!CheckConnection())
537 * PrintQueryResults: print out query results as required
539 * Note: Utility function for use by SendQuery() only.
541 * Returns true if the query executed successfully, false otherwise.
544 PrintQueryResults(PGresult *results)
546 bool success = false;
551 switch (PQresultStatus(results))
553 case PGRES_TUPLES_OK:
554 success = PrintQueryTuples(results);
557 case PGRES_COMMAND_OK:
562 sprintf(buf, "%u", (unsigned int) PQoidValue(results));
565 if (pset.popt.topt.format == PRINT_HTML)
567 fputs("<p>", pset.queryFout);
568 html_escaped_print(PQcmdStatus(results),
570 fputs("</p>\n", pset.queryFout);
573 fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
575 SetVariable(pset.vars, "LASTOID", buf);
579 case PGRES_EMPTY_QUERY:
585 /* nothing to do here */
593 fflush(pset.queryFout);
600 * SendQuery: send the query string to the backend
601 * (and print out results)
603 * Note: This is the "front door" way to send a query. That is, use it to
604 * send queries actually entered by the user. These queries will be subject to
606 * To send "back door" queries (generated by slash commands, etc.) in a
607 * controlled way, use PSQLexec().
609 * Returns true if the query executed successfully, false otherwise.
612 SendQuery(const char *query)
615 TimevalStruct before,
621 psql_error("You are currently not connected to a database.\n");
625 if (GetVariableBool(pset.vars, "SINGLESTEP"))
629 printf(gettext("***(Single step mode: verify command)*******************************************\n"
631 "***(press return to proceed or enter x and return to cancel)********************\n"),
634 if (fgets(buf, sizeof(buf), stdin) != NULL)
638 else if (VariableEquals(pset.vars, "ECHO", "queries"))
646 if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
647 !GetVariableBool(pset.vars, "AUTOCOMMIT") &&
648 !is_transact_command(query))
650 results = PQexec(pset.db, "BEGIN");
651 if (PQresultStatus(results) != PGRES_COMMAND_OK)
653 psql_error("%s", PQerrorMessage(pset.db));
662 GETTIMEOFDAY(&before);
664 results = PQexec(pset.db, query);
666 /* these operations are included in the timing result: */
667 OK = (AcceptResult(results) && ProcessCopyResult(results));
670 GETTIMEOFDAY(&after);
672 /* but printing results isn't: */
674 OK = PrintQueryResults(results);
678 /* Possible microtiming output */
679 if (OK && pset.timing)
680 printf(gettext("Time: %.3f ms\n"), DIFF_MSEC(&after, &before));
682 /* check for events that may occur during query execution */
684 if (pset.encoding != PQclientEncoding(pset.db) &&
685 PQclientEncoding(pset.db) >= 0)
687 /* track effects of SET CLIENT_ENCODING */
688 pset.encoding = PQclientEncoding(pset.db);
689 pset.popt.topt.encoding = pset.encoding;
690 SetVariable(pset.vars, "ENCODING",
691 pg_encoding_to_char(pset.encoding));
694 PrintNotifications();
700 * check whether a query string begins with BEGIN/COMMIT/ROLLBACK/START XACT
703 is_transact_command(const char *query)
708 * First we must advance over any whitespace and comments.
712 if (isspace((unsigned char) *query))
714 else if (query[0] == '-' && query[1] == '-')
717 while (*query && *query != '\n')
720 else if (query[0] == '/' && query[1] == '*')
725 if (query[0] == '*' && query[1] == '/')
735 break; /* found first token */
739 * Check word length ("beginx" is not "begin").
742 while (isalpha((unsigned char) query[wordlen]))
745 if (wordlen == 5 && strncasecmp(query, "begin", 5) == 0)
747 if (wordlen == 6 && strncasecmp(query, "commit", 6) == 0)
749 if (wordlen == 8 && strncasecmp(query, "rollback", 8) == 0)
751 if (wordlen == 5 && strncasecmp(query, "abort", 5) == 0)
753 if (wordlen == 3 && strncasecmp(query, "end", 3) == 0)
755 if (wordlen == 5 && strncasecmp(query, "start", 5) == 0)
763 parse_char(char **buf)
767 l = strtol(*buf, buf, 0);
774 * Test if the current user is a database superuser.
776 * Note: this will correctly detect superuserness only with a protocol-3.0
777 * or newer backend; otherwise it will always say "false".
787 val = PQparameterStatus(pset.db, "is_superuser");
789 if (val && strcmp(val, "on") == 0)
797 * Return the session user of the current connection.
799 * Note: this will correctly detect the session user only with a
800 * protocol-3.0 or newer backend; otherwise it will return the
804 session_username(void)
811 val = PQparameterStatus(pset.db, "session_authorization");
815 return PQuser(pset.db);
821 * substitute '~' with HOME or '~username' with username's home dir
825 expand_tilde(char **filename)
827 if (!filename || !(*filename))
830 /* MSDOS uses tilde for short versions of long file names, so skip it. */
833 /* try tilde expansion */
834 if (**filename == '~')
846 while (*p != '/' && *p != '\0')
852 if (*(fn + 1) == '\0')
853 home = getenv("HOME");
854 else if ((pw = getpwnam(fn + 1)) != NULL)
862 newfn = malloc(strlen(home) + strlen(p) + 1);
865 psql_error("out of memory\n");