2 * psql - the PostgreSQL interactive terminal
4 * Copyright (c) 2000-2005, PostgreSQL Global Development Group
6 * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.108 2005/10/15 02:49:40 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)
53 typedef struct _timeb TimevalStruct;
55 #define GETTIMEOFDAY(T) _ftime(T)
56 #define DIFF_MSEC(T, U) \
57 (((T)->time - (U)->time) * 1000.0 + \
58 ((T)->millitm - (U)->millitm))
61 extern bool prompt_state;
64 static bool command_no_begin(const char *query);
67 * "Safe" wrapper around strdup()
70 pg_strdup(const char *string)
76 fprintf(stderr, _("%s: pg_strdup: cannot duplicate null pointer (internal error)\n"),
83 psql_error("out of memory\n");
90 pg_malloc(size_t size)
97 psql_error("out of memory\n");
104 pg_malloc_zero(size_t size)
108 tmp = pg_malloc(size);
109 memset(tmp, 0, size);
114 pg_calloc(size_t nmemb, size_t size)
118 tmp = calloc(nmemb, size);
121 psql_error("out of memory");
129 * -- handler for -o command line option and \o command
131 * Tries to open file fname (or pipe if fname starts with '|')
132 * and stores the file handle in pset)
133 * Upon failure, sets stdout and returns false.
136 setQFout(const char *fname)
140 /* Close old file/pipe */
141 if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
143 if (pset.queryFoutPipe)
144 pclose(pset.queryFout);
146 fclose(pset.queryFout);
149 /* If no filename, set stdout */
150 if (!fname || fname[0] == '\0')
152 pset.queryFout = stdout;
153 pset.queryFoutPipe = false;
155 else if (*fname == '|')
157 pset.queryFout = popen(fname + 1, "w");
158 pset.queryFoutPipe = true;
162 pset.queryFout = fopen(fname, "w");
163 pset.queryFoutPipe = false;
166 if (!(pset.queryFout))
168 psql_error("%s: %s\n", fname, strerror(errno));
169 pset.queryFout = stdout;
170 pset.queryFoutPipe = false;
176 pqsignal(SIGPIPE, pset.queryFoutPipe ? SIG_IGN : SIG_DFL);
185 * Error reporting for scripts. Errors should look like
186 * psql:filename:lineno: message
190 psql_error(const char *fmt,...)
195 if (pset.queryFout != stdout)
196 fflush(pset.queryFout);
199 fprintf(stderr, "%s:%s:%u: ", pset.progname, pset.inputfile, pset.lineno);
201 vfprintf(stderr, _(fmt), ap);
208 * for backend Notice messages (INFO, WARNING, etc)
211 NoticeProcessor(void *arg, const char *message)
213 (void) arg; /* not used */
214 psql_error("%s", message);
220 * Code to support query cancellation
222 * Before we start a query, we enable a SIGINT signal catcher that sends a
223 * cancel request to the backend. Note that sending the cancel directly from
224 * the signal handler is safe because PQcancel() is written to make it
225 * so. We use write() to print to stderr because it's better to use simple
226 * facilities in a signal handler.
228 * On win32, the signal cancelling happens on a separate thread, because
229 * that's how SetConsoleCtrlHandler works. The PQcancel function is safe
230 * for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required
231 * to protect the PGcancel structure against being changed while the other
232 * thread is using it.
234 static PGcancel *cancelConn = NULL;
237 static CRITICAL_SECTION cancelConnLock;
240 volatile bool cancel_pressed = false;
242 #define write_stderr(str) write(fileno(stderr), str, strlen(str))
248 handle_sigint(SIGNAL_ARGS)
250 int save_errno = errno;
253 /* Don't muck around if prompting for a password. */
257 if (cancelConn == NULL)
258 siglongjmp(main_loop_jmp, 1);
260 cancel_pressed = true;
262 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
263 write_stderr("Cancel request sent\n");
266 write_stderr("Could not send cancel request: ");
267 write_stderr(errbuf);
269 errno = save_errno; /* just in case the write changed it */
274 consoleHandler(DWORD dwCtrlType)
278 if (dwCtrlType == CTRL_C_EVENT ||
279 dwCtrlType == CTRL_BREAK_EVENT)
284 /* Perform query cancel */
285 EnterCriticalSection(&cancelConnLock);
286 if (cancelConn != NULL)
288 cancel_pressed = true;
290 if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
291 write_stderr("Cancel request sent\n");
294 write_stderr("Could not send cancel request: ");
295 write_stderr(errbuf);
298 LeaveCriticalSection(&cancelConnLock);
303 /* Return FALSE for any signals not being handled */
308 setup_win32_locks(void)
310 InitializeCriticalSection(&cancelConnLock);
314 setup_cancel_handler(void)
316 SetConsoleCtrlHandler(consoleHandler, TRUE);
323 * Returns whether our backend connection is still there.
328 return PQstatus(pset.db) != CONNECTION_BAD;
335 * Verify that we still have a good connection to the backend, and if not,
336 * see if it can be restored.
338 * Returns true if either the connection was still there, or it could be
339 * restored successfully; false otherwise. If, however, there was no
340 * connection and the session is non-interactive, this will exit the program
341 * with a code of EXIT_BADCONN.
344 CheckConnection(void)
351 if (!pset.cur_cmd_interactive)
353 psql_error("connection to server was lost\n");
357 fputs(_("The connection to the server was lost. Attempting reset: "), stderr);
362 fputs(_("Failed.\n"), stderr);
369 fputs(_("Succeeded.\n"), stderr);
380 * Set cancelConn to point to the current database connection.
386 EnterCriticalSection(&cancelConnLock);
389 /* Free the old one if we have one */
390 if (cancelConn != NULL)
391 PQfreeCancel(cancelConn);
393 cancelConn = PQgetCancel(pset.db);
396 LeaveCriticalSection(&cancelConnLock);
404 * Free the current cancel connection, if any, and set to NULL.
407 ResetCancelConn(void)
410 EnterCriticalSection(&cancelConnLock);
414 PQfreeCancel(cancelConn);
419 LeaveCriticalSection(&cancelConnLock);
425 * on errors, print syntax error position if available.
427 * the query is expected to be in the client encoding.
430 ReportSyntaxErrorPosition(const PGresult *result, const char *query)
432 #define DISPLAY_SIZE 60 /* screen width limit, in screen cols */
433 #define MIN_RIGHT_CUT 10 /* try to keep this far away from EOL */
452 if (pset.verbosity == PQERRORS_TERSE)
455 sp = PQresultErrorField(result, PG_DIAG_STATEMENT_POSITION);
458 sp = PQresultErrorField(result, PG_DIAG_INTERNAL_POSITION);
460 return; /* no syntax error */
461 query = PQresultErrorField(result, PG_DIAG_INTERNAL_QUERY);
464 return; /* nothing to reference location to */
466 if (sscanf(sp, "%d", &loc) != 1)
468 psql_error("INTERNAL ERROR: unexpected statement position \"%s\"\n",
473 /* Make a writable copy of the query, and a buffer for messages. */
474 wquery = pg_strdup(query);
476 initPQExpBuffer(&msg);
479 * The returned cursor position is measured in logical characters. Each
480 * character might occupy multiple physical bytes in the string, and in
481 * some Far Eastern character sets it might take more than one screen
482 * column as well. We compute the starting byte offset and starting
483 * screen column of each logical character, and store these in qidx[] and
484 * scridx[] respectively.
487 /* we need a safe allocation size... */
488 slen = strlen(query) + 1;
490 qidx = (int *) pg_malloc(slen * sizeof(int));
491 scridx = (int *) pg_malloc(slen * sizeof(int));
495 for (i = 0; query[qoffset] != '\0'; i++)
498 scridx[i] = scroffset;
499 scroffset += PQdsplen(&query[qoffset], pset.encoding);
500 qoffset += PQmblen(&query[qoffset], pset.encoding);
503 scridx[i] = scroffset;
505 psql_assert(clen < slen);
507 /* convert loc to zero-based offset in qidx/scridx arrays */
510 /* do we have something to show? */
511 if (loc >= 0 && loc <= clen)
513 /* input line number of our syntax error. */
515 /* first included char of extract. */
517 /* last-plus-1 included char of extract. */
521 * Replace tabs with spaces in the writable copy. (Later we might
522 * want to think about coping with their variable screen width, but
525 * Extract line number and begin and end indexes of line containing error
526 * location. There will not be any newlines or carriage returns in
527 * the selected extract.
529 for (i = 0; i < clen; i++)
531 /* character length must be 1 or it's not ASCII */
532 if ((qidx[i + 1] - qidx[i]) == 1)
534 if (wquery[qidx[i]] == '\t')
535 wquery[qidx[i]] = ' ';
536 else if (wquery[qidx[i]] == '\r' || wquery[qidx[i]] == '\n')
541 * count lines before loc. Each \r or \n counts as a
542 * line except when \r \n appear together.
544 if (wquery[qidx[i]] == '\r' ||
546 (qidx[i] - qidx[i - 1]) != 1 ||
547 wquery[qidx[i - 1]] != '\r')
549 /* extract beginning = last line start before loc. */
554 /* set extract end. */
563 /* If the line extracted is too long, we truncate it. */
566 if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
569 * We first truncate right if it is enough. This code might be
570 * off a space or so on enforcing MIN_RIGHT_CUT if there's a wide
571 * character right there, but that should be okay.
573 if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT)
575 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
581 /* Truncate right if not too close to loc. */
582 while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend])
588 /* Truncate left if still too long. */
589 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
597 /* the extract MUST contain the target position! */
598 psql_assert(ibeg <= loc && loc <= iend);
600 /* truncate working copy at desired endpoint */
601 wquery[qidx[iend]] = '\0';
603 /* Begin building the finished message. */
604 printfPQExpBuffer(&msg, _("LINE %d: "), loc_line);
606 appendPQExpBufferStr(&msg, "...");
609 * While we have the prefix in the msg buffer, compute its screen
613 for (i = 0; i < msg.len; i += PQmblen(&msg.data[i], pset.encoding))
614 scroffset += PQdsplen(&msg.data[i], pset.encoding);
616 /* Finish and emit the message. */
617 appendPQExpBufferStr(&msg, &wquery[qidx[ibeg]]);
619 appendPQExpBufferStr(&msg, "...");
621 psql_error("%s\n", msg.data);
623 /* Now emit the cursor marker line. */
624 scroffset += scridx[loc] - scridx[ibeg];
625 resetPQExpBuffer(&msg);
626 for (i = 0; i < scroffset; i++)
627 appendPQExpBufferChar(&msg, ' ');
628 appendPQExpBufferChar(&msg, '^');
630 psql_error("%s\n", msg.data);
634 termPQExpBuffer(&msg);
645 * Checks whether a result is valid, giving an error message if necessary;
646 * resets cancelConn as needed, and ensures that the connection to the backend
649 * Returns true for valid result, false for error state.
652 AcceptResult(const PGresult *result, const char *query)
661 switch (PQresultStatus(result))
663 case PGRES_COMMAND_OK:
664 case PGRES_TUPLES_OK:
665 case PGRES_EMPTY_QUERY:
667 /* Fine, do nothing */
671 /* keep cancel connection for copy out state */
682 const char *error = PQerrorMessage(pset.db);
685 psql_error("%s", error);
687 ReportSyntaxErrorPosition(result, query);
699 * This is the way to send "backdoor" queries (those not directly entered
700 * by the user). It is subject to -E but not -e.
702 * In autocommit-off mode, a new transaction block is started if start_xact
703 * is true; nothing special is done when start_xact is false. Typically,
704 * start_xact = false is used for SELECTs and explicit BEGIN/COMMIT commands.
706 * Note: we don't bother to check PQclientEncoding; it is assumed that no
707 * caller uses this path to issue "SET CLIENT_ENCODING".
710 PSQLexec(const char *query, bool start_xact)
717 psql_error("You are currently not connected to a database.\n");
721 echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
722 if (echo_hidden != VAR_NOTSET)
724 printf(_("********* QUERY **********\n"
726 "**************************\n\n"), query);
730 fprintf(pset.logfile,
731 _("********* QUERY **********\n"
733 "**************************\n\n"), query);
734 fflush(pset.logfile);
737 if (echo_hidden == 1) /* noexec? */
743 if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
744 !GetVariableBool(pset.vars, "AUTOCOMMIT"))
746 res = PQexec(pset.db, "BEGIN");
747 if (PQresultStatus(res) != PGRES_COMMAND_OK)
749 psql_error("%s", PQerrorMessage(pset.db));
757 res = PQexec(pset.db, query);
759 if (!AcceptResult(res, query) && res)
771 * PrintNotifications: check for asynchronous notifications, and print them out
774 PrintNotifications(void)
778 while ((notify = PQnotifies(pset.db)))
780 fprintf(pset.queryFout, _("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
781 notify->relname, notify->be_pid);
782 fflush(pset.queryFout);
789 * PrintQueryTuples: assuming query result is OK, print its tuples
791 * Returns true if successful, false otherwise.
794 PrintQueryTuples(const PGresult *results)
796 printQueryOpt my_popt = pset.popt;
798 my_popt.topt.normal_query = true;
800 /* write output to \g argument, if any */
803 FILE *queryFout_copy = pset.queryFout;
804 bool queryFoutPipe_copy = pset.queryFoutPipe;
806 pset.queryFout = stdout; /* so it doesn't get closed */
809 if (!setQFout(pset.gfname))
811 pset.queryFout = queryFout_copy;
812 pset.queryFoutPipe = queryFoutPipe_copy;
816 printQuery(results, &my_popt, pset.queryFout, pset.logfile);
818 /* close file/pipe, restore old setting */
821 pset.queryFout = queryFout_copy;
822 pset.queryFoutPipe = queryFoutPipe_copy;
828 printQuery(results, &my_popt, pset.queryFout, pset.logfile);
835 * ProcessCopyResult: if command was a COPY FROM STDIN/TO STDOUT, handle it
837 * Note: Utility function for use by SendQuery() only.
839 * Returns true if the query executed successfully, false otherwise.
842 ProcessCopyResult(PGresult *results)
844 bool success = false;
849 switch (PQresultStatus(results))
851 case PGRES_TUPLES_OK:
852 case PGRES_COMMAND_OK:
853 case PGRES_EMPTY_QUERY:
854 /* nothing to do here */
859 success = handleCopyOut(pset.db, pset.queryFout);
863 success = handleCopyIn(pset.db, pset.cur_cmd_source);
870 /* may need this to recover from conn loss during COPY */
871 if (!CheckConnection())
879 * PrintQueryResults: print out query results as required
881 * Note: Utility function for use by SendQuery() only.
883 * Returns true if the query executed successfully, false otherwise.
886 PrintQueryResults(PGresult *results)
888 bool success = false;
893 switch (PQresultStatus(results))
895 case PGRES_TUPLES_OK:
896 success = PrintQueryTuples(results);
899 case PGRES_COMMAND_OK:
904 snprintf(buf, sizeof(buf),
905 "%u", (unsigned int) PQoidValue(results));
908 if (pset.popt.topt.format == PRINT_HTML)
910 fputs("<p>", pset.queryFout);
911 html_escaped_print(PQcmdStatus(results),
913 fputs("</p>\n", pset.queryFout);
916 fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
919 fprintf(pset.logfile, "%s\n", PQcmdStatus(results));
920 SetVariable(pset.vars, "LASTOID", buf);
924 case PGRES_EMPTY_QUERY:
930 /* nothing to do here */
938 fflush(pset.queryFout);
945 * SendQuery: send the query string to the backend
946 * (and print out results)
948 * Note: This is the "front door" way to send a query. That is, use it to
949 * send queries actually entered by the user. These queries will be subject to
951 * To send "back door" queries (generated by slash commands, etc.) in a
952 * controlled way, use PSQLexec().
954 * Returns true if the query executed successfully, false otherwise.
957 SendQuery(const char *query)
960 TimevalStruct before,
963 on_error_rollback_savepoint = false;
964 PGTransactionStatusType transaction_status;
965 static bool on_error_rollback_warning = false;
966 const char *rollback_str;
970 psql_error("You are currently not connected to a database.\n");
974 if (GetVariableBool(pset.vars, "SINGLESTEP"))
978 printf(_("***(Single step mode: verify command)*******************************************\n"
980 "***(press return to proceed or enter x and return to cancel)********************\n"),
983 if (fgets(buf, sizeof(buf), stdin) != NULL)
987 else if (VariableEquals(pset.vars, "ECHO", "queries"))
995 fprintf(pset.logfile,
996 _("********* QUERY **********\n"
998 "**************************\n\n"), query);
999 fflush(pset.logfile);
1004 transaction_status = PQtransactionStatus(pset.db);
1006 if (transaction_status == PQTRANS_IDLE &&
1007 !GetVariableBool(pset.vars, "AUTOCOMMIT") &&
1008 !command_no_begin(query))
1010 results = PQexec(pset.db, "BEGIN");
1011 if (PQresultStatus(results) != PGRES_COMMAND_OK)
1013 psql_error("%s", PQerrorMessage(pset.db));
1019 transaction_status = PQtransactionStatus(pset.db);
1022 if (transaction_status == PQTRANS_INTRANS &&
1023 (rollback_str = GetVariable(pset.vars, "ON_ERROR_ROLLBACK")) != NULL &&
1024 /* !off and !interactive is 'on' */
1025 pg_strcasecmp(rollback_str, "off") != 0 &&
1026 (pset.cur_cmd_interactive ||
1027 pg_strcasecmp(rollback_str, "interactive") != 0))
1029 if (on_error_rollback_warning == false && pset.sversion < 80000)
1031 fprintf(stderr, _("The server version (%d) does not support savepoints for ON_ERROR_ROLLBACK.\n"),
1033 on_error_rollback_warning = true;
1037 results = PQexec(pset.db, "SAVEPOINT pg_psql_temporary_savepoint");
1038 if (PQresultStatus(results) != PGRES_COMMAND_OK)
1040 psql_error("%s", PQerrorMessage(pset.db));
1046 on_error_rollback_savepoint = true;
1051 GETTIMEOFDAY(&before);
1053 results = PQexec(pset.db, query);
1055 /* these operations are included in the timing result: */
1056 OK = (AcceptResult(results, query) && ProcessCopyResult(results));
1059 GETTIMEOFDAY(&after);
1061 /* but printing results isn't: */
1063 OK = PrintQueryResults(results);
1067 /* If we made a temporary savepoint, possibly release/rollback */
1068 if (on_error_rollback_savepoint)
1070 transaction_status = PQtransactionStatus(pset.db);
1072 /* We always rollback on an error */
1073 if (transaction_status == PQTRANS_INERROR)
1074 results = PQexec(pset.db, "ROLLBACK TO pg_psql_temporary_savepoint");
1075 /* If they are no longer in a transaction, then do nothing */
1076 else if (transaction_status != PQTRANS_INTRANS)
1081 * Do nothing if they are messing with savepoints themselves: If
1082 * the user did RELEASE or ROLLBACK, our savepoint is gone. If
1083 * they issued a SAVEPOINT, releasing ours would remove theirs.
1085 if (strcmp(PQcmdStatus(results), "SAVEPOINT") == 0 ||
1086 strcmp(PQcmdStatus(results), "RELEASE") == 0 ||
1087 strcmp(PQcmdStatus(results), "ROLLBACK") == 0)
1090 results = PQexec(pset.db, "RELEASE pg_psql_temporary_savepoint");
1092 if (PQresultStatus(results) != PGRES_COMMAND_OK)
1094 psql_error("%s", PQerrorMessage(pset.db));
1102 /* Possible microtiming output */
1103 if (OK && pset.timing)
1104 printf(_("Time: %.3f ms\n"), DIFF_MSEC(&after, &before));
1106 /* check for events that may occur during query execution */
1108 if (pset.encoding != PQclientEncoding(pset.db) &&
1109 PQclientEncoding(pset.db) >= 0)
1111 /* track effects of SET CLIENT_ENCODING */
1112 pset.encoding = PQclientEncoding(pset.db);
1113 pset.popt.topt.encoding = pset.encoding;
1114 SetVariable(pset.vars, "ENCODING",
1115 pg_encoding_to_char(pset.encoding));
1118 PrintNotifications();
1125 * Advance the given char pointer over white space and SQL comments.
1128 skip_white_space(const char *query)
1130 int cnestlevel = 0; /* slash-star comment nest level */
1134 int mblen = PQmblen(query, pset.encoding);
1137 * Note: we assume the encoding is a superset of ASCII, so that for
1138 * example "query[0] == '/'" is meaningful. However, we do NOT assume
1139 * that the second and subsequent bytes of a multibyte character
1140 * couldn't look like ASCII characters; so it is critical to advance
1141 * by mblen, not 1, whenever we haven't exactly identified the
1142 * character we are skipping over.
1144 if (isspace((unsigned char) *query))
1146 else if (query[0] == '/' && query[1] == '*')
1151 else if (cnestlevel > 0 && query[0] == '*' && query[1] == '/')
1156 else if (cnestlevel == 0 && query[0] == '-' && query[1] == '-')
1161 * We have to skip to end of line since any slash-star inside the
1162 * -- comment does NOT start a slash-star comment.
1171 query += PQmblen(query, pset.encoding);
1174 else if (cnestlevel > 0)
1177 break; /* found first token */
1185 * Check whether a command is one of those for which we should NOT start
1186 * a new transaction block (ie, send a preceding BEGIN).
1188 * These include the transaction control statements themselves, plus
1189 * certain statements that the backend disallows inside transaction blocks.
1192 command_no_begin(const char *query)
1197 * First we must advance over any whitespace and comments.
1199 query = skip_white_space(query);
1202 * Check word length (since "beginx" is not "begin").
1205 while (isalpha((unsigned char) query[wordlen]))
1206 wordlen += PQmblen(&query[wordlen], pset.encoding);
1209 * Transaction control commands. These should include every keyword that
1210 * gives rise to a TransactionStmt in the backend grammar, except for the
1211 * savepoint-related commands.
1213 * (We assume that START must be START TRANSACTION, since there is presently
1214 * no other "START foo" command.)
1216 if (wordlen == 5 && pg_strncasecmp(query, "abort", 5) == 0)
1218 if (wordlen == 5 && pg_strncasecmp(query, "begin", 5) == 0)
1220 if (wordlen == 5 && pg_strncasecmp(query, "start", 5) == 0)
1222 if (wordlen == 6 && pg_strncasecmp(query, "commit", 6) == 0)
1224 if (wordlen == 3 && pg_strncasecmp(query, "end", 3) == 0)
1226 if (wordlen == 8 && pg_strncasecmp(query, "rollback", 8) == 0)
1228 if (wordlen == 7 && pg_strncasecmp(query, "prepare", 7) == 0)
1230 /* PREPARE TRANSACTION is a TC command, PREPARE foo is not */
1233 query = skip_white_space(query);
1236 while (isalpha((unsigned char) query[wordlen]))
1237 wordlen += PQmblen(&query[wordlen], pset.encoding);
1239 if (wordlen == 11 && pg_strncasecmp(query, "transaction", 11) == 0)
1245 * Commands not allowed within transactions. The statements checked for
1246 * here should be exactly those that call PreventTransactionChain() in the
1249 * Note: we are a bit sloppy about CLUSTER, which is transactional in some
1250 * variants but not others.
1252 if (wordlen == 6 && pg_strncasecmp(query, "vacuum", 6) == 0)
1254 if (wordlen == 7 && pg_strncasecmp(query, "cluster", 7) == 0)
1258 * Note: these tests will match CREATE SYSTEM, DROP SYSTEM, and REINDEX
1259 * TABLESPACE, which aren't really valid commands so we don't care much.
1260 * The other six possible matches are correct.
1262 if ((wordlen == 6 && pg_strncasecmp(query, "create", 6) == 0) ||
1263 (wordlen == 4 && pg_strncasecmp(query, "drop", 4) == 0) ||
1264 (wordlen == 7 && pg_strncasecmp(query, "reindex", 7) == 0))
1268 query = skip_white_space(query);
1271 while (isalpha((unsigned char) query[wordlen]))
1272 wordlen += PQmblen(&query[wordlen], pset.encoding);
1274 if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
1276 if (wordlen == 6 && pg_strncasecmp(query, "system", 6) == 0)
1278 if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
1287 * Test if the current user is a database superuser.
1289 * Note: this will correctly detect superuserness only with a protocol-3.0
1290 * or newer backend; otherwise it will always say "false".
1300 val = PQparameterStatus(pset.db, "is_superuser");
1302 if (val && strcmp(val, "on") == 0)
1310 * Return the session user of the current connection.
1312 * Note: this will correctly detect the session user only with a
1313 * protocol-3.0 or newer backend; otherwise it will return the
1317 session_username(void)
1324 val = PQparameterStatus(pset.db, "session_authorization");
1328 return PQuser(pset.db);
1334 * substitute '~' with HOME or '~username' with username's home dir
1338 expand_tilde(char **filename)
1340 if (!filename || !(*filename))
1344 * WIN32 doesn't use tilde expansion for file names. Also, it uses tilde
1345 * for short versions of long file names, though the tilde is usually
1346 * toward the end, not at the beginning.
1350 /* try tilde expansion */
1351 if (**filename == '~')
1357 char home[MAXPGPATH];
1363 while (*p != '/' && *p != '\0')
1369 if (*(fn + 1) == '\0')
1370 get_home_path(home); /* ~ or ~/ only */
1371 else if ((pw = getpwnam(fn + 1)) != NULL)
1372 StrNCpy(home, pw->pw_dir, MAXPGPATH); /* ~user */
1375 if (strlen(home) != 0)
1379 newfn = pg_malloc(strlen(home) + strlen(p) + 1);
1380 strcpy(newfn, home);