]> granicus.if.org Git - postgresql/blob - src/bin/psql/common.c
Allow psql to handle tilde user expansion for file names.
[postgresql] / src / bin / psql / common.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2003, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.79 2004/01/09 21:12:20 momjian 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
61 #endif
62
63 extern bool prompt_state;
64
65
66 static bool is_transact_command(const char *query);
67
68
69 /*
70  * "Safe" wrapper around strdup()
71  */
72 char *
73 xstrdup(const char *string)
74 {
75         char       *tmp;
76
77         if (!string)
78         {
79                 fprintf(stderr, gettext("%s: xstrdup: cannot duplicate null pointer (internal error)\n"),
80                                 pset.progname);
81                 exit(EXIT_FAILURE);
82         }
83         tmp = strdup(string);
84         if (!tmp)
85         {
86                 psql_error("out of memory\n");
87                 exit(EXIT_FAILURE);
88         }
89         return tmp;
90 }
91
92
93
94 /*
95  * setQFout
96  * -- handler for -o command line option and \o command
97  *
98  * Tries to open file fname (or pipe if fname starts with '|')
99  * and stores the file handle in pset)
100  * Upon failure, sets stdout and returns false.
101  */
102 bool
103 setQFout(const char *fname)
104 {
105         bool            status = true;
106
107         /* Close old file/pipe */
108         if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr)
109         {
110                 if (pset.queryFoutPipe)
111                         pclose(pset.queryFout);
112                 else
113                         fclose(pset.queryFout);
114         }
115
116         /* If no filename, set stdout */
117         if (!fname || fname[0] == '\0')
118         {
119                 pset.queryFout = stdout;
120                 pset.queryFoutPipe = false;
121         }
122         else if (*fname == '|')
123         {
124                 pset.queryFout = popen(fname + 1, "w");
125                 pset.queryFoutPipe = true;
126         }
127         else
128         {
129                 pset.queryFout = fopen(fname, "w");
130                 pset.queryFoutPipe = false;
131         }
132
133         if (!(pset.queryFout))
134         {
135                 psql_error("%s: %s\n", fname, strerror(errno));
136                 pset.queryFout = stdout;
137                 pset.queryFoutPipe = false;
138                 status = false;
139         }
140
141         /* Direct signals */
142 #ifndef WIN32
143         pqsignal(SIGPIPE, pset.queryFoutPipe ? SIG_IGN : SIG_DFL);
144 #endif
145
146         return status;
147 }
148
149
150
151 /*
152  * Error reporting for scripts. Errors should look like
153  *       psql:filename:lineno: message
154  *
155  */
156 void
157 psql_error(const char *fmt,...)
158 {
159         va_list         ap;
160
161         fflush(stdout);
162         if (pset.queryFout != stdout)
163                 fflush(pset.queryFout);
164
165         if (pset.inputfile)
166                 fprintf(stderr, "%s:%s:%u: ", pset.progname, pset.inputfile, pset.lineno);
167         va_start(ap, fmt);
168         vfprintf(stderr, gettext(fmt), ap);
169         va_end(ap);
170 }
171
172
173
174 /*
175  * for backend Notice messages (INFO, WARNING, etc)
176  */
177 void
178 NoticeProcessor(void *arg, const char *message)
179 {
180         (void) arg;                                     /* not used */
181         psql_error("%s", message);
182 }
183
184
185
186 /*
187  * Code to support query cancellation
188  *
189  * Before we start a query, we enable a SIGINT signal catcher that sends a
190  * cancel request to the backend. Note that sending the cancel directly from
191  * the signal handler is safe because PQrequestCancel() is written to make it
192  * so. We use write() to print to stdout because it's better to use simple
193  * facilities in a signal handler.
194  */
195 static PGconn *volatile cancelConn = NULL;
196
197 volatile bool cancel_pressed = false;
198
199
200 #ifndef WIN32
201
202 #define write_stderr(String) write(fileno(stderr), String, strlen(String))
203
204 void
205 handle_sigint(SIGNAL_ARGS)
206 {
207         int                     save_errno = errno;
208
209         /* Don't muck around if prompting for a password. */
210         if (prompt_state)
211                 return;
212
213         if (cancelConn == NULL)
214                 siglongjmp(main_loop_jmp, 1);
215
216         cancel_pressed = true;
217
218         if (PQrequestCancel(cancelConn))
219                 write_stderr("Cancel request sent\n");
220         else
221         {
222                 write_stderr("Could not send cancel request: ");
223                 write_stderr(PQerrorMessage(cancelConn));
224         }
225         errno = save_errno;                     /* just in case the write changed it */
226 }
227 #endif   /* not WIN32 */
228
229
230
231 /* ConnectionUp
232  *
233  * Returns whether our backend connection is still there.
234  */
235 static bool
236 ConnectionUp()
237 {
238         return PQstatus(pset.db) != CONNECTION_BAD;
239 }
240
241
242
243 /* CheckConnection
244  *
245  * Verify that we still have a good connection to the backend, and if not,
246  * see if it can be restored.
247  *
248  * Returns true if either the connection was still there, or it could be
249  * restored successfully; false otherwise.      If, however, there was no
250  * connection and the session is non-interactive, this will exit the program
251  * with a code of EXIT_BADCONN.
252  */
253 static bool
254 CheckConnection(void)
255 {
256         bool            OK;
257
258         OK = ConnectionUp();
259         if (!OK)
260         {
261                 if (!pset.cur_cmd_interactive)
262                 {
263                         psql_error("connection to server was lost\n");
264                         exit(EXIT_BADCONN);
265                 }
266
267                 fputs(gettext("The connection to the server was lost. Attempting reset: "), stderr);
268                 PQreset(pset.db);
269                 OK = ConnectionUp();
270                 if (!OK)
271                 {
272                         fputs(gettext("Failed.\n"), stderr);
273                         PQfinish(pset.db);
274                         pset.db = NULL;
275                         ResetCancelConn();
276                         UnsyncVariables();
277                 }
278                 else
279                         fputs(gettext("Succeeded.\n"), stderr);
280         }
281
282         return OK;
283 }
284
285
286
287 /*
288  * SetCancelConn
289  *
290  * Set cancelConn to point to the current database connection.
291  */
292 static void
293 SetCancelConn(void)
294 {
295         cancelConn = pset.db;
296 }
297
298
299 /*
300  * ResetCancelConn
301  *
302  * Set cancelConn to NULL.      I don't know what this means exactly, but it saves
303  * having to export the variable.
304  */
305 void
306 ResetCancelConn(void)
307 {
308         cancelConn = NULL;
309 }
310
311
312 /*
313  * AcceptResult
314  *
315  * Checks whether a result is valid, giving an error message if necessary;
316  * resets cancelConn as needed, and ensures that the connection to the backend
317  * is still up.
318  *
319  * Returns true for valid result, false for error state.
320  */
321 static bool
322 AcceptResult(const PGresult *result)
323 {
324         bool            OK = true;
325
326         ResetCancelConn();
327
328         if (!result)
329                 OK = false;
330         else
331                 switch (PQresultStatus(result))
332                 {
333                         case PGRES_COMMAND_OK:
334                         case PGRES_TUPLES_OK:
335                         case PGRES_EMPTY_QUERY:
336                         case PGRES_COPY_IN:
337                                 /* Fine, do nothing */
338                                 break;
339
340                         case PGRES_COPY_OUT:
341                                 /* keep cancel connection for copy out state */
342                                 SetCancelConn();
343                                 break;
344
345                         default:
346                                 OK = false;
347                                 break;
348                 }
349
350         if (!OK)
351         {
352                 psql_error("%s", PQerrorMessage(pset.db));
353                 CheckConnection();
354         }
355
356         return OK;
357 }
358
359
360
361 /*
362  * PSQLexec
363  *
364  * This is the way to send "backdoor" queries (those not directly entered
365  * by the user). It is subject to -E but not -e.
366  *
367  * In autocommit-off mode, a new transaction block is started if start_xact
368  * is true; nothing special is done when start_xact is false.  Typically,
369  * start_xact = false is used for SELECTs and explicit BEGIN/COMMIT commands.
370  *
371  * Note: we don't bother to check PQclientEncoding; it is assumed that no
372  * caller uses this path to issue "SET CLIENT_ENCODING".
373  */
374 PGresult *
375 PSQLexec(const char *query, bool start_xact)
376 {
377         PGresult   *res;
378         int                     echo_hidden;
379
380         if (!pset.db)
381         {
382                 psql_error("You are currently not connected to a database.\n");
383                 return NULL;
384         }
385
386         echo_hidden = SwitchVariable(pset.vars, "ECHO_HIDDEN", "noexec", NULL);
387         if (echo_hidden != VAR_NOTSET)
388         {
389                 printf("********* QUERY **********\n"
390                            "%s\n"
391                            "**************************\n\n", query);
392                 fflush(stdout);
393
394                 if (echo_hidden == 1)   /* noexec? */
395                         return NULL;
396         }
397
398         SetCancelConn();
399
400         if (start_xact && PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
401                 !GetVariableBool(pset.vars, "AUTOCOMMIT"))
402         {
403                 res = PQexec(pset.db, "BEGIN");
404                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
405                 {
406                         psql_error("%s", PQerrorMessage(pset.db));
407                         PQclear(res);
408                         ResetCancelConn();
409                         return NULL;
410                 }
411                 PQclear(res);
412         }
413
414         res = PQexec(pset.db, query);
415
416         if (!AcceptResult(res) && res)
417         {
418                 PQclear(res);
419                 res = NULL;
420         }
421
422         return res;
423 }
424
425
426
427 /*
428  * PrintNotifications: check for asynchronous notifications, and print them out
429  */
430 static void
431 PrintNotifications(void)
432 {
433         PGnotify   *notify;
434
435         while ((notify = PQnotifies(pset.db)))
436         {
437                 fprintf(pset.queryFout, gettext("Asynchronous notification \"%s\" received from server process with PID %d.\n"),
438                                 notify->relname, notify->be_pid);
439                 fflush(pset.queryFout);
440                 PQfreemem(notify);
441         }
442 }
443
444
445 /*
446  * PrintQueryTuples: assuming query result is OK, print its tuples
447  *
448  * Returns true if successful, false otherwise.
449  */
450 static bool
451 PrintQueryTuples(const PGresult *results)
452 {
453         /* write output to \g argument, if any */
454         if (pset.gfname)
455         {
456                 FILE       *queryFout_copy = pset.queryFout;
457                 bool            queryFoutPipe_copy = pset.queryFoutPipe;
458
459                 pset.queryFout = stdout;        /* so it doesn't get closed */
460
461                 /* open file/pipe */
462                 if (!setQFout(pset.gfname))
463                 {
464                         pset.queryFout = queryFout_copy;
465                         pset.queryFoutPipe = queryFoutPipe_copy;
466                         return false;
467                 }
468
469                 printQuery(results, &pset.popt, pset.queryFout);
470
471                 /* close file/pipe, restore old setting */
472                 setQFout(NULL);
473
474                 pset.queryFout = queryFout_copy;
475                 pset.queryFoutPipe = queryFoutPipe_copy;
476
477                 free(pset.gfname);
478                 pset.gfname = NULL;
479         }
480         else
481                 printQuery(results, &pset.popt, pset.queryFout);
482
483         return true;
484 }
485
486
487 /*
488  * ProcessCopyResult: if command was a COPY FROM STDIN/TO STDOUT, handle it
489  *
490  * Note: Utility function for use by SendQuery() only.
491  *
492  * Returns true if the query executed successfully, false otherwise.
493  */
494 static bool
495 ProcessCopyResult(PGresult *results)
496 {
497         bool            success = false;
498
499         if (!results)
500                 return false;
501
502         switch (PQresultStatus(results))
503         {
504                 case PGRES_TUPLES_OK:
505                 case PGRES_COMMAND_OK:
506                 case PGRES_EMPTY_QUERY:
507                         /* nothing to do here */
508                         success = true;
509                         break;
510
511                 case PGRES_COPY_OUT:
512                         success = handleCopyOut(pset.db, pset.queryFout);
513                         break;
514
515                 case PGRES_COPY_IN:
516                         if (pset.cur_cmd_interactive && !QUIET())
517                                 puts(gettext("Enter data to be copied followed by a newline.\n"
518                                                          "End with a backslash and a period on a line by itself."));
519
520                         success = handleCopyIn(pset.db, pset.cur_cmd_source,
521                           pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL);
522                         break;
523
524                 default:
525                         break;
526         }
527
528         /* may need this to recover from conn loss during COPY */
529         if (!CheckConnection())
530                 return false;
531
532         return success;
533 }
534
535
536 /*
537  * PrintQueryResults: print out query results as required
538  *
539  * Note: Utility function for use by SendQuery() only.
540  *
541  * Returns true if the query executed successfully, false otherwise.
542  */
543 static bool
544 PrintQueryResults(PGresult *results)
545 {
546         bool            success = false;
547
548         if (!results)
549                 return false;
550
551         switch (PQresultStatus(results))
552         {
553                 case PGRES_TUPLES_OK:
554                         success = PrintQueryTuples(results);
555                         break;
556
557                 case PGRES_COMMAND_OK:
558                         {
559                                 char            buf[10];
560
561                                 success = true;
562                                 sprintf(buf, "%u", (unsigned int) PQoidValue(results));
563                                 if (!QUIET())
564                                 {
565                                         if (pset.popt.topt.format == PRINT_HTML)
566                                         {
567                                                 fputs("<p>", pset.queryFout);
568                                                 html_escaped_print(PQcmdStatus(results),
569                                                                                    pset.queryFout);
570                                                 fputs("</p>\n", pset.queryFout);
571                                         }
572                                         else
573                                                 fprintf(pset.queryFout, "%s\n", PQcmdStatus(results));
574                                 }
575                                 SetVariable(pset.vars, "LASTOID", buf);
576                                 break;
577                         }
578
579                 case PGRES_EMPTY_QUERY:
580                         success = true;
581                         break;
582
583                 case PGRES_COPY_OUT:
584                 case PGRES_COPY_IN:
585                         /* nothing to do here */
586                         success = true;
587                         break;
588
589                 default:
590                         break;
591         }
592
593         fflush(pset.queryFout);
594
595         return success;
596 }
597
598
599 /*
600  * SendQuery: send the query string to the backend
601  * (and print out results)
602  *
603  * Note: This is the "front door" way to send a query. That is, use it to
604  * send queries actually entered by the user. These queries will be subject to
605  * single step mode.
606  * To send "back door" queries (generated by slash commands, etc.) in a
607  * controlled way, use PSQLexec().
608  *
609  * Returns true if the query executed successfully, false otherwise.
610  */
611 bool
612 SendQuery(const char *query)
613 {
614         PGresult   *results;
615         TimevalStruct before,
616                                 after;
617         bool            OK;
618
619         if (!pset.db)
620         {
621                 psql_error("You are currently not connected to a database.\n");
622                 return false;
623         }
624
625         if (GetVariableBool(pset.vars, "SINGLESTEP"))
626         {
627                 char            buf[3];
628
629                 printf(gettext("***(Single step mode: verify command)*******************************************\n"
630                                            "%s\n"
631                                            "***(press return to proceed or enter x and return to cancel)********************\n"),
632                            query);
633                 fflush(stdout);
634                 if (fgets(buf, sizeof(buf), stdin) != NULL)
635                         if (buf[0] == 'x')
636                                 return false;
637         }
638         else if (VariableEquals(pset.vars, "ECHO", "queries"))
639         {
640                 puts(query);
641                 fflush(stdout);
642         }
643
644         SetCancelConn();
645
646         if (PQtransactionStatus(pset.db) == PQTRANS_IDLE &&
647                 !GetVariableBool(pset.vars, "AUTOCOMMIT") &&
648                 !is_transact_command(query))
649         {
650                 results = PQexec(pset.db, "BEGIN");
651                 if (PQresultStatus(results) != PGRES_COMMAND_OK)
652                 {
653                         psql_error("%s", PQerrorMessage(pset.db));
654                         PQclear(results);
655                         ResetCancelConn();
656                         return false;
657                 }
658                 PQclear(results);
659         }
660
661         if (pset.timing)
662                 GETTIMEOFDAY(&before);
663
664         results = PQexec(pset.db, query);
665
666         /* these operations are included in the timing result: */
667         OK = (AcceptResult(results) && ProcessCopyResult(results));
668
669         if (pset.timing)
670                 GETTIMEOFDAY(&after);
671
672         /* but printing results isn't: */
673         if (OK)
674                 OK = PrintQueryResults(results);
675
676         PQclear(results);
677
678         /* Possible microtiming output */
679         if (OK && pset.timing)
680                 printf(gettext("Time: %.3f ms\n"), DIFF_MSEC(&after, &before));
681
682         /* check for events that may occur during query execution */
683
684         if (pset.encoding != PQclientEncoding(pset.db) &&
685                 PQclientEncoding(pset.db) >= 0)
686         {
687                 /* track effects of SET CLIENT_ENCODING */
688                 pset.encoding = PQclientEncoding(pset.db);
689                 pset.popt.topt.encoding = pset.encoding;
690                 SetVariable(pset.vars, "ENCODING",
691                                         pg_encoding_to_char(pset.encoding));
692         }
693
694         PrintNotifications();
695
696         return OK;
697 }
698
699 /*
700  * check whether a query string begins with BEGIN/COMMIT/ROLLBACK/START XACT
701  */
702 static bool
703 is_transact_command(const char *query)
704 {
705         int                     wordlen;
706
707         /*
708          * First we must advance over any whitespace and comments.
709          */
710         while (*query)
711         {
712                 if (isspace((unsigned char) *query))
713                         query++;
714                 else if (query[0] == '-' && query[1] == '-')
715                 {
716                         query += 2;
717                         while (*query && *query != '\n')
718                                 query++;
719                 }
720                 else if (query[0] == '/' && query[1] == '*')
721                 {
722                         query += 2;
723                         while (*query)
724                         {
725                                 if (query[0] == '*' && query[1] == '/')
726                                 {
727                                         query += 2;
728                                         break;
729                                 }
730                                 else
731                                         query++;
732                         }
733                 }
734                 else
735                         break;                          /* found first token */
736         }
737
738         /*
739          * Check word length ("beginx" is not "begin").
740          */
741         wordlen = 0;
742         while (isalpha((unsigned char) query[wordlen]))
743                 wordlen++;
744
745         if (wordlen == 5 && strncasecmp(query, "begin", 5) == 0)
746                 return true;
747         if (wordlen == 6 && strncasecmp(query, "commit", 6) == 0)
748                 return true;
749         if (wordlen == 8 && strncasecmp(query, "rollback", 8) == 0)
750                 return true;
751         if (wordlen == 5 && strncasecmp(query, "abort", 5) == 0)
752                 return true;
753         if (wordlen == 3 && strncasecmp(query, "end", 3) == 0)
754                 return true;
755         if (wordlen == 5 && strncasecmp(query, "start", 5) == 0)
756                 return true;
757
758         return false;
759 }
760
761
762 char
763 parse_char(char **buf)
764 {
765         long            l;
766
767         l = strtol(*buf, buf, 0);
768         --*buf;
769         return (char) l;
770 }
771
772
773 /*
774  * Test if the current user is a database superuser.
775  *
776  * Note: this will correctly detect superuserness only with a protocol-3.0
777  * or newer backend; otherwise it will always say "false".
778  */
779 bool
780 is_superuser(void)
781 {
782         const char *val;
783
784         if (!pset.db)
785                 return false;
786
787         val = PQparameterStatus(pset.db, "is_superuser");
788
789         if (val && strcmp(val, "on") == 0)
790                 return true;
791
792         return false;
793 }
794
795
796 /*
797  * Return the session user of the current connection.
798  *
799  * Note: this will correctly detect the session user only with a
800  * protocol-3.0 or newer backend; otherwise it will return the
801  * connection user.
802  */
803 const char *
804 session_username(void)
805 {
806         const char *val;
807
808         if (!pset.db)
809                 return NULL;
810
811         val = PQparameterStatus(pset.db, "session_authorization");
812         if (val)
813                 return val;
814         else
815                 return PQuser(pset.db);
816 }
817
818
819 /* expand_tilde
820  *
821  * substitute '~' with HOME or '~username' with username's home dir
822  *
823  */
824 char *
825 expand_tilde(char **filename)
826 {
827         if (!filename || !(*filename))
828                 return NULL;
829
830         /* MSDOS uses tilde for short versions of long file names, so skip it. */
831 #ifndef WIN32
832
833         /* try tilde expansion */
834         if (**filename == '~')
835         {
836                 char       *fn;
837                 char       *home;
838                 char            oldp,
839                                    *p;
840                 struct passwd *pw;
841
842                 fn = *filename;
843                 home = NULL;
844
845                 p = fn + 1;
846                 while (*p != '/' && *p != '\0')
847                         p++;
848
849                 oldp = *p;
850                 *p = '\0';
851
852                 if (*(fn + 1) == '\0')
853                         home = getenv("HOME");
854                 else if ((pw = getpwnam(fn + 1)) != NULL)
855                         home = pw->pw_dir;
856
857                 *p = oldp;
858                 if (home)
859                 {
860                         char       *newfn;
861
862                         newfn = malloc(strlen(home) + strlen(p) + 1);
863                         if (!newfn)
864                         {
865                                 psql_error("out of memory\n");
866                                 exit(EXIT_FAILURE);
867                         }
868                         strcpy(newfn, home);
869                         strcat(newfn, p);
870
871                         free(fn);
872                         *filename = newfn;
873                 }
874         }
875 #endif
876
877         return *filename;
878 }