]> granicus.if.org Git - postgresql/blob - src/bin/psql/common.c
Invent a new, more thread-safe version of PQrequestCancel, called PQcancel.
[postgresql] / src / bin / psql / common.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2004, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.93 2004/10/30 23:10:50 tgl Exp $
7  */
8 #include "postgres_fe.h"
9 #include "common.h"
10
11 #include <ctype.h>
12 #ifndef HAVE_STRDUP
13 #include <strdup.h>
14 #endif
15 #include <signal.h>
16 #ifndef WIN32
17 #include <sys/time.h>
18 #include <unistd.h>                             /* for write() */
19 #include <setjmp.h>
20 #else
21 #include <io.h>                                 /* for _write() */
22 #include <win32.h>
23 #include <sys/timeb.h>                  /* for _ftime() */
24 #endif
25
26 #include "libpq-fe.h"
27 #include "pqsignal.h"
28
29 #include "settings.h"
30 #include "variables.h"
31 #include "command.h"
32 #include "copy.h"
33 #include "prompt.h"
34 #include "print.h"
35 #include "mainloop.h"
36 #include "mb/pg_wchar.h"
37
38
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.
42  */
43 #ifndef WIN32
44
45 typedef struct timeval TimevalStruct;
46
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)
51
52 #else
53
54 typedef struct _timeb TimevalStruct;
55
56 #define GETTIMEOFDAY(T) _ftime(T)
57 #define DIFF_MSEC(T, U) \
58         (((T)->time - (U)->time) * 1000.0 + \
59          ((T)->millitm - (U)->millitm))
60 #endif
61
62 extern bool prompt_state;
63
64
65 static bool command_no_begin(const char *query);
66
67
68 /*
69  * "Safe" wrapper around strdup()
70  */
71 char *
72 pg_strdup(const char *string)
73 {
74         char       *tmp;
75
76         if (!string)
77         {
78                 fprintf(stderr, gettext("%s: xstrdup: cannot duplicate null pointer (internal error)\n"),
79                                 pset.progname);
80                 exit(EXIT_FAILURE);
81         }
82         tmp = strdup(string);
83         if (!tmp)
84         {
85                 psql_error("out of memory\n");
86                 exit(EXIT_FAILURE);
87         }
88         return tmp;
89 }
90
91 void *
92 pg_malloc(size_t size)
93 {
94         void       *tmp;
95
96         tmp = malloc(size);
97         if (!tmp)
98         {
99                 psql_error("out of memory\n");
100                 exit(EXIT_FAILURE);
101         }
102         return tmp;
103 }
104
105 void *
106 pg_malloc_zero(size_t size)
107 {
108         void       *tmp;
109
110         tmp = pg_malloc(size);
111         memset(tmp, 0, size);
112         return tmp;
113 }
114
115 void *
116 pg_calloc(size_t nmemb, size_t size)
117 {
118         void       *tmp;
119
120         tmp = calloc(nmemb, size);
121         if (!tmp)
122         {
123                 psql_error("out of memory");
124                 exit(EXIT_FAILURE);
125         }
126         return tmp;
127 }
128
129 /*
130  * setQFout
131  * -- handler for -o command line option and \o command
132  *
133  * Tries to open file fname (or pipe if fname starts with '|')
134  * and stores the file handle in pset)
135  * Upon failure, sets stdout and returns false.
136  */
137 bool
138 setQFout(const char *fname)
139 {
140         bool            status = true;
141
142         /* Close old file/pipe */
143         if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
144         {
145                 if (pset.queryFoutPipe)
146                         pclose(pset.queryFout);
147                 else
148                         fclose(pset.queryFout);
149         }
150
151         /* If no filename, set stdout */
152         if (!fname || fname[0] == '\0')
153         {
154                 pset.queryFout = stdout;
155                 pset.queryFoutPipe = false;
156         }
157         else if (*fname == '|')
158         {
159                 pset.queryFout = popen(fname + 1, "w");
160                 pset.queryFoutPipe = true;
161         }
162         else
163         {
164                 pset.queryFout = fopen(fname, "w");
165                 pset.queryFoutPipe = false;
166         }
167
168         if (!(pset.queryFout))
169         {
170                 psql_error("%s: %s\n", fname, strerror(errno));
171                 pset.queryFout = stdout;
172                 pset.queryFoutPipe = false;
173                 status = false;
174         }
175
176         /* Direct signals */
177 #ifndef WIN32
178         pqsignal(SIGPIPE, pset.queryFoutPipe ? SIG_IGN : SIG_DFL);
179 #endif
180
181         return status;
182 }
183
184
185
186 /*
187  * Error reporting for scripts. Errors should look like
188  *       psql:filename:lineno: message
189  *
190  */
191 void
192 psql_error(const char *fmt,...)
193 {
194         va_list         ap;
195
196         fflush(stdout);
197         if (pset.queryFout != stdout)
198                 fflush(pset.queryFout);
199
200         if (pset.inputfile)
201                 fprintf(stderr, "%s:%s:%u: ", pset.progname, pset.inputfile, pset.lineno);
202         va_start(ap, fmt);
203         vfprintf(stderr, gettext(fmt), ap);
204         va_end(ap);
205 }
206
207
208
209 /*
210  * for backend Notice messages (INFO, WARNING, etc)
211  */
212 void
213 NoticeProcessor(void *arg, const char *message)
214 {
215         (void) arg;                                     /* not used */
216         psql_error("%s", message);
217 }
218
219
220
221 /*
222  * Code to support query cancellation
223  *
224  * Before we start a query, we enable a SIGINT signal catcher that sends a
225  * cancel request to the backend. Note that sending the cancel directly from
226  * the signal handler is safe because PQcancel() is written to make it
227  * so. We use write() to print to stderr because it's better to use simple
228  * facilities in a signal handler.
229  *
230  * On win32, the signal cancelling happens on a separate thread, because
231  * that's how SetConsoleCtrlHandler works. The PQcancel function is safe
232  * for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required
233  * to protect the PGcancel structure against being changed while the other
234  * thread is using it.
235  */
236 static PGcancel *cancelConn = NULL;
237 #ifdef WIN32
238 static CRITICAL_SECTION cancelConnLock;
239 #endif
240
241 volatile bool cancel_pressed = false;
242
243 #define write_stderr(str)       write(fileno(stderr), str, strlen(str))
244
245
246 #ifndef WIN32
247
248 void
249 handle_sigint(SIGNAL_ARGS)
250 {
251         int                     save_errno = errno;
252         char        errbuf[256];
253
254         /* Don't muck around if prompting for a password. */
255         if (prompt_state)
256                 return;
257
258         if (cancelConn == NULL)
259                 siglongjmp(main_loop_jmp, 1);
260
261         cancel_pressed = true;
262
263         if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
264                 write_stderr("Cancel request sent\n");
265         else
266         {
267                 write_stderr("Could not send cancel request: ");
268                 write_stderr(errbuf);
269         }
270         errno = save_errno;                     /* just in case the write changed it */
271 }
272
273 #else /* WIN32 */
274
275 static BOOL WINAPI
276 consoleHandler(DWORD dwCtrlType)
277 {
278         char        errbuf[256];
279
280         if (dwCtrlType == CTRL_C_EVENT ||
281                 dwCtrlType == CTRL_BREAK_EVENT)
282         {
283                 if (prompt_state)
284                         return TRUE;
285
286                 /* Perform query cancel */
287                 EnterCriticalSection(&cancelConnLock);
288                 if (cancelConn != NULL)
289                 {
290                         cancel_pressed = true;
291
292                         if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
293                                 write_stderr("Cancel request sent\n");
294                         else
295                         {
296                                 write_stderr("Could not send cancel request: ");
297                                 write_stderr(errbuf);
298                         }
299                 }
300                 LeaveCriticalSection(&cancelConnLock);
301
302                 return TRUE;
303         }
304         else
305                 /* Return FALSE for any signals not being handled */
306                 return FALSE;
307 }
308
309 void
310 setup_cancel_handler(void)
311 {
312         InitializeCriticalSection(&cancelConnLock);
313         SetConsoleCtrlHandler(consoleHandler, TRUE);
314 }
315
316 #endif /* WIN32 */
317
318
319 /* ConnectionUp
320  *
321  * Returns whether our backend connection is still there.
322  */
323 static bool
324 ConnectionUp(void)
325 {
326         return PQstatus(pset.db) != CONNECTION_BAD;
327 }
328
329
330
331 /* CheckConnection
332  *
333  * Verify that we still have a good connection to the backend, and if not,
334  * see if it can be restored.
335  *
336  * Returns true if either the connection was still there, or it could be
337  * restored successfully; false otherwise.      If, however, there was no
338  * connection and the session is non-interactive, this will exit the program
339  * with a code of EXIT_BADCONN.
340  */
341 static bool
342 CheckConnection(void)
343 {
344         bool            OK;
345
346         OK = ConnectionUp();
347         if (!OK)
348         {
349                 if (!pset.cur_cmd_interactive)
350                 {
351                         psql_error("connection to server was lost\n");
352                         exit(EXIT_BADCONN);
353                 }
354
355                 fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr);
356                 PQreset(pset.db);
357                 OK = ConnectionUp();
358                 if (!OK)
359                 {
360                         fputs(gettext("Failed.\n"), stderr);
361                         PQfinish(pset.db);
362                         pset.db = NULL;
363                         ResetCancelConn();
364                         UnsyncVariables();
365                 }
366                 else
367                         fputs(gettext("Succeeded.\n"), stderr);
368         }
369
370         return OK;
371 }
372
373
374
375 /*
376  * SetCancelConn
377  *
378  * Set cancelConn to point to the current database connection.
379  */
380 static void
381 SetCancelConn(void)
382 {
383 #ifdef WIN32
384         EnterCriticalSection(&cancelConnLock);
385 #endif
386
387         /* Free the old one if we have one */
388         if (cancelConn != NULL)
389                 PQfreeCancel(cancelConn);
390
391         cancelConn = PQgetCancel(pset.db);
392
393 #ifdef WIN32
394         LeaveCriticalSection(&cancelConnLock);
395 #endif
396 }
397
398
399 /*
400  * ResetCancelConn
401  *
402  * Free the current cancel connection, if any, and set to NULL.
403  */
404 void
405 ResetCancelConn(void)
406 {
407 #ifdef WIN32
408         EnterCriticalSection(&cancelConnLock);
409 #endif
410
411         if (cancelConn)
412                 PQfreeCancel(cancelConn);
413
414         cancelConn = NULL;
415
416 #ifdef WIN32
417         LeaveCriticalSection(&cancelConnLock);
418 #endif
419 }
420
421
422 /*
423  * on errors, print syntax error position if available.
424  *
425  * the query is expected to be in the client encoding.
426  */
427 static void
428 ReportSyntaxErrorPosition(const PGresult *result, const char *query)
429 {
430 #define DISPLAY_SIZE    60              /* screen width limit, in screen cols */
431 #define MIN_RIGHT_CUT   10              /* try to keep this far away from EOL */
432
433         int                     loc = 0;
434         const char *sp;
435         int                     clen,
436                                 slen,
437                                 i,
438                            *qidx,
439                            *scridx,
440                                 qoffset,
441                                 scroffset,
442                                 ibeg,
443                                 iend,
444                                 loc_line;
445         char       *wquery;
446         bool            beg_trunc,
447                                 end_trunc;
448         PQExpBufferData msg;
449
450         if (pset.verbosity == PQERRORS_TERSE)
451                 return;
452
453         sp = PQresultErrorField(result, PG_DIAG_STATEMENT_POSITION);
454         if (sp == NULL)
455         {
456                 sp = PQresultErrorField(result, PG_DIAG_INTERNAL_POSITION);
457                 if (sp == NULL)
458                         return;                         /* no syntax error */
459                 query = PQresultErrorField(result, PG_DIAG_INTERNAL_QUERY);
460         }
461         if (query == NULL)
462                 return;                                 /* nothing to reference location to */
463
464         if (sscanf(sp, "%d", &loc) != 1)
465         {
466                 psql_error("INTERNAL ERROR: unexpected statement position \"%s\"\n",
467                                    sp);
468                 return;
469         }
470
471         /* Make a writable copy of the query, and a buffer for messages. */
472         wquery = pg_strdup(query);
473
474         initPQExpBuffer(&msg);
475
476         /*
477          * The returned cursor position is measured in logical characters.
478          * Each character might occupy multiple physical bytes in the string,
479          * and in some Far Eastern character sets it might take more than one
480          * screen column as well.  We compute the starting byte offset and
481          * starting screen column of each logical character, and store these
482          * in qidx[] and scridx[] respectively.
483          */
484
485         /* we need a safe allocation size... */
486         slen = strlen(query) + 1;
487
488         qidx = (int *) pg_malloc(slen * sizeof(int));
489         scridx = (int *) pg_malloc(slen * sizeof(int));
490
491         qoffset = 0;
492         scroffset = 0;
493         for (i = 0; query[qoffset] != '\0'; i++)
494         {
495                 qidx[i] = qoffset;
496                 scridx[i] = scroffset;
497                 scroffset += PQdsplen(&query[qoffset], pset.encoding);
498                 qoffset += PQmblen(&query[qoffset], pset.encoding);
499         }
500         qidx[i] = qoffset;
501         scridx[i] = scroffset;
502         clen = i;
503         psql_assert(clen < slen);
504
505         /* convert loc to zero-based offset in qidx/scridx arrays */
506         loc--;
507
508         /* do we have something to show? */
509         if (loc >= 0 && loc <= clen)
510         {
511                 /* input line number of our syntax error. */
512                 loc_line = 1;
513                 /* first included char of extract. */
514                 ibeg = 0;
515                 /* last-plus-1 included char of extract. */
516                 iend = clen;
517
518                 /*
519                  * Replace tabs with spaces in the writable copy.  (Later we might
520                  * want to think about coping with their variable screen width,
521                  * but not today.)
522                  *
523                  * Extract line number and begin and end indexes of line containing
524                  * error location.      There will not be any newlines or carriage
525                  * returns in the selected extract.
526                  */
527                 for (i = 0; i < clen; i++)
528                 {
529                         /* character length must be 1 or it's not ASCII */
530                         if ((qidx[i + 1] - qidx[i]) == 1)
531                         {
532                                 if (wquery[qidx[i]] == '\t')
533                                         wquery[qidx[i]] = ' ';
534                                 else if (wquery[qidx[i]] == '\r' || wquery[qidx[i]] == '\n')
535                                 {
536                                         if (i < loc)
537                                         {
538                                                 /*
539                                                  * count lines before loc.      Each \r or \n counts
540                                                  * as a line except when \r \n appear together.
541                                                  */
542                                                 if (wquery[qidx[i]] == '\r' ||
543                                                         i == 0 ||
544                                                         (qidx[i] - qidx[i - 1]) != 1 ||
545                                                         wquery[qidx[i - 1]] != '\r')
546                                                         loc_line++;
547                                                 /* extract beginning = last line start before loc. */
548                                                 ibeg = i + 1;
549                                         }
550                                         else
551                                         {
552                                                 /* set extract end. */
553                                                 iend = i;
554                                                 /* done scanning. */
555                                                 break;
556                                         }
557                                 }
558                         }
559                 }
560
561                 /* If the line extracted is too long, we truncate it. */
562                 beg_trunc = false;
563                 end_trunc = false;
564                 if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
565                 {
566                         /*
567                          * We first truncate right if it is enough.  This code might
568                          * be off a space or so on enforcing MIN_RIGHT_CUT if there's
569                          * a wide character right there, but that should be okay.
570                          */
571                         if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT)
572                         {
573                                 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
574                                         iend--;
575                                 end_trunc = true;
576                         }
577                         else
578                         {
579                                 /* Truncate right if not too close to loc. */
580                                 while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend])
581                                 {
582                                         iend--;
583                                         end_trunc = true;
584                                 }
585
586                                 /* Truncate left if still too long. */
587                                 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
588                                 {
589                                         ibeg++;
590                                         beg_trunc = true;
591                                 }
592                         }
593                 }
594
595                 /* the extract MUST contain the target position! */
596                 psql_assert(ibeg <= loc && loc <= iend);
597
598                 /* truncate working copy at desired endpoint */
599                 wquery[qidx[iend]] = '\0';
600
601                 /* Begin building the finished message. */
602                 printfPQExpBuffer(&msg, gettext("LINE %d: "), loc_line);
603                 if (beg_trunc)
604                         appendPQExpBufferStr(&msg, "...");
605
606                 /*
607                  * While we have the prefix in the msg buffer, compute its screen
608                  * width.
609                  */
610                 scroffset = 0;
611                 for (i = 0; i < msg.len; i += PQmblen(&msg.data[i], pset.encoding))
612                         scroffset += PQdsplen(&msg.data[i], pset.encoding);
613
614                 /* Finish and emit the message. */
615                 appendPQExpBufferStr(&msg, &wquery[qidx[ibeg]]);
616                 if (end_trunc)
617                         appendPQExpBufferStr(&msg, "...");
618
619                 psql_error("%s\n", msg.data);
620
621                 /* Now emit the cursor marker line. */
622                 scroffset += scridx[loc] - scridx[ibeg];
623                 resetPQExpBuffer(&msg);
624                 for (i = 0; i < scroffset; i++)
625                         appendPQExpBufferChar(&msg, ' ');
626                 appendPQExpBufferChar(&msg, '^');
627
628                 psql_error("%s\n", msg.data);
629         }
630
631         /* Clean up. */
632         termPQExpBuffer(&msg);
633
634         free(wquery);
635         free(qidx);
636         free(scridx);
637 }
638
639
640 /*
641  * AcceptResult
642  *
643  * Checks whether a result is valid, giving an error message if necessary;
644  * resets cancelConn as needed, and ensures that the connection to the backend
645  * is still up.
646  *
647  * Returns true for valid result, false for error state.
648  */
649 static bool
650 AcceptResult(const PGresult *result, const char *query)
651 {
652         bool            OK = true;
653
654         ResetCancelConn();
655
656         if (!result)
657                 OK = false;
658         else
659                 switch (PQresultStatus(result))
660                 {
661                         case PGRES_COMMAND_OK:
662                         case PGRES_TUPLES_OK:
663                         case PGRES_EMPTY_QUERY:
664                         case PGRES_COPY_IN:
665                                 /* Fine, do nothing */
666                                 break;
667
668                         case PGRES_COPY_OUT:
669                                 /* keep cancel connection for copy out state */
670                                 SetCancelConn();
671                                 break;
672
673                         default:
674                                 OK = false;
675                                 break;
676                 }
677
678         if (!OK)
679         {
680                 psql_error("%s", PQerrorMessage(pset.db));
681                 ReportSyntaxErrorPosition(result, query);
682                 CheckConnection();
683         }
684
685         return OK;
686 }
687
688
689
690 /*
691  * PSQLexec
692  *
693  * This is the way to send "backdoor" queries (those not directly entered
694  * by the user). It is subject to -E but not -e.
695  *
696  * In autocommit-off mode, a new transaction block is started if start_xact
697  * is true; nothing special is done when start_xact is false.  Typically,
698  * start_xact = false is used for SELECTs and explicit BEGIN/COMMIT commands.
699  *
700  * Note: we don't bother to check PQclientEncoding; it is assumed that no
701  * caller uses this path to issue "SET CLIENT_ENCODING".
702  */
703 PGresult *
704 PSQLexec(const char *query, bool start_xact)
705 {
706         PGresult   *res;
707         int                     echo_hidden;
708
709         if (!pset.db)
710         {
711                 psql_error("You are currently not connected to a database.\n");
712                 return NULL;
713         }
714
715         echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
716         if (echo_hidden != VAR_NOTSET)
717         {
718                 printf("********* QUERY **********\n"
719                            "%s\n"
720                            "**************************\n\n", query);
721                 fflush(stdout);
722
723                 if (echo_hidden == 1)   /* noexec? */
724                         return NULL;
725         }
726
727         SetCancelConn();
728
729         if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
730                 !GetVariableBool(pset.vars, "AUTOCOMMIT"))
731         {
732                 res = PQexec(pset.db, "BEGIN");
733                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
734                 {
735                         psql_error("%s", PQerrorMessage(pset.db));
736                         PQclear(res);
737                         ResetCancelConn();
738                         return NULL;
739                 }
740                 PQclear(res);
741         }
742
743         res = PQexec(pset.db, query);
744
745         if (!AcceptResult(res, query) && res)
746         {
747                 PQclear(res);
748                 res = NULL;
749         }
750
751         return res;
752 }
753
754
755
756 /*
757  * PrintNotifications: check for asynchronous notifications, and print them out
758  */
759 static void
760 PrintNotifications(void)
761 {
762         PGnotify   *notify;
763
764         while ((notify = PQnotifies(pset.db)))
765         {
766                 fprintf(pset.queryFout, gettext("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
767                                 notify->relname, notify->be_pid);
768                 fflush(pset.queryFout);
769                 PQfreemem(notify);
770         }
771 }
772
773
774 /*
775  * PrintQueryTuples: assuming query result is OK, print its tuples
776  *
777  * Returns true if successful, false otherwise.
778  */
779 static bool
780 PrintQueryTuples(const PGresult *results)
781 {
782         /* write output to \g argument, if any */
783         if (pset.gfname)
784         {
785                 FILE       *queryFout_copy = pset.queryFout;
786                 bool            queryFoutPipe_copy = pset.queryFoutPipe;
787
788                 pset.queryFout = stdout;        /* so it doesn't get closed */
789
790                 /* open file/pipe */
791                 if (!setQFout(pset.gfname))
792                 {
793                         pset.queryFout = queryFout_copy;
794                         pset.queryFoutPipe = queryFoutPipe_copy;
795                         return false;
796                 }
797
798                 printQuery(results, &pset.popt, pset.queryFout);
799
800                 /* close file/pipe, restore old setting */
801                 setQFout(NULL);
802
803                 pset.queryFout = queryFout_copy;
804                 pset.queryFoutPipe = queryFoutPipe_copy;
805
806                 free(pset.gfname);
807                 pset.gfname = NULL;
808         }
809         else
810                 printQuery(results, &pset.popt, pset.queryFout);
811
812         return true;
813 }
814
815
816 /*
817  * ProcessCopyResult: if command was a COPY FROM STDIN/TO STDOUT, handle it
818  *
819  * Note: Utility function for use by SendQuery() only.
820  *
821  * Returns true if the query executed successfully, false otherwise.
822  */
823 static bool
824 ProcessCopyResult(PGresult *results)
825 {
826         bool            success = false;
827
828         if (!results)
829                 return false;
830
831         switch (PQresultStatus(results))
832         {
833                 case PGRES_TUPLES_OK:
834                 case PGRES_COMMAND_OK:
835                 case PGRES_EMPTY_QUERY:
836                         /* nothing to do here */
837                         success = true;
838                         break;
839
840                 case PGRES_COPY_OUT:
841                         success = handleCopyOut(pset.db, pset.queryFout);
842                         break;
843
844                 case PGRES_COPY_IN:
845                         success = handleCopyIn(pset.db, pset.cur_cmd_source);
846                         break;
847
848                 default:
849                         break;
850         }
851
852         /* may need this to recover from conn loss during COPY */
853         if (!CheckConnection())
854                 return false;
855
856         return success;
857 }
858
859
860 /*
861  * PrintQueryResults: print out query results as required
862  *
863  * Note: Utility function for use by SendQuery() only.
864  *
865  * Returns true if the query executed successfully, false otherwise.
866  */
867 static bool
868 PrintQueryResults(PGresult *results)
869 {
870         bool            success = false;
871
872         if (!results)
873                 return false;
874
875         switch (PQresultStatus(results))
876         {
877                 case PGRES_TUPLES_OK:
878                         success = PrintQueryTuples(results);
879                         break;
880
881                 case PGRES_COMMAND_OK:
882                         {
883                                 char            buf[10];
884
885                                 success = true;
886                                 snprintf(buf, sizeof(buf),
887                                                  "%u", (unsigned int) PQoidValue(results));
888                                 if (!QUIET())
889                                 {
890                                         if (pset.popt.topt.format == PRINT_HTML)
891                                         {
892                                                 fputs("<p>", pset.queryFout);
893                                                 html_escaped_print(PQcmdStatus(results),
894                                                                                    pset.queryFout);
895                                                 fputs("</p>\n", pset.queryFout);
896                                         }
897                                         else
898                                                 fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
899                                 }
900                                 SetVariable(pset.vars, "LASTOID", buf);
901                                 break;
902                         }
903
904                 case PGRES_EMPTY_QUERY:
905                         success = true;
906                         break;
907
908                 case PGRES_COPY_OUT:
909                 case PGRES_COPY_IN:
910                         /* nothing to do here */
911                         success = true;
912                         break;
913
914                 default:
915                         break;
916         }
917
918         fflush(pset.queryFout);
919
920         return success;
921 }
922
923
924 /*
925  * SendQuery: send the query string to the backend
926  * (and print out results)
927  *
928  * Note: This is the "front door" way to send a query. That is, use it to
929  * send queries actually entered by the user. These queries will be subject to
930  * single step mode.
931  * To send "back door" queries (generated by slash commands, etc.) in a
932  * controlled way, use PSQLexec().
933  *
934  * Returns true if the query executed successfully, false otherwise.
935  */
936 bool
937 SendQuery(const char *query)
938 {
939         PGresult   *results;
940         TimevalStruct before,
941                                 after;
942         bool            OK;
943
944         if (!pset.db)
945         {
946                 psql_error("You are currently not connected to a database.\n");
947                 return false;
948         }
949
950         if (GetVariableBool(pset.vars, "SINGLESTEP"))
951         {
952                 char            buf[3];
953
954                 printf(gettext("***(Single step mode: verify command)*******************************************\n"
955                                            "%s\n"
956                                            "***(press return to proceed or enter x and return to cancel)********************\n"),
957                            query);
958                 fflush(stdout);
959                 if (fgets(buf, sizeof(buf), stdin) != NULL)
960                         if (buf[0] == 'x')
961                                 return false;
962         }
963         else if (VariableEquals(pset.vars, "ECHO", "queries"))
964         {
965                 puts(query);
966                 fflush(stdout);
967         }
968
969         SetCancelConn();
970
971         if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
972                 !GetVariableBool(pset.vars, "AUTOCOMMIT") &&
973                 !command_no_begin(query))
974         {
975                 results = PQexec(pset.db, "BEGIN");
976                 if (PQresultStatus(results) != PGRES_COMMAND_OK)
977                 {
978                         psql_error("%s", PQerrorMessage(pset.db));
979                         PQclear(results);
980                         ResetCancelConn();
981                         return false;
982                 }
983                 PQclear(results);
984         }
985
986         if (pset.timing)
987                 GETTIMEOFDAY(&before);
988
989         results = PQexec(pset.db, query);
990
991         /* these operations are included in the timing result: */
992         OK = (AcceptResult(results, query) && ProcessCopyResult(results));
993
994         if (pset.timing)
995                 GETTIMEOFDAY(&after);
996
997         /* but printing results isn't: */
998         if (OK)
999                 OK = PrintQueryResults(results);
1000
1001         PQclear(results);
1002
1003         /* Possible microtiming output */
1004         if (OK && pset.timing)
1005                 printf(gettext("Time: %.3f ms\n"), DIFF_MSEC(&after, &before));
1006
1007         /* check for events that may occur during query execution */
1008
1009         if (pset.encoding != PQclientEncoding(pset.db) &&
1010                 PQclientEncoding(pset.db) >= 0)
1011         {
1012                 /* track effects of SET CLIENT_ENCODING */
1013                 pset.encoding = PQclientEncoding(pset.db);
1014                 pset.popt.topt.encoding = pset.encoding;
1015                 SetVariable(pset.vars, "ENCODING",
1016                                         pg_encoding_to_char(pset.encoding));
1017         }
1018
1019         PrintNotifications();
1020
1021         return OK;
1022 }
1023
1024
1025 /*
1026  * Advance the given char pointer over white space and SQL comments.
1027  */
1028 static const char *
1029 skip_white_space(const char *query)
1030 {
1031         int                     cnestlevel = 0;         /* slash-star comment nest level */
1032
1033         while (*query)
1034         {
1035                 int             mblen = PQmblen(query, pset.encoding);
1036
1037                 /*
1038                  * Note: we assume the encoding is a superset of ASCII, so that
1039                  * for example "query[0] == '/'" is meaningful.  However, we do NOT
1040                  * assume that the second and subsequent bytes of a multibyte
1041                  * character couldn't look like ASCII characters; so it is critical
1042                  * to advance by mblen, not 1, whenever we haven't exactly identified
1043                  * the character we are skipping over.
1044                  */
1045                 if (isspace((unsigned char) *query))
1046                         query += mblen;
1047                 else if (query[0] == '/' && query[1] == '*')
1048                 {
1049                         cnestlevel++;
1050                         query += 2;
1051                 }
1052                 else if (cnestlevel > 0 && query[0] == '*' && query[1] == '/')
1053                 {
1054                         cnestlevel--;
1055                         query += 2;
1056                 }
1057                 else if (cnestlevel == 0 && query[0] == '-' && query[1] == '-')
1058                 {
1059                         query += 2;
1060                         /*
1061                          * We have to skip to end of line since any slash-star inside
1062                          * the -- comment does NOT start a slash-star comment.
1063                          */
1064                         while (*query)
1065                         {
1066                                 if (*query == '\n')
1067                                 {
1068                                         query++;
1069                                         break;
1070                                 }
1071                                 query += PQmblen(query, pset.encoding);
1072                         }
1073                 }
1074                 else if (cnestlevel > 0)
1075                         query += mblen;
1076                 else
1077                         break;                          /* found first token */
1078         }
1079
1080         return query;
1081 }
1082
1083
1084 /*
1085  * Check whether a command is one of those for which we should NOT start
1086  * a new transaction block (ie, send a preceding BEGIN).
1087  *
1088  * These include the transaction control statements themselves, plus
1089  * certain statements that the backend disallows inside transaction blocks.
1090  */
1091 static bool
1092 command_no_begin(const char *query)
1093 {
1094         int                     wordlen;
1095
1096         /*
1097          * First we must advance over any whitespace and comments.
1098          */
1099         query = skip_white_space(query);
1100
1101         /*
1102          * Check word length (since "beginx" is not "begin").
1103          */
1104         wordlen = 0;
1105         while (isalpha((unsigned char) query[wordlen]))
1106                 wordlen += PQmblen(&query[wordlen], pset.encoding);
1107
1108         /*
1109          * Transaction control commands.  These should include every keyword
1110          * that gives rise to a TransactionStmt in the backend grammar, except
1111          * for the savepoint-related commands.
1112          *
1113          * (We assume that START must be START TRANSACTION, since there is 
1114          * presently no other "START foo" command.)
1115          */
1116         if (wordlen == 5 && pg_strncasecmp(query, "abort", 5) == 0)
1117                 return true;
1118         if (wordlen == 5 && pg_strncasecmp(query, "begin", 5) == 0)
1119                 return true;
1120         if (wordlen == 5 && pg_strncasecmp(query, "start", 5) == 0)
1121                 return true;
1122         if (wordlen == 6 && pg_strncasecmp(query, "commit", 6) == 0)
1123                 return true;
1124         if (wordlen == 3 && pg_strncasecmp(query, "end", 3) == 0)
1125                 return true;
1126         if (wordlen == 8 && pg_strncasecmp(query, "rollback", 8) == 0)
1127                 return true;
1128
1129         /*
1130          * Commands not allowed within transactions.  The statements checked
1131          * for here should be exactly those that call PreventTransactionChain()
1132          * in the backend.
1133          *
1134          * Note: we are a bit sloppy about CLUSTER, which is transactional in
1135          * some variants but not others.
1136          */
1137         if (wordlen == 6 && pg_strncasecmp(query, "vacuum", 6) == 0)
1138                 return true;
1139         if (wordlen == 7 && pg_strncasecmp(query, "cluster", 7) == 0)
1140                 return true;
1141
1142         /*
1143          * Note: these tests will match REINDEX TABLESPACE, which isn't really
1144          * a valid command so we don't care much.  The other five possible
1145          * matches are correct.
1146          */
1147         if ((wordlen == 6 && pg_strncasecmp(query, "create", 6) == 0) ||
1148                 (wordlen == 4 && pg_strncasecmp(query, "drop", 4) == 0) ||
1149                 (wordlen == 7 && pg_strncasecmp(query, "reindex", 7) == 0))
1150         {
1151                 query += wordlen;
1152
1153                 query = skip_white_space(query);
1154
1155                 wordlen = 0;
1156                 while (isalpha((unsigned char) query[wordlen]))
1157                         wordlen += PQmblen(&query[wordlen], pset.encoding);
1158
1159                 if (wordlen == 8 && pg_strncasecmp(query, "database", 8) == 0)
1160                         return true;
1161                 if (wordlen == 10 && pg_strncasecmp(query, "tablespace", 10) == 0)
1162                         return true;
1163         }
1164
1165         return false;
1166 }
1167
1168
1169 char
1170 parse_char(char **buf)
1171 {
1172         long            l;
1173
1174         l = strtol(*buf, buf, 0);
1175         --*buf;
1176         return (char) l;
1177 }
1178
1179
1180 /*
1181  * Test if the current user is a database superuser.
1182  *
1183  * Note: this will correctly detect superuserness only with a protocol-3.0
1184  * or newer backend; otherwise it will always say "false".
1185  */
1186 bool
1187 is_superuser(void)
1188 {
1189         const char *val;
1190
1191         if (!pset.db)
1192                 return false;
1193
1194         val = PQparameterStatus(pset.db, "is_superuser");
1195
1196         if (val && strcmp(val, "on") == 0)
1197                 return true;
1198
1199         return false;
1200 }
1201
1202
1203 /*
1204  * Return the session user of the current connection.
1205  *
1206  * Note: this will correctly detect the session user only with a
1207  * protocol-3.0 or newer backend; otherwise it will return the
1208  * connection user.
1209  */
1210 const char *
1211 session_username(void)
1212 {
1213         const char *val;
1214
1215         if (!pset.db)
1216                 return NULL;
1217
1218         val = PQparameterStatus(pset.db, "session_authorization");
1219         if (val)
1220                 return val;
1221         else
1222                 return PQuser(pset.db);
1223 }
1224
1225
1226 /* expand_tilde
1227  *
1228  * substitute '~' with HOME or '~username' with username's home dir
1229  *
1230  */
1231 char *
1232 expand_tilde(char **filename)
1233 {
1234         if (!filename || !(*filename))
1235                 return NULL;
1236
1237         /* MSDOS uses tilde for short versions of long file names, so skip it. */
1238 #ifndef WIN32
1239
1240         /* try tilde expansion */
1241         if (**filename == '~')
1242         {
1243                 char       *fn;
1244                 char            oldp,
1245                                    *p;
1246                 struct passwd *pw;
1247                 char            home[MAXPGPATH];
1248
1249                 fn = *filename;
1250                 *home = '\0';
1251
1252                 p = fn + 1;
1253                 while (*p != '/' && *p != '\0')
1254                         p++;
1255
1256                 oldp = *p;
1257                 *p = '\0';
1258
1259                 if (*(fn + 1) == '\0')
1260                         get_home_path(home);
1261                 else if ((pw = getpwnam(fn + 1)) != NULL)
1262                         StrNCpy(home, pw->pw_dir, MAXPGPATH);
1263
1264                 *p = oldp;
1265                 if (strlen(home) != 0)
1266                 {
1267                         char       *newfn;
1268
1269                         newfn = pg_malloc(strlen(home) + strlen(p) + 1);
1270                         strcpy(newfn, home);
1271                         strcat(newfn, p);
1272
1273                         free(fn);
1274                         *filename = newfn;
1275                 }
1276         }
1277 #endif
1278
1279         return *filename;
1280 }