2 * psql - the PostgreSQL interactive terminal
4 * Copyright 2000 by PostgreSQL Global Development Group
6 * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.68 2003/08/04 00:43:29 momjian Exp $
8 #include "postgres_fe.h"
20 #include <unistd.h> /* for write() */
23 #include <io.h> /* for _write() */
25 #include <sys/timeb.h> /* for _ftime() */
32 #include "variables.h"
40 /* Workarounds for Windows */
41 /* Probably to be moved up the source tree in the future, perhaps to be replaced by
42 * more specific checks like configure-style HAVE_GETTIMEOFDAY macros.
46 typedef struct timeval TimevalStruct;
48 #define GETTIMEOFDAY(T) gettimeofday(T, NULL)
49 #define DIFF_MSEC(T, U) ((((T)->tv_sec - (U)->tv_sec) * 1000000.0 + (T)->tv_usec - (U)->tv_usec) / 1000.0)
53 typedef struct _timeb TimevalStruct;
55 #define GETTIMEOFDAY(T) _ftime(T)
56 #define DIFF_MSEC(T, U) ((((T)->time - (U)->time) * 1000.0 + (T)->millitm - (U)->millitm))
59 extern bool prompt_state;
62 static bool is_transact_command(const char *query);
66 * "Safe" wrapper around strdup()
69 xstrdup(const char *string)
75 fprintf(stderr, gettext("%s: xstrdup: cannot duplicate null pointer (internal error)\n"),
82 psql_error("out of memory\n");
92 * -- handler for -o command line option and \o command
94 * Tries to open file fname (or pipe if fname starts with '|')
95 * and stores the file handle in pset)
96 * Upon failure, sets stdout and returns false.
99 setQFout(const char *fname)
103 /* Close old file/pipe */
104 if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
106 if (pset.queryFoutPipe)
107 pclose(pset.queryFout);
109 fclose(pset.queryFout);
112 /* If no filename, set stdout */
113 if (!fname || fname[0] == '\0')
115 pset.queryFout = stdout;
116 pset.queryFoutPipe = false;
118 else if (*fname == '|')
120 pset.queryFout = popen(fname + 1, "w");
121 pset.queryFoutPipe = true;
125 pset.queryFout = fopen(fname, "w");
126 pset.queryFoutPipe = false;
129 if (!(pset.queryFout))
131 psql_error("%s: %s\n", fname, strerror(errno));
132 pset.queryFout = stdout;
133 pset.queryFoutPipe = false;
139 pqsignal(SIGPIPE, pset.queryFoutPipe ? SIG_IGN : SIG_DFL);
148 * Error reporting for scripts. Errors should look like
149 * psql:filename:lineno: message
153 psql_error(const char *fmt,...)
158 if (pset.queryFout != stdout)
159 fflush(pset.queryFout);
162 fprintf(stderr, "%s:%s:%u: ", pset.progname, pset.inputfile, pset.lineno);
164 vfprintf(stderr, gettext(fmt), ap);
171 * for backend Notice messages (INFO, WARNING, etc)
174 NoticeProcessor(void *arg, const char *message)
176 (void) arg; /* not used */
177 psql_error("%s", message);
183 * Code to support query cancellation
185 * Before we start a query, we enable a SIGINT signal catcher that sends a
186 * cancel request to the backend. Note that sending the cancel directly from
187 * the signal handler is safe because PQrequestCancel() is written to make it
188 * so. We use write() to print to stdout because it's better to use simple
189 * facilities in a signal handler.
191 static PGconn *volatile cancelConn = NULL;
193 volatile bool cancel_pressed = false;
198 #define write_stderr(String) write(fileno(stderr), String, strlen(String))
201 handle_sigint(SIGNAL_ARGS)
203 int save_errno = errno;
205 /* Don't muck around if prompting for a password. */
209 if (cancelConn == NULL)
210 siglongjmp(main_loop_jmp, 1);
212 cancel_pressed = true;
214 if (PQrequestCancel(cancelConn))
215 write_stderr("Cancel request sent\n");
218 write_stderr("Could not send cancel request: ");
219 write_stderr(PQerrorMessage(cancelConn));
221 errno = save_errno; /* just in case the write changed it */
223 #endif /* not WIN32 */
229 * Returns whether our backend connection is still there.
234 return PQstatus(pset.db) != CONNECTION_BAD;
241 * Verify that we still have a good connection to the backend, and if not,
242 * see if it can be restored.
244 * Returns true if either the connection was still there, or it could be
245 * restored successfully; false otherwise. If, however, there was no
246 * connection and the session is non-interactive, this will exit the program
247 * with a code of EXIT_BADCONN.
257 if (!pset.cur_cmd_interactive)
259 psql_error("connection to server was lost\n");
263 fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr);
268 fputs(gettext("Failed.\n"), stderr);
275 fputs(gettext("Succeeded.\n"), stderr);
286 * Set cancelConn to point to the current database connection.
291 cancelConn = pset.db;
298 * Set cancelConn to NULL. I don't know what this means exactly, but it saves
299 * having to export the variable.
302 ResetCancelConn(void)
311 * Checks whether a result is valid, giving an error message if necessary;
312 * resets cancelConn as needed, and ensures that the connection to the backend
315 * Returns true for valid result, false for error state.
318 AcceptResult(const PGresult *result)
327 switch (PQresultStatus(result))
329 case PGRES_COMMAND_OK:
330 case PGRES_TUPLES_OK:
332 /* Fine, do nothing */
336 /* keep cancel connection for copy out state */
348 psql_error("%s", PQerrorMessage(pset.db));
359 * This is the way to send "backdoor" queries (those not directly entered
360 * by the user). It is subject to -E but not -e.
362 * In autocommit-off mode, a new transaction block is started if start_xact
363 * is true; nothing special is done when start_xact is false. Typically,
364 * start_xact = false is used for SELECTs and explicit BEGIN/COMMIT commands.
367 PSQLexec(const char *query, bool start_xact)
374 psql_error("You are currently not connected to a database.\n");
378 echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
379 if (echo_hidden != VAR_NOTSET)
381 printf("********* QUERY **********\n"
383 "**************************\n\n", query);
386 if (echo_hidden == 1) /* noexec? */
392 if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
393 !GetVariableBool(pset.vars, "AUTOCOMMIT"))
395 res = PQexec(pset.db, "BEGIN");
396 if (PQresultStatus(res) != PGRES_COMMAND_OK)
398 psql_error("%s", PQerrorMessage(pset.db));
406 res = PQexec(pset.db, query);
408 if (!AcceptResult(res) && res)
420 * PrintNotifications: check for asynchronous notifications, and print them out
424 PrintNotifications(void)
428 while ((notify = PQnotifies(pset.db)))
430 fprintf(pset.queryFout, gettext("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
431 notify->relname, notify->be_pid);
433 fflush(pset.queryFout);
439 * PrintQueryTuples: assuming query result is OK, print its tuples
441 * Returns true if successful, false otherwise.
444 PrintQueryTuples(const PGresult *results)
446 /* write output to \g argument, if any */
449 FILE *queryFout_copy = pset.queryFout;
450 bool queryFoutPipe_copy = pset.queryFoutPipe;
452 pset.queryFout = stdout; /* so it doesn't get closed */
455 if (!setQFout(pset.gfname))
457 pset.queryFout = queryFout_copy;
458 pset.queryFoutPipe = queryFoutPipe_copy;
462 printQuery(results, &pset.popt, pset.queryFout);
464 /* close file/pipe, restore old setting */
467 pset.queryFout = queryFout_copy;
468 pset.queryFoutPipe = queryFoutPipe_copy;
474 printQuery(results, &pset.popt, pset.queryFout);
482 * PrintQueryResults: analyze query results and print them out
484 * Note: Utility function for use by SendQuery() only.
486 * Returns true if the query executed successfully, false otherwise.
489 PrintQueryResults(PGresult *results,
490 const TimevalStruct * before,
491 const TimevalStruct * after)
493 bool success = false;
498 switch (PQresultStatus(results))
500 case PGRES_TUPLES_OK:
501 success = PrintQueryTuples(results);
503 case PGRES_EMPTY_QUERY:
506 case PGRES_COMMAND_OK:
511 sprintf(buf, "%u", (unsigned int) PQoidValue(results));
514 if (pset.popt.topt.format == PRINT_HTML)
516 fputs("<p>", pset.queryFout);
517 html_escaped_print(PQcmdStatus(results), pset.queryFout);
518 fputs("</p>\n", pset.queryFout);
521 fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
523 SetVariable(pset.vars, "LASTOID", buf);
527 success = handleCopyOut(pset.db, pset.queryFout);
531 if (pset.cur_cmd_interactive && !QUIET())
532 puts(gettext("Enter data to be copied followed by a newline.\n"
533 "End with a backslash and a period on a line by itself."));
535 success = handleCopyIn(pset.db, pset.cur_cmd_source,
536 pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL);
543 fflush(pset.queryFout);
545 if (!CheckConnection())
548 /* Possible microtiming output */
549 if (pset.timing && success)
550 printf(gettext("Time: %.2f ms\n"), DIFF_MSEC(after, before));
558 * SendQuery: send the query string to the backend
559 * (and print out results)
561 * Note: This is the "front door" way to send a query. That is, use it to
562 * send queries actually entered by the user. These queries will be subject to
564 * To send "back door" queries (generated by slash commands, etc.) in a
565 * controlled way, use PSQLexec().
567 * Returns true if the query executed successfully, false otherwise.
570 SendQuery(const char *query)
573 TimevalStruct before,
579 psql_error("You are currently not connected to a database.\n");
583 if (GetVariableBool(pset.vars, "SINGLESTEP"))
587 printf(gettext("***(Single step mode: verify command)*******************************************\n"
589 "***(press return to proceed or enter x and return to cancel)********************\n"),
592 if (fgets(buf, sizeof(buf), stdin) != NULL)
596 else if (VariableEquals(pset.vars, "ECHO", "queries"))
604 if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
605 !GetVariableBool(pset.vars, "AUTOCOMMIT") &&
606 !is_transact_command(query))
608 results = PQexec(pset.db, "BEGIN");
609 if (PQresultStatus(results) != PGRES_COMMAND_OK)
611 psql_error("%s", PQerrorMessage(pset.db));
620 GETTIMEOFDAY(&before);
621 results = PQexec(pset.db, query);
623 GETTIMEOFDAY(&after);
625 OK = (AcceptResult(results) && PrintQueryResults(results, &before, &after));
628 PrintNotifications();
633 * check whether a query string begins with BEGIN/COMMIT/ROLLBACK/START XACT
636 is_transact_command(const char *query)
641 * First we must advance over any whitespace and comments.
645 if (isspace((unsigned char) *query))
647 else if (query[0] == '-' && query[1] == '-')
650 while (*query && *query != '\n')
653 else if (query[0] == '/' && query[1] == '*')
658 if (query[0] == '*' && query[1] == '/')
668 break; /* found first token */
672 * Check word length ("beginx" is not "begin").
675 while (isalpha((unsigned char) query[wordlen]))
678 if (wordlen == 5 && strncasecmp(query, "begin", 5) == 0)
680 if (wordlen == 6 && strncasecmp(query, "commit", 6) == 0)
682 if (wordlen == 8 && strncasecmp(query, "rollback", 8) == 0)
684 if (wordlen == 5 && strncasecmp(query, "abort", 5) == 0)
686 if (wordlen == 3 && strncasecmp(query, "end", 3) == 0)
688 if (wordlen == 5 && strncasecmp(query, "start", 5) == 0)
696 parse_char(char **buf)
700 l = strtol(*buf, buf, 0);
707 * Test if the current user is a database superuser.
709 * Note: this will correctly detect superuserness only with a protocol-3.0
710 * or newer backend; otherwise it will always say "false".
720 val = PQparameterStatus(pset.db, "is_superuser");
722 if (val && strcmp(val, "on") == 0)