]> granicus.if.org Git - postgresql/blob - src/bin/psql/common.c
Add fflush of stdout when outputing query.
[postgresql] / src / bin / psql / common.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright 2000 by PostgreSQL Global Development Group
5  *
6  * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.67 2003/07/31 04:23:40 momjian Exp $
7  */
8 #include "postgres_fe.h"
9 #include "common.h"
10
11 #include <ctype.h>
12 #include <errno.h>
13 #include <stdarg.h>
14 #ifndef HAVE_STRDUP
15 #include <strdup.h>
16 #endif
17 #include <signal.h>
18 #ifndef WIN32
19 #include <sys/time.h>
20 #include <unistd.h>                             /* for write() */
21 #include <setjmp.h>
22 #else
23 #include <io.h>                                 /* for _write() */
24 #include <win32.h>
25 #include <sys/timeb.h>                  /* for _ftime() */
26 #endif
27
28 #include "libpq-fe.h"
29 #include "pqsignal.h"
30
31 #include "settings.h"
32 #include "variables.h"
33 #include "command.h"
34 #include "copy.h"
35 #include "prompt.h"
36 #include "print.h"
37 #include "mainloop.h"
38
39
40 /* Workarounds for Windows */
41 /* Probably to be moved up the source tree in the future, perhaps to be replaced by
42  * more specific checks like configure-style HAVE_GETTIMEOFDAY macros.
43  */
44 #ifndef WIN32
45
46 typedef struct timeval TimevalStruct;
47 #define GETTIMEOFDAY(T) gettimeofday(T, NULL)
48 #define DIFF_MSEC(T, U) ((((T)->tv_sec - (U)->tv_sec) * 1000000.0 + (T)->tv_usec - (U)->tv_usec) / 1000.0)
49
50 #else
51
52 typedef struct _timeb TimevalStruct;
53 #define GETTIMEOFDAY(T) _ftime(T)
54 #define DIFF_MSEC(T, U) ((((T)->time - (U)->time) * 1000.0 + (T)->millitm - (U)->millitm))
55
56 #endif
57
58 extern bool prompt_state;
59
60
61 static bool is_transact_command(const char *query);
62
63
64 /*
65  * "Safe" wrapper around strdup()
66  */
67 char *
68 xstrdup(const char *string)
69 {
70         char       *tmp;
71
72         if (!string)
73         {
74                 fprintf(stderr, gettext("%s: xstrdup: cannot duplicate null pointer (internal error)\n"),
75                                 pset.progname);
76                 exit(EXIT_FAILURE);
77         }
78         tmp = strdup(string);
79         if (!tmp)
80         {
81                 psql_error("out of memory\n");
82                 exit(EXIT_FAILURE);
83         }
84         return tmp;
85 }
86
87
88
89 /*
90  * setQFout
91  * -- handler for -o command line option and \o command
92  *
93  * Tries to open file fname (or pipe if fname starts with '|')
94  * and stores the file handle in pset)
95  * Upon failure, sets stdout and returns false.
96  */
97 bool
98 setQFout(const char *fname)
99 {
100         bool            status = true;
101
102         /* Close old file/pipe */
103         if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
104         {
105                 if (pset.queryFoutPipe)
106                         pclose(pset.queryFout);
107                 else
108                         fclose(pset.queryFout);
109         }
110
111         /* If no filename, set stdout */
112         if (!fname || fname[0] == '\0')
113         {
114                 pset.queryFout = stdout;
115                 pset.queryFoutPipe = false;
116         }
117         else if (*fname == '|')
118         {
119                 pset.queryFout = popen(fname + 1, "w");
120                 pset.queryFoutPipe = true;
121         }
122         else
123         {
124                 pset.queryFout = fopen(fname, "w");
125                 pset.queryFoutPipe = false;
126         }
127
128         if (!(pset.queryFout))
129         {
130                 psql_error("%s: %s\n", fname, strerror(errno));
131                 pset.queryFout = stdout;
132                 pset.queryFoutPipe = false;
133                 status = false;
134         }
135
136         /* Direct signals */
137 #ifndef WIN32
138         pqsignal(SIGPIPE, pset.queryFoutPipe ? SIG_IGN : SIG_DFL);
139 #endif
140
141         return status;
142 }
143
144
145
146 /*
147  * Error reporting for scripts. Errors should look like
148  *       psql:filename:lineno: message
149  *
150  */
151 void
152 psql_error(const char *fmt,...)
153 {
154         va_list         ap;
155
156         fflush(stdout);
157         if (pset.queryFout != stdout)
158                 fflush(pset.queryFout);
159
160         if (pset.inputfile)
161                 fprintf(stderr, "%s:%s:%u: ", pset.progname, pset.inputfile, pset.lineno);
162         va_start(ap, fmt);
163         vfprintf(stderr, gettext(fmt), ap);
164         va_end(ap);
165 }
166
167
168
169 /*
170  * for backend Notice messages (INFO, WARNING, etc)
171  */
172 void
173 NoticeProcessor(void *arg, const char *message)
174 {
175         (void) arg;                                     /* not used */
176         psql_error("%s", message);
177 }
178
179
180
181 /*
182  * Code to support query cancellation
183  *
184  * Before we start a query, we enable a SIGINT signal catcher that sends a
185  * cancel request to the backend. Note that sending the cancel directly from
186  * the signal handler is safe because PQrequestCancel() is written to make it
187  * so. We use write() to print to stdout because it's better to use simple
188  * facilities in a signal handler.
189  */
190 static PGconn      *volatile cancelConn = NULL;
191
192 volatile bool cancel_pressed = false;
193
194
195 #ifndef WIN32
196
197 #define write_stderr(String) write(fileno(stderr), String, strlen(String))
198
199 void
200 handle_sigint(SIGNAL_ARGS)
201 {
202         int                     save_errno = errno;
203
204         /* Don't muck around if prompting for a password. */
205         if (prompt_state)
206                 return;
207
208         if (cancelConn == NULL)
209                 siglongjmp(main_loop_jmp, 1);
210
211         cancel_pressed = true;
212
213         if (PQrequestCancel(cancelConn))
214                 write_stderr("Cancel request sent\n");
215         else
216         {
217                 write_stderr("Could not send cancel request: ");
218                 write_stderr(PQerrorMessage(cancelConn));
219         }
220         errno = save_errno;                     /* just in case the write changed it */
221 }
222 #endif   /* not WIN32 */
223
224
225
226 /* ConnectionUp
227  *
228  * Returns whether our backend connection is still there.
229  */
230 static bool 
231 ConnectionUp()
232 {
233         return PQstatus(pset.db) != CONNECTION_BAD;
234 }
235
236
237
238 /* CheckConnection
239  *
240  * Verify that we still have a good connection to the backend, and if not,
241  * see if it can be restored.
242  *
243  * Returns true if either the connection was still there, or it could be
244  * restored successfully; false otherwise.  If, however, there was no
245  * connection and the session is non-interactive, this will exit the program
246  * with a code of EXIT_BADCONN.
247  */
248 static bool
249 CheckConnection()
250 {
251         bool OK;
252         
253         OK = ConnectionUp();
254         if (!OK)
255         {
256                 if (!pset.cur_cmd_interactive)
257                 {
258                         psql_error("connection to server was lost\n");
259                         exit(EXIT_BADCONN);
260                 }
261
262                 fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr);
263                 PQreset(pset.db);
264                 OK = ConnectionUp();
265                 if (!OK)
266                 {
267                         fputs(gettext("Failed.\n"), stderr);
268                         PQfinish(pset.db);
269                         pset.db = NULL;
270                         ResetCancelConn();
271                         UnsyncVariables();
272                 }
273                 else
274                         fputs(gettext("Succeeded.\n"), stderr);
275         }
276
277         return OK;
278 }
279
280
281
282 /*
283  * SetCancelConn
284  *
285  * Set cancelConn to point to the current database connection.
286  */
287 static void SetCancelConn(void)
288 {
289   cancelConn = pset.db;
290 }
291
292
293 /*
294  * ResetCancelConn
295  *
296  * Set cancelConn to NULL.  I don't know what this means exactly, but it saves
297  * having to export the variable.
298  */
299 void ResetCancelConn(void)
300 {
301   cancelConn = NULL;
302 }
303
304
305 /*
306  * AcceptResult
307  *
308  * Checks whether a result is valid, giving an error message if necessary;
309  * resets cancelConn as needed, and ensures that the connection to the backend
310  * is still up.
311  *
312  * Returns true for valid result, false for error state.
313  */
314 static bool
315 AcceptResult(const PGresult *result)
316 {
317         bool OK = true;
318
319         ResetCancelConn();
320
321         if (!result)
322         {
323           OK = false;
324         }
325         else switch (PQresultStatus(result))
326         {
327           case PGRES_COMMAND_OK:
328           case PGRES_TUPLES_OK:
329           case PGRES_COPY_IN:
330                  /* Fine, do nothing */
331                  break;
332
333           case PGRES_COPY_OUT:
334                  /* keep cancel connection for copy out state */
335                  SetCancelConn();
336                  break;
337
338           default:
339                  OK = false;
340                  break;
341         }
342
343         if (!OK) 
344         {
345                 CheckConnection();
346                 psql_error("%s", PQerrorMessage(pset.db));
347         }
348
349         return OK;
350 }
351
352
353
354 /*
355  * PSQLexec
356  *
357  * This is the way to send "backdoor" queries (those not directly entered
358  * by the user). It is subject to -E but not -e.
359  *
360  * In autocommit-off mode, a new transaction block is started if start_xact
361  * is true; nothing special is done when start_xact is false.  Typically,
362  * start_xact = false is used for SELECTs and explicit BEGIN/COMMIT commands.
363  */
364 PGresult *
365 PSQLexec(const char *query, bool start_xact)
366 {
367         PGresult   *res;
368         int     echo_hidden;
369
370         if (!pset.db)
371         {
372                 psql_error("You are currently not connected to a database.\n");
373                 return NULL;
374         }
375
376         echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
377         if (echo_hidden != VAR_NOTSET)
378         {
379                 printf("********* QUERY **********\n"
380                            "%s\n"
381                            "**************************\n\n", query);
382                 fflush(stdout);
383
384                 if (echo_hidden == 1)   /* noexec? */
385                         return NULL;
386         }
387
388         SetCancelConn();
389
390         if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
391                 !GetVariableBool(pset.vars, "AUTOCOMMIT"))
392         {
393                 res = PQexec(pset.db, "BEGIN");
394                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
395                 {
396                         psql_error("%s", PQerrorMessage(pset.db));
397                         PQclear(res);
398                         ResetCancelConn();
399                         return NULL;
400                 }
401                 PQclear(res);
402         }
403
404         res = PQexec(pset.db, query);
405
406         if (!AcceptResult(res) && res)
407         {
408                 PQclear(res);
409                 res = NULL;
410         }
411
412         return res;
413 }
414
415
416
417 /*
418  * PrintNotifications: check for asynchronous notifications, and print them out
419  *
420  */
421 static void
422 PrintNotifications(void)
423 {
424         PGnotify   *notify;
425
426         while ((notify = PQnotifies(pset.db)))
427         {
428                 fprintf(pset.queryFout, gettext("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
429                                 notify->relname, notify->be_pid);
430                 PQfreemem(notify);
431                 fflush(pset.queryFout);
432         }
433 }
434
435
436 /*
437  * PrintQueryTuples: assuming query result is OK, print its tuples
438  *
439  * Returns true if successful, false otherwise.
440  */
441 static bool 
442 PrintQueryTuples(const PGresult *results)
443 {
444                                 /* write output to \g argument, if any */
445                                 if (pset.gfname)
446                                 {
447                                         FILE       *queryFout_copy = pset.queryFout;
448                                         bool            queryFoutPipe_copy = pset.queryFoutPipe;
449
450                                         pset.queryFout = stdout;        /* so it doesn't get
451                                                                                                  * closed */
452
453                                         /* open file/pipe */
454                                         if (!setQFout(pset.gfname))
455                                         {
456                                                 pset.queryFout = queryFout_copy;
457                                                 pset.queryFoutPipe = queryFoutPipe_copy;
458                         return false;
459                                         }
460
461                                         printQuery(results, &pset.popt, pset.queryFout);
462
463                                         /* close file/pipe, restore old setting */
464                                         setQFout(NULL);
465
466                                         pset.queryFout = queryFout_copy;
467                                         pset.queryFoutPipe = queryFoutPipe_copy;
468
469                                         free(pset.gfname);
470                                         pset.gfname = NULL;
471                                 }
472                                 else
473                                 {
474                                         printQuery(results, &pset.popt, pset.queryFout);
475                                 }
476
477         return true;
478 }
479
480
481
482 /*
483  * PrintQueryResults: analyze query results and print them out
484  *
485  * Note: Utility function for use by SendQuery() only.
486  *
487  * Returns true if the query executed successfully, false otherwise.
488  */
489 static bool
490 PrintQueryResults(PGresult *results, 
491                 const TimevalStruct *before, 
492                 const TimevalStruct *after)
493 {
494         bool    success = false;
495
496         if (!results) 
497           return false;
498
499         switch (PQresultStatus(results))
500         {
501                 case PGRES_TUPLES_OK:
502                         success = PrintQueryTuples(results);
503                                 break;
504                         case PGRES_EMPTY_QUERY:
505                                 success = true;
506                                 break;
507                         case PGRES_COMMAND_OK:
508                                 {
509                                         char            buf[10];
510
511                                         success = true;
512                                         sprintf(buf, "%u", (unsigned int) PQoidValue(results));
513                                         if (!QUIET())
514                                                 {
515                                                         if (pset.popt.topt.format == PRINT_HTML)
516                                                         {
517                                                                 fputs("<p>", pset.queryFout);
518                                                                 html_escaped_print(PQcmdStatus(results), pset.queryFout);
519                                                                 fputs("</p>\n", pset.queryFout);
520                                                         }
521                                                         else
522                                                         {
523                                                                 fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
524                                                         }
525                                                 }
526                                         SetVariable(pset.vars, "LASTOID", buf);
527                                         break;
528                                 }
529                         case PGRES_COPY_OUT:
530                                 success = handleCopyOut(pset.db, pset.queryFout);
531                                 break;
532
533                         case PGRES_COPY_IN:
534                                 if (pset.cur_cmd_interactive && !QUIET())
535                                         puts(gettext("Enter data to be copied followed by a newline.\n"
536                                                                  "End with a backslash and a period on a line by itself."));
537
538                                 success = handleCopyIn(pset.db, pset.cur_cmd_source,
539                                                                            pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL);
540                                 break;
541
542                 default:
543                                 break;
544                 }
545
546                 fflush(pset.queryFout);
547
548         if (!CheckConnection()) return false;
549
550         /* Possible microtiming output */
551         if (pset.timing && success)
552                 printf(gettext("Time: %.2f ms\n"), DIFF_MSEC(after, before));
553
554         return success;
555 }
556
557
558
559 /*
560  * SendQuery: send the query string to the backend
561  * (and print out results)
562  *
563  * Note: This is the "front door" way to send a query. That is, use it to
564  * send queries actually entered by the user. These queries will be subject to
565  * single step mode.
566  * To send "back door" queries (generated by slash commands, etc.) in a
567  * controlled way, use PSQLexec().
568  *
569  * Returns true if the query executed successfully, false otherwise.
570  */
571 bool
572 SendQuery(const char *query)
573 {
574         PGresult   *results;
575         TimevalStruct before, after;
576         bool OK;
577
578         if (!pset.db)
579         {
580                 psql_error("You are currently not connected to a database.\n");
581                 return false;
582         }
583
584         if (GetVariableBool(pset.vars, "SINGLESTEP"))
585         {
586                 char            buf[3];
587
588                 printf(gettext("***(Single step mode: verify command)*******************************************\n"
589                                            "%s\n"
590                                            "***(press return to proceed or enter x and return to cancel)********************\n"),
591                            query);
592                 fflush(stdout);
593                 if (fgets(buf, sizeof(buf), stdin) != NULL)
594                         if (buf[0] == 'x')
595                                 return false;
596         }
597         else if (VariableEquals(pset.vars, "ECHO", "queries"))
598         {
599                 puts(query);
600                 fflush(stdout);
601         }
602         
603         SetCancelConn();
604
605         if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
606                 !GetVariableBool(pset.vars, "AUTOCOMMIT") &&
607                 !is_transact_command(query))
608         {
609                 results = PQexec(pset.db, "BEGIN");
610                 if (PQresultStatus(results) != PGRES_COMMAND_OK)
611                 {
612                         psql_error("%s", PQerrorMessage(pset.db));
613                         PQclear(results);
614                         ResetCancelConn();
615                         return false;
616                 }
617                 PQclear(results);
618         }
619
620         if (pset.timing)
621                 GETTIMEOFDAY(&before);
622         results = PQexec(pset.db, query);
623         if (pset.timing)
624                 GETTIMEOFDAY(&after);
625
626         OK = (AcceptResult(results) && PrintQueryResults(results, &before, &after));
627         PQclear(results);
628
629         PrintNotifications();
630         return OK;
631 }
632
633 /*
634  * check whether a query string begins with BEGIN/COMMIT/ROLLBACK/START XACT
635  */
636 static bool
637 is_transact_command(const char *query)
638 {
639         int             wordlen;
640
641         /*
642          * First we must advance over any whitespace and comments.
643          */
644         while (*query)
645         {
646                 if (isspace((unsigned char) *query))
647                         query++;
648                 else if (query[0] == '-' && query[1] == '-')
649                 {
650                         query += 2;
651                         while (*query && *query != '\n')
652                                 query++;
653                 }
654                 else if (query[0] == '/' && query[1] == '*')
655                 {
656                         query += 2;
657                         while (*query)
658                         {
659                                 if (query[0] == '*' && query[1] == '/')
660                                 {
661                                         query += 2;
662                                         break;
663                                 }
664                                 else
665                                         query++;
666                         }
667                 }
668                 else
669                         break;                          /* found first token */
670         }
671
672         /*
673          * Check word length ("beginx" is not "begin").
674          */
675         wordlen = 0;
676         while (isalpha((unsigned char) query[wordlen]))
677                 wordlen++;
678
679         if (wordlen == 5 && strncasecmp(query, "begin", 5) == 0)
680                 return true;
681         if (wordlen == 6 && strncasecmp(query, "commit", 6) == 0)
682                 return true;
683         if (wordlen == 8 && strncasecmp(query, "rollback", 8) == 0)
684                 return true;
685         if (wordlen == 5 && strncasecmp(query, "abort", 5) == 0)
686                 return true;
687         if (wordlen == 3 && strncasecmp(query, "end", 3) == 0)
688                 return true;
689         if (wordlen == 5 && strncasecmp(query, "start", 5) == 0)
690                 return true;
691
692         return false;
693 }
694
695
696 char parse_char(char **buf)
697 {
698   long l;
699
700   l = strtol(*buf, buf, 0);
701   --*buf;
702   return (char)l;
703 }
704
705
706 /*
707  * Test if the current user is a database superuser.
708  *
709  * Note: this will correctly detect superuserness only with a protocol-3.0
710  * or newer backend; otherwise it will always say "false".
711  */
712 bool
713 is_superuser(void)
714 {
715         const char *val;
716
717         if (!pset.db)
718                 return false;
719
720         val = PQparameterStatus(pset.db, "is_superuser");
721
722         if (val && strcmp(val, "on") == 0)
723                 return true;
724
725         return false;
726 }