2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2006, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.130 2006/10/04 00:30:05 momjian Exp $
8 #include "postgres_fe.h"
15 #include <unistd.h> /* for write() */
17 #include <io.h> /* for _write() */
19 #include <sys/timeb.h> /* for _ftime() */
27 #include "mb/pg_wchar.h"
31 /* Workarounds for Windows */
32 /* Probably to be moved up the source tree in the future, perhaps to be replaced by
33 * more specific checks like configure-style HAVE_GETTIMEOFDAY macros.
37 typedef struct timeval TimevalStruct;
39 #define GETTIMEOFDAY(T) gettimeofday(T, NULL)
40 #define DIFF_MSEC(T, U) \
41 ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
42 ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
45 typedef struct _timeb TimevalStruct;
47 #define GETTIMEOFDAY(T) _ftime(T)
48 #define DIFF_MSEC(T, U) \
49 (((T)->time - (U)->time) * 1000.0 + \
50 ((T)->millitm - (U)->millitm))
54 static bool ExecQueryUsingCursor(const char *query, double *elapsed_msec);
55 static bool command_no_begin(const char *query);
56 static bool is_select_command(const char *query);
59 * "Safe" wrapper around strdup()
62 pg_strdup(const char *string)
68 fprintf(stderr, _("%s: pg_strdup: cannot duplicate null pointer (internal error)\n"),
75 psql_error("out of memory\n");
82 pg_malloc(size_t size)
89 psql_error("out of memory\n");
96 pg_malloc_zero(size_t size)
100 tmp = pg_malloc(size);
101 memset(tmp, 0, size);
106 pg_calloc(size_t nmemb, size_t size)
110 tmp = calloc(nmemb, size);
113 psql_error("out of memory");
121 * -- handler for -o command line option and \o command
123 * Tries to open file fname (or pipe if fname starts with '|')
124 * and stores the file handle in pset)
125 * Upon failure, sets stdout and returns false.
128 setQFout(const char *fname)
132 /* Close old file/pipe */
133 if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
135 if (pset.queryFoutPipe)
136 pclose(pset.queryFout);
138 fclose(pset.queryFout);
141 /* If no filename, set stdout */
142 if (!fname || fname[0] == '\0')
144 pset.queryFout = stdout;
145 pset.queryFoutPipe = false;
147 else if (*fname == '|')
149 pset.queryFout = popen(fname + 1, "w");
150 pset.queryFoutPipe = true;
154 pset.queryFout = fopen(fname, "w");
155 pset.queryFoutPipe = false;
158 if (!(pset.queryFout))
160 psql_error("%s: %s\n", fname, strerror(errno));
161 pset.queryFout = stdout;
162 pset.queryFoutPipe = false;
168 pqsignal(SIGPIPE, pset.queryFoutPipe ? SIG_IGN : SIG_DFL);
177 * Error reporting for scripts. Errors should look like
178 * psql:filename:lineno: message
182 psql_error(const char *fmt,...)
187 if (pset.queryFout != stdout)
188 fflush(pset.queryFout);
191 fprintf(stderr, "%s:%s:" UINT64_FORMAT ": ", pset.progname, pset.inputfile, pset.lineno);
193 vfprintf(stderr, _(fmt), ap);
200 * for backend Notice messages (INFO, WARNING, etc)
203 NoticeProcessor(void *arg, const char *message)
205 (void) arg; /* not used */
206 psql_error("%s", message);
212 * Code to support query cancellation
214 * Before we start a query, we enable the SIGINT signal catcher to send a
215 * cancel request to the backend. Note that sending the cancel directly from
216 * the signal handler is safe because PQcancel() is written to make it
217 * so. We use write() to report to stderr because it's better to use simple
218 * facilities in a signal handler.
220 * On win32, the signal cancelling happens on a separate thread, because
221 * that's how SetConsoleCtrlHandler works. The PQcancel function is safe
222 * for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required
223 * to protect the PGcancel structure against being changed while the signal
224 * thread is using it.
226 * SIGINT is supposed to abort all long-running psql operations, not only
227 * database queries. In most places, this is accomplished by checking
228 * cancel_pressed during long-running loops. However, that won't work when
229 * blocked on user input (in readline() or fgets()). In those places, we
230 * set sigint_interrupt_enabled TRUE while blocked, instructing the signal
231 * catcher to longjmp through sigint_interrupt_jmp. We assume readline and
232 * fgets are coded to handle possible interruption. (XXX currently this does
233 * not work on win32, so control-C is less useful there)
235 volatile bool sigint_interrupt_enabled = false;
237 sigjmp_buf sigint_interrupt_jmp;
239 static PGcancel *volatile cancelConn = NULL;
242 static CRITICAL_SECTION cancelConnLock;
245 #define write_stderr(str) write(fileno(stderr), str, strlen(str))
251 handle_sigint(SIGNAL_ARGS)
253 int save_errno = errno;
256 /* if we are waiting for input, longjmp out of it */
257 if (sigint_interrupt_enabled)
259 sigint_interrupt_enabled = false;
260 siglongjmp(sigint_interrupt_jmp, 1);
263 /* else, set cancel flag to stop any long-running loops */
264 cancel_pressed = true;
266 /* and send QueryCancel if we are processing a database query */
267 if (cancelConn != NULL)
269 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
270 write_stderr("Cancel request sent\n");
273 write_stderr("Could not send cancel request: ");
274 write_stderr(errbuf);
278 errno = save_errno; /* just in case the write changed it */
282 setup_cancel_handler(void)
284 pqsignal(SIGINT, handle_sigint);
289 consoleHandler(DWORD dwCtrlType)
293 if (dwCtrlType == CTRL_C_EVENT ||
294 dwCtrlType == CTRL_BREAK_EVENT)
297 * Can't longjmp here, because we are in wrong thread :-(
300 /* set cancel flag to stop any long-running loops */
301 cancel_pressed = true;
303 /* and send QueryCancel if we are processing a database query */
304 EnterCriticalSection(&cancelConnLock);
305 if (cancelConn != NULL)
307 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
308 write_stderr("Cancel request sent\n");
311 write_stderr("Could not send cancel request: ");
312 write_stderr(errbuf);
315 LeaveCriticalSection(&cancelConnLock);
320 /* Return FALSE for any signals not being handled */
325 setup_cancel_handler(void)
327 InitializeCriticalSection(&cancelConnLock);
329 SetConsoleCtrlHandler(consoleHandler, TRUE);
336 * Returns whether our backend connection is still there.
341 return PQstatus(pset.db) != CONNECTION_BAD;
348 * Verify that we still have a good connection to the backend, and if not,
349 * see if it can be restored.
351 * Returns true if either the connection was still there, or it could be
352 * restored successfully; false otherwise. If, however, there was no
353 * connection and the session is non-interactive, this will exit the program
354 * with a code of EXIT_BADCONN.
357 CheckConnection(void)
364 if (!pset.cur_cmd_interactive)
366 psql_error("connection to server was lost\n");
370 fputs(_("The connection to the server was lost. Attempting reset: "), stderr);
375 fputs(_("Failed.\n"), stderr);
382 fputs(_("Succeeded.\n"), stderr);
393 * Set cancelConn to point to the current database connection.
398 PGcancel *oldCancelConn;
401 EnterCriticalSection(&cancelConnLock);
404 /* Free the old one if we have one */
405 oldCancelConn = cancelConn;
406 /* be sure handle_sigint doesn't use pointer while freeing */
409 if (oldCancelConn != NULL)
410 PQfreeCancel(oldCancelConn);
412 cancelConn = PQgetCancel(pset.db);
415 LeaveCriticalSection(&cancelConnLock);
423 * Free the current cancel connection, if any, and set to NULL.
426 ResetCancelConn(void)
428 PGcancel *oldCancelConn;
431 EnterCriticalSection(&cancelConnLock);
434 oldCancelConn = cancelConn;
435 /* be sure handle_sigint doesn't use pointer while freeing */
438 if (oldCancelConn != NULL)
439 PQfreeCancel(oldCancelConn);
442 LeaveCriticalSection(&cancelConnLock);
450 * Checks whether a result is valid, giving an error message if necessary;
451 * and ensures that the connection to the backend is still up.
453 * Returns true for valid result, false for error state.
456 AcceptResult(const PGresult *result)
463 switch (PQresultStatus(result))
465 case PGRES_COMMAND_OK:
466 case PGRES_TUPLES_OK:
467 case PGRES_EMPTY_QUERY:
470 /* Fine, do nothing */
480 const char *error = PQerrorMessage(pset.db);
483 psql_error("%s", error);
496 * This is the way to send "backdoor" queries (those not directly entered
497 * by the user). It is subject to -E but not -e.
499 * In autocommit-off mode, a new transaction block is started if start_xact
500 * is true; nothing special is done when start_xact is false. Typically,
501 * start_xact = false is used for SELECTs and explicit BEGIN/COMMIT commands.
503 * Caller is responsible for handling the ensuing processing if a COPY
506 * Note: we don't bother to check PQclientEncoding; it is assumed that no
507 * caller uses this path to issue "SET CLIENT_ENCODING".
510 PSQLexec(const char *query, bool start_xact)
516 psql_error("You are currently not connected to a database.\n");
520 if (pset.echo_hidden != PSQL_ECHO_HIDDEN_OFF)
522 printf(_("********* QUERY **********\n"
524 "**************************\n\n"), query);
528 fprintf(pset.logfile,
529 _("********* QUERY **********\n"
531 "**************************\n\n"), query);
532 fflush(pset.logfile);
535 if (pset.echo_hidden == PSQL_ECHO_HIDDEN_NOEXEC)
543 PQtransactionStatus(pset.db) == PQTRANS_IDLE)
545 res = PQexec(pset.db, "BEGIN");
546 if (PQresultStatus(res) != PGRES_COMMAND_OK)
548 psql_error("%s", PQerrorMessage(pset.db));
556 res = PQexec(pset.db, query);
560 if (!AcceptResult(res))
572 * PrintNotifications: check for asynchronous notifications, and print them out
575 PrintNotifications(void)
579 while ((notify = PQnotifies(pset.db)))
581 fprintf(pset.queryFout, _("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
582 notify->relname, notify->be_pid);
583 fflush(pset.queryFout);
590 * PrintQueryTuples: assuming query result is OK, print its tuples
592 * Returns true if successful, false otherwise.
595 PrintQueryTuples(const PGresult *results)
597 printQueryOpt my_popt = pset.popt;
599 /* write output to \g argument, if any */
602 /* keep this code in sync with ExecQueryUsingCursor */
603 FILE *queryFout_copy = pset.queryFout;
604 bool queryFoutPipe_copy = pset.queryFoutPipe;
606 pset.queryFout = stdout; /* so it doesn't get closed */
609 if (!setQFout(pset.gfname))
611 pset.queryFout = queryFout_copy;
612 pset.queryFoutPipe = queryFoutPipe_copy;
616 printQuery(results, &my_popt, pset.queryFout, pset.logfile);
618 /* close file/pipe, restore old setting */
621 pset.queryFout = queryFout_copy;
622 pset.queryFoutPipe = queryFoutPipe_copy;
628 printQuery(results, &my_popt, pset.queryFout, pset.logfile);
635 * ProcessCopyResult: if command was a COPY FROM STDIN/TO STDOUT, handle it
637 * Note: Utility function for use by SendQuery() only.
639 * Returns true if the query executed successfully, false otherwise.
642 ProcessCopyResult(PGresult *results)
644 bool success = false;
649 switch (PQresultStatus(results))
651 case PGRES_TUPLES_OK:
652 case PGRES_COMMAND_OK:
653 case PGRES_EMPTY_QUERY:
654 /* nothing to do here */
660 success = handleCopyOut(pset.db, pset.queryFout);
666 success = handleCopyIn(pset.db, pset.cur_cmd_source,
667 PQbinaryTuples(results));
675 /* may need this to recover from conn loss during COPY */
676 if (!CheckConnection())
684 * PrintQueryStatus: report command status as required
686 * Note: Utility function for use by PrintQueryResults() only.
689 PrintQueryStatus(PGresult *results)
695 if (pset.popt.topt.format == PRINT_HTML)
697 fputs("<p>", pset.queryFout);
698 html_escaped_print(PQcmdStatus(results), pset.queryFout);
699 fputs("</p>\n", pset.queryFout);
702 fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
706 fprintf(pset.logfile, "%s\n", PQcmdStatus(results));
708 snprintf(buf, sizeof(buf), "%u", (unsigned int) PQoidValue(results));
709 SetVariable(pset.vars, "LASTOID", buf);
714 * PrintQueryResults: print out query results as required
716 * Note: Utility function for use by SendQuery() only.
718 * Returns true if the query executed successfully, false otherwise.
721 PrintQueryResults(PGresult *results)
723 bool success = false;
724 const char *cmdstatus;
729 switch (PQresultStatus(results))
731 case PGRES_TUPLES_OK:
732 /* print the data ... */
733 success = PrintQueryTuples(results);
734 /* if it's INSERT/UPDATE/DELETE RETURNING, also print status */
735 cmdstatus = PQcmdStatus(results);
736 if (strncmp(cmdstatus, "INSERT", 6) == 0 ||
737 strncmp(cmdstatus, "UPDATE", 6) == 0 ||
738 strncmp(cmdstatus, "DELETE", 6) == 0)
739 PrintQueryStatus(results);
742 case PGRES_COMMAND_OK:
743 PrintQueryStatus(results);
747 case PGRES_EMPTY_QUERY:
753 /* nothing to do here */
761 fflush(pset.queryFout);
768 * SendQuery: send the query string to the backend
769 * (and print out results)
771 * Note: This is the "front door" way to send a query. That is, use it to
772 * send queries actually entered by the user. These queries will be subject to
774 * To send "back door" queries (generated by slash commands, etc.) in a
775 * controlled way, use PSQLexec().
777 * Returns true if the query executed successfully, false otherwise.
780 SendQuery(const char *query)
783 PGTransactionStatusType transaction_status;
784 double elapsed_msec = 0;
786 on_error_rollback_savepoint = false;
787 static bool on_error_rollback_warning = false;
791 psql_error("You are currently not connected to a database.\n");
799 printf(_("***(Single step mode: verify command)*******************************************\n"
801 "***(press return to proceed or enter x and return to cancel)********************\n"),
804 if (fgets(buf, sizeof(buf), stdin) != NULL)
808 else if (pset.echo == PSQL_ECHO_QUERIES)
816 fprintf(pset.logfile,
817 _("********* QUERY **********\n"
819 "**************************\n\n"), query);
820 fflush(pset.logfile);
825 transaction_status = PQtransactionStatus(pset.db);
827 if (transaction_status == PQTRANS_IDLE &&
829 !command_no_begin(query))
831 results = PQexec(pset.db, "BEGIN");
832 if (PQresultStatus(results) != PGRES_COMMAND_OK)
834 psql_error("%s", PQerrorMessage(pset.db));
840 transaction_status = PQtransactionStatus(pset.db);
843 if (transaction_status == PQTRANS_INTRANS &&
844 pset.on_error_rollback != PSQL_ERROR_ROLLBACK_OFF &&
845 (pset.cur_cmd_interactive ||
846 pset.on_error_rollback == PSQL_ERROR_ROLLBACK_ON))
848 if (on_error_rollback_warning == false && pset.sversion < 80000)
850 fprintf(stderr, _("The server version (%d) does not support savepoints for ON_ERROR_ROLLBACK.\n"),
852 on_error_rollback_warning = true;
856 results = PQexec(pset.db, "SAVEPOINT pg_psql_temporary_savepoint");
857 if (PQresultStatus(results) != PGRES_COMMAND_OK)
859 psql_error("%s", PQerrorMessage(pset.db));
865 on_error_rollback_savepoint = true;
869 if (pset.fetch_count <= 0 || !is_select_command(query))
871 /* Default fetch-it-all-and-print mode */
872 TimevalStruct before,
876 GETTIMEOFDAY(&before);
878 results = PQexec(pset.db, query);
880 /* these operations are included in the timing result: */
882 OK = (AcceptResult(results) && ProcessCopyResult(results));
886 GETTIMEOFDAY(&after);
887 elapsed_msec = DIFF_MSEC(&after, &before);
890 /* but printing results isn't: */
892 OK = PrintQueryResults(results);
896 /* Fetch-in-segments mode */
897 OK = ExecQueryUsingCursor(query, &elapsed_msec);
899 results = NULL; /* PQclear(NULL) does nothing */
902 /* If we made a temporary savepoint, possibly release/rollback */
903 if (on_error_rollback_savepoint)
907 transaction_status = PQtransactionStatus(pset.db);
909 /* We always rollback on an error */
910 if (transaction_status == PQTRANS_INERROR)
911 svptres = PQexec(pset.db, "ROLLBACK TO pg_psql_temporary_savepoint");
912 /* If they are no longer in a transaction, then do nothing */
913 else if (transaction_status != PQTRANS_INTRANS)
918 * Do nothing if they are messing with savepoints themselves: If
919 * the user did RELEASE or ROLLBACK, our savepoint is gone. If
920 * they issued a SAVEPOINT, releasing ours would remove theirs.
923 (strcmp(PQcmdStatus(results), "SAVEPOINT") == 0 ||
924 strcmp(PQcmdStatus(results), "RELEASE") == 0 ||
925 strcmp(PQcmdStatus(results), "ROLLBACK") == 0))
928 svptres = PQexec(pset.db, "RELEASE pg_psql_temporary_savepoint");
930 if (svptres && PQresultStatus(svptres) != PGRES_COMMAND_OK)
932 psql_error("%s", PQerrorMessage(pset.db));
944 /* Possible microtiming output */
945 if (OK && pset.timing)
946 printf(_("Time: %.3f ms\n"), elapsed_msec);
948 /* check for events that may occur during query execution */
950 if (pset.encoding != PQclientEncoding(pset.db) &&
951 PQclientEncoding(pset.db) >= 0)
953 /* track effects of SET CLIENT_ENCODING */
954 pset.encoding = PQclientEncoding(pset.db);
955 pset.popt.topt.encoding = pset.encoding;
956 SetVariable(pset.vars, "ENCODING",
957 pg_encoding_to_char(pset.encoding));
960 PrintNotifications();
967 * ExecQueryUsingCursor: run a SELECT-like query using a cursor
969 * This feature allows result sets larger than RAM to be dealt with.
971 * Returns true if the query executed successfully, false otherwise.
973 * If pset.timing is on, total query time (exclusive of result-printing) is
974 * stored into *elapsed_msec.
977 ExecQueryUsingCursor(const char *query, double *elapsed_msec)
982 printQueryOpt my_popt = pset.popt;
983 FILE *queryFout_copy = pset.queryFout;
984 bool queryFoutPipe_copy = pset.queryFoutPipe;
985 bool started_txn = false;
986 bool did_pager = false;
989 TimevalStruct before,
994 /* initialize print options for partial table output */
995 my_popt.topt.start_table = true;
996 my_popt.topt.stop_table = false;
997 my_popt.topt.prior_records = 0;
1000 GETTIMEOFDAY(&before);
1002 /* if we're not in a transaction, start one */
1003 if (PQtransactionStatus(pset.db) == PQTRANS_IDLE)
1005 results = PQexec(pset.db, "BEGIN");
1006 OK = AcceptResult(results) &&
1007 (PQresultStatus(results) == PGRES_COMMAND_OK);
1014 /* Send DECLARE CURSOR */
1015 initPQExpBuffer(&buf);
1016 appendPQExpBuffer(&buf, "DECLARE _psql_cursor NO SCROLL CURSOR FOR\n%s",
1019 results = PQexec(pset.db, buf.data);
1020 OK = AcceptResult(results) &&
1021 (PQresultStatus(results) == PGRES_COMMAND_OK);
1023 termPQExpBuffer(&buf);
1029 GETTIMEOFDAY(&after);
1030 *elapsed_msec += DIFF_MSEC(&after, &before);
1033 snprintf(fetch_cmd, sizeof(fetch_cmd),
1034 "FETCH FORWARD %d FROM _psql_cursor",
1037 /* prepare to write output to \g argument, if any */
1040 /* keep this code in sync with PrintQueryTuples */
1041 pset.queryFout = stdout; /* so it doesn't get closed */
1043 /* open file/pipe */
1044 if (!setQFout(pset.gfname))
1046 pset.queryFout = queryFout_copy;
1047 pset.queryFoutPipe = queryFoutPipe_copy;
1056 GETTIMEOFDAY(&before);
1058 /* get FETCH_COUNT tuples at a time */
1059 results = PQexec(pset.db, fetch_cmd);
1063 GETTIMEOFDAY(&after);
1064 *elapsed_msec += DIFF_MSEC(&after, &before);
1067 if (PQresultStatus(results) != PGRES_TUPLES_OK)
1069 /* shut down pager before printing error message */
1072 ClosePager(pset.queryFout);
1073 pset.queryFout = queryFout_copy;
1074 pset.queryFoutPipe = queryFoutPipe_copy;
1078 OK = AcceptResult(results);
1084 ntuples = PQntuples(results);
1086 if (ntuples < pset.fetch_count)
1088 /* this is the last result set, so allow footer decoration */
1089 my_popt.topt.stop_table = true;
1091 else if (pset.queryFout == stdout && !did_pager)
1094 * If query requires multiple result sets, hack to ensure that
1095 * only one pager instance is used for the whole mess
1097 pset.queryFout = PageOutput(100000, my_popt.topt.pager);
1101 printQuery(results, &my_popt, pset.queryFout, pset.logfile);
1103 /* after the first result set, disallow header decoration */
1104 my_popt.topt.start_table = false;
1105 my_popt.topt.prior_records += ntuples;
1109 if (ntuples < pset.fetch_count || cancel_pressed)
1113 /* close \g argument file/pipe, restore old setting */
1116 /* keep this code in sync with PrintQueryTuples */
1119 pset.queryFout = queryFout_copy;
1120 pset.queryFoutPipe = queryFoutPipe_copy;
1127 ClosePager(pset.queryFout);
1128 pset.queryFout = queryFout_copy;
1129 pset.queryFoutPipe = queryFoutPipe_copy;
1134 GETTIMEOFDAY(&before);
1137 * We try to close the cursor on either success or failure, but on failure
1138 * ignore the result (it's probably just a bleat about being in an aborted
1141 results = PQexec(pset.db, "CLOSE _psql_cursor");
1144 OK = AcceptResult(results) &&
1145 (PQresultStatus(results) == PGRES_COMMAND_OK);
1151 results = PQexec(pset.db, OK ? "COMMIT" : "ROLLBACK");
1152 OK &= AcceptResult(results) &&
1153 (PQresultStatus(results) == PGRES_COMMAND_OK);
1159 GETTIMEOFDAY(&after);
1160 *elapsed_msec += DIFF_MSEC(&after, &before);
1168 * Advance the given char pointer over white space and SQL comments.
1171 skip_white_space(const char *query)
1173 int cnestlevel = 0; /* slash-star comment nest level */
1177 int mblen = PQmblen(query, pset.encoding);
1180 * Note: we assume the encoding is a superset of ASCII, so that for
1181 * example "query[0] == '/'" is meaningful. However, we do NOT assume
1182 * that the second and subsequent bytes of a multibyte character
1183 * couldn't look like ASCII characters; so it is critical to advance
1184 * by mblen, not 1, whenever we haven't exactly identified the
1185 * character we are skipping over.
1187 if (isspace((unsigned char) *query))
1189 else if (query[0] == '/' && query[1] == '*')
1194 else if (cnestlevel > 0 && query[0] == '*' && query[1] == '/')
1199 else if (cnestlevel == 0 && query[0] == '-' && query[1] == '-')
1204 * We have to skip to end of line since any slash-star inside the
1205 * -- comment does NOT start a slash-star comment.
1214 query += PQmblen(query, pset.encoding);
1217 else if (cnestlevel > 0)
1220 break; /* found first token */
1228 * Check whether a command is one of those for which we should NOT start
1229 * a new transaction block (ie, send a preceding BEGIN).
1231 * These include the transaction control statements themselves, plus
1232 * certain statements that the backend disallows inside transaction blocks.
1235 command_no_begin(const char *query)
1240 * First we must advance over any whitespace and comments.
1242 query = skip_white_space(query);
1245 * Check word length (since "beginx" is not "begin").
1248 while (isalpha((unsigned char) query[wordlen]))
1249 wordlen += PQmblen(&query[wordlen], pset.encoding);
1252 * Transaction control commands. These should include every keyword that
1253 * gives rise to a TransactionStmt in the backend grammar, except for the
1254 * savepoint-related commands.
1256 * (We assume that START must be START TRANSACTION, since there is
1257 * presently no other "START foo" command.)
1259 if (wordlen == 5 && pg_strncasecmp(query, "abort", 5) == 0)
1261 if (wordlen == 5 && pg_strncasecmp(query, "begin", 5) == 0)
1263 if (wordlen == 5 && pg_strncasecmp(query, "start", 5) == 0)
1265 if (wordlen == 6 && pg_strncasecmp(query, "commit", 6) == 0)
1267 if (wordlen == 3 && pg_strncasecmp(query, "end", 3) == 0)
1269 if (wordlen == 8 && pg_strncasecmp(query, "rollback", 8) == 0)
1271 if (wordlen == 7 && pg_strncasecmp(query, "prepare", 7) == 0)
1273 /* PREPARE TRANSACTION is a TC command, PREPARE foo is not */
1276 query = skip_white_space(query);
1279 while (isalpha((unsigned char) query[wordlen]))
1280 wordlen += PQmblen(&query[wordlen], pset.encoding);
1282 if (wordlen == 11 && pg_strncasecmp(query, "transaction", 11) == 0)
1288 * Commands not allowed within transactions. The statements checked for
1289 * here should be exactly those that call PreventTransactionChain() in the
1292 if (wordlen == 6 && pg_strncasecmp(query, "vacuum", 6) == 0)
1294 if (wordlen == 7 && pg_strncasecmp(query, "cluster", 7) == 0)
1296 /* CLUSTER with any arguments is allowed in transactions */
1299 query = skip_white_space(query);
1301 if (isalpha((unsigned char) query[0]))
1302 return false; /* has additional words */
1303 return true; /* it's CLUSTER without arguments */
1306 if (wordlen == 6 && pg_strncasecmp(query, "create", 6) == 0)
1310 query = skip_white_space(query);
1313 while (isalpha((unsigned char) query[wordlen]))
1314 wordlen += PQmblen(&query[wordlen], pset.encoding);
1316 if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
1318 if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
1321 /* CREATE [UNIQUE] INDEX CONCURRENTLY isn't allowed in xacts */
1322 if (wordlen == 6 && pg_strncasecmp(query, "unique", 6) == 0)
1326 query = skip_white_space(query);
1329 while (isalpha((unsigned char) query[wordlen]))
1330 wordlen += PQmblen(&query[wordlen], pset.encoding);
1333 if (wordlen == 5 && pg_strncasecmp(query, "index", 5) == 0)
1337 query = skip_white_space(query);
1340 while (isalpha((unsigned char) query[wordlen]))
1341 wordlen += PQmblen(&query[wordlen], pset.encoding);
1343 if (wordlen == 12 && pg_strncasecmp(query, "concurrently", 12) == 0)
1351 * Note: these tests will match DROP SYSTEM and REINDEX TABLESPACE, which
1352 * aren't really valid commands so we don't care much. The other four
1353 * possible matches are correct.
1355 if ((wordlen == 4 && pg_strncasecmp(query, "drop", 4) == 0) ||
1356 (wordlen == 7 && pg_strncasecmp(query, "reindex", 7) == 0))
1360 query = skip_white_space(query);
1363 while (isalpha((unsigned char) query[wordlen]))
1364 wordlen += PQmblen(&query[wordlen], pset.encoding);
1366 if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
1368 if (wordlen == 6 && pg_strncasecmp(query, "system", 6) == 0)
1370 if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
1379 * Check whether the specified command is a SELECT (or VALUES).
1382 is_select_command(const char *query)
1387 * First advance over any whitespace, comments and left parentheses.
1391 query = skip_white_space(query);
1392 if (query[0] == '(')
1399 * Check word length (since "selectx" is not "select").
1402 while (isalpha((unsigned char) query[wordlen]))
1403 wordlen += PQmblen(&query[wordlen], pset.encoding);
1405 if (wordlen == 6 && pg_strncasecmp(query, "select", 6) == 0)
1408 if (wordlen == 6 && pg_strncasecmp(query, "values", 6) == 0)
1416 * Test if the current user is a database superuser.
1418 * Note: this will correctly detect superuserness only with a protocol-3.0
1419 * or newer backend; otherwise it will always say "false".
1429 val = PQparameterStatus(pset.db, "is_superuser");
1431 if (val && strcmp(val, "on") == 0)
1439 * Test if the current session uses standard string literals.
1441 * Note: With a pre-protocol-3.0 connection this will always say "false",
1442 * which should be the right answer.
1445 standard_strings(void)
1452 val = PQparameterStatus(pset.db, "standard_conforming_strings");
1454 if (val && strcmp(val, "on") == 0)
1462 * Return the session user of the current connection.
1464 * Note: this will correctly detect the session user only with a
1465 * protocol-3.0 or newer backend; otherwise it will return the
1469 session_username(void)
1476 val = PQparameterStatus(pset.db, "session_authorization");
1480 return PQuser(pset.db);
1486 * substitute '~' with HOME or '~username' with username's home dir
1490 expand_tilde(char **filename)
1492 if (!filename || !(*filename))
1496 * WIN32 doesn't use tilde expansion for file names. Also, it uses tilde
1497 * for short versions of long file names, though the tilde is usually
1498 * toward the end, not at the beginning.
1502 /* try tilde expansion */
1503 if (**filename == '~')
1509 char home[MAXPGPATH];
1515 while (*p != '/' && *p != '\0')
1521 if (*(fn + 1) == '\0')
1522 get_home_path(home); /* ~ or ~/ only */
1523 else if ((pw = getpwnam(fn + 1)) != NULL)
1524 StrNCpy(home, pw->pw_dir, MAXPGPATH); /* ~user */
1527 if (strlen(home) != 0)
1531 newfn = pg_malloc(strlen(home) + strlen(p) + 1);
1532 strcpy(newfn, home);