]> granicus.if.org Git - postgresql/blob - src/bin/psql/command.c
added ALTER TABLE DROP COLUMN, early version
[postgresql] / src / bin / psql / command.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright 2000 by PostgreSQL Global Development Team
5  *
6  * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.14 2000/01/22 14:20:51 petere Exp $
7  */
8 #include <c.h>
9 #include "command.h"
10
11 #include <errno.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <ctype.h>
16 #ifndef WIN32
17 #include <sys/types.h>                  /* for umask() */
18 #include <sys/stat.h>                   /* for umask(), stat() */
19 #include <unistd.h>                             /* for geteuid(), getpid(), stat() */
20 #endif
21 #include <assert.h>
22
23 #include <libpq-fe.h>
24 #include <pqexpbuffer.h>
25
26 #include "stringutils.h"
27 #include "mainloop.h"
28 #include "copy.h"
29 #include "help.h"
30 #include "settings.h"
31 #include "common.h"
32 #include "large_obj.h"
33 #include "print.h"
34 #include "describe.h"
35 #include "input.h"
36 #include "variables.h"
37
38 #ifdef WIN32
39 #include "../../interfaces/libpq/win32.h"
40 #define popen(x,y) _popen(x,y)
41 #define pclose(x) _pclose(x)
42 #endif
43
44
45 /* functions for use in this file */
46
47 static backslashResult exec_command(const char *cmd,
48                          char *const * options,
49                          const char *options_string,
50                          PQExpBuffer query_buf);
51
52 static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
53
54 static char * unescape(const char *source);
55
56 static bool do_connect(const char *new_dbname,
57                        const char *new_user);
58
59
60 static bool do_shell(const char *command);
61
62 /*
63  * Perhaps this should be changed to "infinity",
64  * but there is no convincing reason to bother
65  * at this point.
66  */
67 #define NR_OPTIONS 16
68
69
70 /*----------
71  * HandleSlashCmds:
72  *
73  * Handles all the different commands that start with '\',
74  * ordinarily called by MainLoop().
75  *
76  * 'line' is the current input line, which should not start with a '\'
77  * but with the actual command name
78  * (that is taken care of by MainLoop)
79  *
80  * 'query_buf' contains the query-so-far, which may be modified by
81  * execution of the backslash command (for example, \r clears it)
82  * query_buf can be NULL if there is no query-so-far.
83  *
84  * Returns a status code indicating what action is desired, see command.h.
85  *----------
86  */
87
88 backslashResult
89 HandleSlashCmds(const char *line,
90                                 PQExpBuffer query_buf,
91                                 const char **end_of_cmd)
92 {
93         backslashResult status = CMD_SKIP_LINE;
94         char       *my_line;
95         char       *options[NR_OPTIONS+1];
96         char       *token;
97         const char *options_string = NULL;
98         const char *cmd;
99         size_t          blank_loc;
100         int                     i;
101         const char *continue_parse = NULL;      /* tell the mainloop where the
102                                                                                  * backslash command ended */
103
104 #ifdef USE_ASSERT_CHECKING
105     assert(line);
106     assert(query_buf);
107     assert(end_of_cmd);
108 #endif
109
110         my_line = xstrdup(line);
111
112         /*
113          * Find the first whitespace. line[blank_loc] will now
114          * be the whitespace character or the \0 at the end
115      *
116      * Also look for a backslash, so stuff like \p\g works.
117          */
118         blank_loc = strcspn(my_line, " \t\\");
119
120     if (my_line[blank_loc] == '\\')
121     {
122         continue_parse = &my_line[blank_loc];
123                 my_line[blank_loc] = '\0';
124     }
125         /* do we have an option string? */
126         else if (my_line[blank_loc] != '\0')
127     {
128         options_string = &my_line[blank_loc + 1];
129                 my_line[blank_loc] = '\0';
130         }
131
132     options[0] = NULL;
133
134         if (options_string)
135         {
136                 char            quote;
137                 unsigned int pos;
138
139                 options_string = &options_string[strspn(options_string, " \t")];                /* skip leading
140                                                                                                                                                                  * whitespace */
141
142                 i = 0;
143                 token = strtokx(options_string, " \t", "\"'`", '\\', &quote, &pos, pset.encoding);
144
145                 for (i = 0; token && i < NR_OPTIONS; i++)
146                 {
147                         switch (quote)
148                         {
149                                 case '"':
150                                         options[i] = unescape(token);
151                                         break;
152                                 case '\'':
153                                         options[i] = xstrdup(token);
154                                         break;
155                                 case '`':
156                                         {
157                                                 bool            error = false;
158                                                 FILE       *fd = NULL;
159                                                 char       *file = unescape(token);
160                                                 PQExpBufferData output;
161                                                 char            buf[512];
162                                                 size_t          result;
163
164                                                 fd = popen(file, "r");
165                                                 if (!fd)
166                                                 {
167                             psql_error("%s: %s\n", file, strerror(errno));
168                                                         error = true;
169                                                 }
170
171                                                 if (!error)
172                                                 {
173                                                         initPQExpBuffer(&output);
174
175                                                         do
176                                                         {
177                                                                 result = fread(buf, 1, 512, fd);
178                                                                 if (ferror(fd))
179                                                                 {
180                                     psql_error("%s: %s\n", file, strerror(errno));
181                                                                         error = true;
182                                                                         break;
183                                                                 }
184                                                                 appendBinaryPQExpBuffer(&output, buf, result);
185                                                         } while (!feof(fd));
186                                                         appendPQExpBufferChar(&output, '\0');
187
188                                                         if (pclose(fd) == -1)
189                                                         {
190                                 psql_error("%s: %s\n", file, strerror(errno));
191                                                                 error = true;
192                                                         }
193                                                 }
194
195                                                 if (!error)
196                                                 {
197                                                         if (output.data[strlen(output.data) - 1] == '\n')
198                                                                 output.data[strlen(output.data) - 1] = '\0';
199                                                 }
200
201                                                 free(file);
202                                                 if (!error)
203                                                         options[i] = output.data;
204                                                 else
205                                                 {
206                                                         options[i] = xstrdup("");
207                                                         termPQExpBuffer(&output);
208                                                 }
209                                                 break;
210                                         }
211                                 case 0:
212                                 default:
213                                         if (token[0] == '\\')
214                                                 continue_parse = options_string + pos;
215                                         else if (token[0] == '$') 
216                     {
217                         const char * value = GetVariable(pset.vars, token+1);
218                         if (!value)
219                             value = "";
220                                                 options[i] = xstrdup(value);
221                     }
222                                         else
223                                                 options[i] = xstrdup(token);
224                         }
225
226                         if (continue_parse)
227                                 break;
228
229                         token = strtokx(NULL, " \t", "\"'`", '\\', &quote, &pos, pset.encoding);
230                 } /* for */
231
232         options[i] = NULL;
233         }
234
235         cmd = my_line;
236         status = exec_command(cmd, options, options_string, query_buf);
237
238         if (status == CMD_UNKNOWN)
239         {
240
241                 /*
242                  * If the command was not recognized, try inserting a space after
243                  * the first letter and call again. The one letter commands allow
244                  * arguments to start immediately after the command, but that is
245                  * no longer encouraged.
246                  */
247                 const char *new_options[NR_OPTIONS+1];
248                 char            new_cmd[2];
249                 int                     i;
250
251                 for (i = 1; i < NR_OPTIONS+1; i++)
252                         new_options[i] = options[i - 1];
253                 new_options[0] = cmd + 1;
254
255                 new_cmd[0] = cmd[0];
256                 new_cmd[1] = '\0';
257
258                 status = exec_command(new_cmd, (char *const *) new_options, my_line + 2, query_buf);
259         }
260
261         if (status == CMD_UNKNOWN)
262         {
263         if (pset.cur_cmd_interactive)
264             fprintf(stderr, "Invalid command \\%s. Try \\? for help.\n", cmd);
265         else
266             psql_error("invalid command \\%s\n", cmd);
267                 status = CMD_ERROR;
268         }
269
270         if (continue_parse && *(continue_parse + 1) == '\\')
271                 continue_parse += 2;
272
273
274     if (continue_parse)
275         *end_of_cmd = line + (continue_parse - my_line);
276     else
277         *end_of_cmd = line + strlen(line);
278
279         /* clean up */
280         for (i = 0; i < NR_OPTIONS && options[i]; i++)
281                 free(options[i]);
282
283         free(my_line);
284
285         return status;
286 }
287
288
289
290
291 static backslashResult
292 exec_command(const char *cmd,
293                          char *const * options,
294                          const char *options_string,
295                          PQExpBuffer query_buf)
296 {
297         bool            success = true; /* indicate here if the command ran ok or
298                                                                  * failed */
299         bool            quiet = QUIET();
300
301         backslashResult status = CMD_SKIP_LINE;
302
303
304         /* \a -- toggle field alignment This makes little sense but we keep it around. */
305         if (strcmp(cmd, "a") == 0)
306         {
307                 if (pset.popt.topt.format != PRINT_ALIGNED)
308                         success = do_pset("format", "aligned", &pset.popt, quiet);
309                 else
310                         success = do_pset("format", "unaligned", &pset.popt, quiet);
311         }
312
313
314         /* \C -- override table title (formerly change HTML caption) */
315         else if (strcmp(cmd, "C") == 0)
316                 success = do_pset("title", options[0], &pset.popt, quiet);
317
318
319         /*----------
320          * \c or \connect -- connect to new database or as different user
321          *
322          * \c foo bar: connect to db "foo" as user "bar"
323      * \c foo [-]: connect to db "foo" as current user
324      * \c - bar:   connect to current db as user "bar"
325      * \c:          connect to default db as default user
326      *----------
327          */
328         else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
329         {
330                 if (options[1])
331                         /* gave username */
332                         success = do_connect(options[0], options[1]);
333                 else
334                 {
335                         if (options[0])
336                                 /* gave database name */
337                                 success = do_connect(options[0], "");           /* empty string is same
338                                                              * username as before,
339                                                              * NULL would mean libpq
340                                                              * default */
341                         else
342                                 /* connect to default db as default user */
343                                 success = do_connect(NULL, NULL);
344                 }
345         }
346
347
348         /* \copy */
349         else if (strcasecmp(cmd, "copy") == 0)
350                 success = do_copy(options_string);
351
352         /* \copyright */
353         else if (strcmp(cmd, "copyright") == 0)
354                 print_copyright();
355
356         /* \d* commands */
357         else if (cmd[0] == 'd')
358         {
359         bool show_verbose = strchr(cmd, '+') ? true : false;
360
361                 switch (cmd[1])
362                 {
363                         case '\0':
364             case '?':
365                                 if (options[0])
366                                         success = describeTableDetails(options[0], show_verbose);
367                                 else
368                     /* standard listing of interesting things */
369                                         success = listTables("tvs", NULL, show_verbose);
370                                 break;
371                         case 'a':
372                                 success = describeAggregates(options[0]);
373                                 break;
374                         case 'd':
375                                 success = objectDescription(options[0]);
376                                 break;
377                         case 'f':
378                                 success = describeFunctions(options[0], show_verbose);
379                                 break;
380                         case 'l':
381                                 success = do_lo_list();
382                                 break;
383                         case 'o':
384                                 success = describeOperators(options[0]);
385                                 break;
386                         case 'p':
387                                 success = permissionsList(options[0]);
388                                 break;
389                         case 'T':
390                                 success = describeTypes(options[0], show_verbose);
391                                 break;
392                         case 't':
393                         case 'v':
394                         case 'i':
395                         case 's':
396                         case 'S':
397                                 if (cmd[1] == 'S' && cmd[2] == '\0')
398                                         success = listTables("Stvs", NULL, show_verbose);
399                                 else
400                                         success = listTables(&cmd[1], options[0], show_verbose);
401                                 break;
402                         default:
403                                 status = CMD_UNKNOWN;
404                 }
405         }
406
407
408         /*
409          * \e or \edit -- edit the current query buffer (or a file and make it
410          * the query buffer
411          */
412         else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
413                 status = do_edit(options[0], query_buf) ? CMD_NEWEDIT : CMD_ERROR;
414
415
416         /* \echo */
417         else if (strcmp(cmd, "echo") == 0)
418         {
419                 int                     i;
420
421                 for (i = 0; i < 16 && options[i]; i++)
422                         fputs(options[i], stdout);
423                 fputs("\n", stdout);
424         }
425
426         /* \f -- change field separator */
427         else if (strcmp(cmd, "f") == 0)
428                 success = do_pset("fieldsep", options[0], &pset.popt, quiet);
429
430         /* \g means send query */
431         else if (strcmp(cmd, "g") == 0)
432         {
433                 if (!options[0])
434                         pset.gfname = NULL;
435                 else
436                         pset.gfname = xstrdup(options[0]);
437                 status = CMD_SEND;
438         }
439
440         /* help */
441         else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
442     {
443         char buf[256] = "";
444         int i;
445         for (i=0; options && options[i] && strlen(buf)<255; i++)
446         {
447             strncat(buf, options[i], 255 - strlen(buf));
448             if (strlen(buf)<255 && options[i+1])
449                 strcat(buf, " ");
450         }
451         buf[255] = '\0';
452                 helpSQL(buf);
453     }
454
455         /* HTML mode */
456         else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
457     {
458                 if (pset.popt.topt.format != PRINT_HTML)
459                         success = do_pset("format", "html", &pset.popt, quiet);
460                 else
461                         success = do_pset("format", "aligned", &pset.popt, quiet);
462     }
463
464
465         /* \i is include file */
466         else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
467         {
468                 if (!options[0])
469         {
470             psql_error("\\%s: missing required argument\n", cmd);
471                         success = false;
472                 }
473                 else
474                         success = process_file(options[0]);
475         }
476
477
478         /* \l is list databases */
479         else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
480                 success = listAllDbs(false);
481         else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
482                 success = listAllDbs(true);
483
484
485         /* large object things */
486         else if (strncmp(cmd, "lo_", 3) == 0)
487         {
488                 if (strcmp(cmd + 3, "export") == 0)
489                 {
490                         if (!options[1])
491                         {
492                 psql_error("\\%s: missing required argument\n", cmd);
493                                 success = false;
494                         }
495                         else
496                                 success = do_lo_export(options[0], options[1]);
497                 }
498
499                 else if (strcmp(cmd + 3, "import") == 0)
500                 {
501                         if (!options[0])
502                         {
503                 psql_error("\\%s: missing required argument\n", cmd);
504                                 success = false;
505                         }
506                         else
507                                 success = do_lo_import(options[0], options[1]);
508                 }
509
510                 else if (strcmp(cmd + 3, "list") == 0)
511                         success = do_lo_list();
512
513                 else if (strcmp(cmd + 3, "unlink") == 0)
514                 {
515                         if (!options[0])
516                         {
517                 psql_error("\\%s: missing required argument\n", cmd);
518                                 success = false;
519                         }
520                         else
521                                 success = do_lo_unlink(options[0]);
522                 }
523
524                 else
525                         status = CMD_UNKNOWN;
526         }
527
528         /* \o -- set query output */
529         else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
530                 success = setQFout(options[0]);
531
532
533         /* \p prints the current query buffer */
534         else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
535         {
536                 if (query_buf && query_buf->len > 0)
537                         puts(query_buf->data);
538                 else if (!quiet)
539                         puts("Query buffer is empty.");
540                 fflush(stdout);
541         }
542
543         /* \pset -- set printing parameters */
544         else if (strcmp(cmd, "pset") == 0)
545         {
546                 if (!options[0])
547                 {
548             psql_error("\\%s: missing required argument\n", cmd);
549                         success = false;
550                 }
551                 else
552                         success = do_pset(options[0], options[1], &pset.popt, quiet);
553         }
554
555         /* \q or \quit */
556         else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
557                 status = CMD_TERMINATE;
558
559         /* \qecho */
560         else if (strcmp(cmd, "qecho") == 0)
561         {
562                 int                     i;
563
564                 for (i = 0; i < 16 && options[i]; i++)
565                         fputs(options[i], pset.queryFout);
566                 fputs("\n", pset.queryFout);
567         }
568
569         /* reset(clear) the buffer */
570         else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
571         {
572                 resetPQExpBuffer(query_buf);
573                 if (!quiet)
574                         puts("Query buffer reset (cleared).");
575         }
576
577
578         /* \s save history in a file or show it on the screen */
579         else if (strcmp(cmd, "s") == 0)
580         {
581                 const char *fname;
582
583                 if (!options[0])
584                         fname = "/dev/tty";
585                 else
586                         fname = options[0];
587
588                 success = saveHistory(fname);
589
590                 if (success && !quiet && options[0])
591                         printf("Wrote history to %s.\n", fname);
592         }
593
594
595         /* \set -- generalized set option command */
596         else if (strcmp(cmd, "set") == 0)
597         {
598                 if (!options[0])
599                 {
600                         /* list all variables */
601
602                         /*
603                          * (This is in utter violation of the GetVariable abstraction,
604                          * but I have not dreamt up a better way.)
605                          */
606                         struct _variable *ptr;
607
608                         for (ptr = pset.vars; ptr->next; ptr = ptr->next)
609                                 fprintf(stdout, "%s = '%s'\n", ptr->next->name, ptr->next->value);
610                         success = true;
611                 }
612                 else
613                 {
614             const char * val = options[1];
615             if (!val)
616                 val = "";
617                         if (!SetVariable(pset.vars, options[0], val))
618                         {
619                 psql_error("\\%s: error\n", cmd);
620                                 success = false;
621                         }
622                 }
623         }
624
625         /* \t -- turn off headers and row count */
626         else if (strcmp(cmd, "t") == 0)
627                 success = do_pset("tuples_only", NULL, &pset.popt, quiet);
628
629
630         /* \T -- define html <table ...> attributes */
631         else if (strcmp(cmd, "T") == 0)
632                 success = do_pset("tableattr", options[0], &pset.popt, quiet);
633
634     /* \unset */
635     else if (strcmp(cmd, "unset") == 0)
636     {
637         if (!SetVariable(pset.vars, options[0], NULL))
638         {
639             psql_error("\\%s: error\n", cmd);
640
641             success = false;
642                         }
643     }
644
645         /* \w -- write query buffer to file */
646         else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
647         {
648                 FILE       *fd = NULL;
649                 bool            pipe = false;
650
651                 if (!options[0])
652                 {
653             psql_error("\\%s: missing required argument\n", cmd);
654                         success = false;
655                 }
656                 else
657                 {
658                         if (options[0][0] == '|')
659                         {
660                                 pipe = true;
661                                 fd = popen(&options[0][1], "w");
662                         }
663                         else
664                         {
665                                 fd = fopen(options[0], "w");
666                         }
667
668                         if (!fd)
669                         {
670                 psql_error("%s: %s\n", options[0], strerror(errno));
671                                 success = false;
672                         }
673                 }
674
675                 if (fd)
676                 {
677                         int                     result;
678
679                         if (query_buf && query_buf->len > 0)
680                                 fprintf(fd, "%s\n", query_buf->data);
681
682                         if (pipe)
683                                 result = pclose(fd);
684                         else
685                                 result = fclose(fd);
686
687                         if (result == EOF)
688                         {
689                 psql_error("%s: %s\n", options[0], strerror(errno));
690                                 success = false;
691                         }
692                 }
693         }
694
695         /* \x -- toggle expanded table representation */
696         else if (strcmp(cmd, "x") == 0)
697                 success = do_pset("expanded", NULL, &pset.popt, quiet);
698
699
700         /* list table rights (grant/revoke) */
701         else if (strcmp(cmd, "z") == 0)
702                 success = permissionsList(options[0]);
703
704
705         else if (strcmp(cmd, "!") == 0)
706                 success = do_shell(options_string);
707
708         else if (strcmp(cmd, "?") == 0)
709                 slashUsage();
710
711
712 #if 0
713     /*
714          * These commands don't do anything. I just use them to test the
715          * parser.
716          */
717         else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
718         {
719                 int                     i;
720
721                 fprintf(stderr, "+ optline = |%s|\n", options_string);
722                 for (i = 0; options[i]; i++)
723                         fprintf(stderr, "+ opt%d = |%s|\n", i, options[i]);
724         }
725 #endif
726
727         else
728                 status = CMD_UNKNOWN;
729
730         if (!success)
731                 status = CMD_ERROR;
732         return status;
733 }
734
735
736
737 /*
738  * unescape
739  *
740  * Replaces \n, \t, and the like.
741  * Also interpolates ${variables}.
742  *
743  * The return value is malloc()'ed.
744  */
745 static char *
746 unescape(const char *source)
747 {
748         unsigned char *p;
749         bool            esc = false;    /* Last character we saw was the escape
750                                                                  * character */
751         char       *destination,
752                            *tmp;
753         size_t          length;
754
755 #ifdef USE_ASSERT_CHECKING
756         assert(source);
757 #endif
758
759         length = strlen(source) + 1;
760
761         tmp = destination = (char *) malloc(length);
762         if (!tmp)
763         {
764                 psql_error("out of memory\n");
765                 exit(EXIT_FAILURE);
766         }
767
768         for (p = (char *) source; *p; p += PQmblen(p, pset.encoding))
769         {
770                 if (esc)
771                 {
772                         char            c;
773
774                         switch (*p)
775                         {
776                                 case 'n':
777                                         c = '\n';
778                                         break;
779                                 case 'r':
780                                         c = '\r';
781                                         break;
782                                 case 't':
783                                         c = '\t';
784                                         break;
785                                 case 'f':
786                                         c = '\f';
787                                         break;
788                                 case '0':
789                                 case '1':
790                                 case '2':
791                                 case '3':
792                                 case '4':
793                                 case '5':
794                                 case '6':
795                                 case '7':
796                                 case '8':
797                                 case '9':
798                                         {
799                                                 long int        l;
800                                                 char       *end;
801
802                                                 l = strtol(p, &end, 0);
803                                                 c = l;
804                                                 p = end - 1;
805                                                 break;
806                                         }
807                                 default:
808                                         c = *p;
809                         }
810                         *tmp++ = c;
811                         esc = false;
812                 }
813
814                 else if (*p == '\\')
815                         esc = true;
816
817                 else if (*p == '$')
818                 {
819                         if (*(p + 1) == '{')
820                         {
821                                 unsigned int len;
822                                 char       *copy;
823                                 const char *value;
824 #ifndef WIN32
825                                 void       *new;
826 #else
827                                 char *new;
828 #endif
829
830                                 len = strcspn(p + 2, "}");
831                                 copy = xstrdup(p + 2);
832                                 copy[len] = '\0';
833                                 value = GetVariable(pset.vars, copy);
834                 if (!value)
835                     value = "";
836                                 length += strlen(value) - (len + 3);
837                                 new = realloc(destination, length);
838                                 if (!new)
839                                 {
840                                         psql_error("out of memory\n");
841                                         exit(EXIT_FAILURE);
842                                 }
843                                 tmp = new + (tmp - destination);
844                                 destination = new;
845
846                                 strcpy(tmp, value);
847                                 tmp += strlen(value);
848                                 p += len + 2;
849                                 free(copy);
850                         }
851                         else
852                                 *tmp++ = '$';
853                 }
854
855                 else
856                 {
857                         *tmp++ = *p;
858                         esc = false;
859                 }
860         }
861
862         *tmp = '\0';
863         return destination;
864 }
865
866
867
868
869 /* do_connect
870  * -- handler for \connect
871  *
872  * Connects to a database (new_dbname) as a certain user (new_user).
873  * The new user can be NULL. A db name of "-" is the same as the old one.
874  * (That is, the one currently in pset. But pset.db can also be NULL. A NULL
875  * dbname is handled by libpq.)
876  * Returns true if all ok, false if the new connection couldn't be established
877  * but the old one was set back. Otherwise it terminates the program.
878  */
879 static bool
880 do_connect(const char *new_dbname, const char *new_user)
881 {
882         PGconn     *oldconn = pset.db;
883         const char *dbparam = NULL;
884         const char *userparam = NULL;
885         const char *pwparam = NULL;
886         char       *prompted_password = NULL;
887         bool            need_pass;
888         bool            success = false;
889
890     /* Delete variables (in case we fail before setting them anew) */
891     SetVariable(pset.vars, "DBNAME", NULL);
892     SetVariable(pset.vars, "USER", NULL);
893     SetVariable(pset.vars, "HOST", NULL);
894     SetVariable(pset.vars, "PORT", NULL);
895
896         /* If dbname is "-" then use old name, else new one (even if NULL) */
897         if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "-") == 0)
898                 dbparam = PQdb(oldconn);
899         else
900                 dbparam = new_dbname;
901
902         /* If user is "" then use the old one */
903         if (new_user && PQuser(oldconn) && strcmp(new_user, "")==0)
904                 userparam = PQuser(oldconn);
905         else
906                 userparam = new_user;
907
908         /* need to prompt for password? */
909         if (pset.getPassword)
910                 pwparam = prompted_password = simple_prompt("Password: ", 100, false);  /* need to save for
911                                                                                                                                                                  * free() */
912
913         /*
914          * Use old password if no new one given (if you didn't have an old
915          * one, fine)
916          */
917         if (!pwparam && oldconn)
918                 pwparam = PQpass(oldconn);
919
920         do
921         {
922                 need_pass = false;
923                 pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
924                                                                 NULL, NULL, dbparam, userparam, pwparam);
925
926                 if (PQstatus(pset.db) == CONNECTION_BAD &&
927                         strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0)
928                 {
929                         need_pass = true;
930                         free(prompted_password);
931                         prompted_password = NULL;
932                         pwparam = prompted_password = simple_prompt("Password: ", 100, false);
933                 }
934         } while (need_pass);
935
936         free(prompted_password);
937
938         /*
939          * If connection failed, try at least keep the old one. That's
940          * probably more convenient than just kicking you out of the program.
941          */
942         if (!pset.db || PQstatus(pset.db) == CONNECTION_BAD)
943         {
944         if (pset.cur_cmd_interactive)
945         {
946             psql_error("%s", PQerrorMessage(pset.db));
947             PQfinish(pset.db);
948             if (oldconn)
949             {
950                 fputs("Previous connection kept\n", stderr);
951                 pset.db = oldconn;
952             }
953             else
954                 pset.db = NULL;
955         }
956         else
957         {
958             /* we don't want unpredictable things to
959              * happen in scripting mode */
960             psql_error("\\connect: %s", PQerrorMessage(pset.db));
961             PQfinish(pset.db);
962                         if (oldconn)
963                                 PQfinish(oldconn);
964             pset.db = NULL;
965                 }
966         }
967         else
968         {
969                 if (!QUIET())
970                 {
971                         if (userparam != new_user)      /* no new user */
972                                 printf("You are now connected to database %s.\n", dbparam);
973                         else if (dbparam != new_dbname)         /* no new db */
974                                 printf("You are now connected as new user %s.\n", new_user);
975                         else /* both new */
976                                 printf("You are now connected to database %s as user %s.\n",
977                                            PQdb(pset.db), PQuser(pset.db));
978                 }
979
980                 if (oldconn)
981                         PQfinish(oldconn);
982
983                 success = true;
984         }
985
986     PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
987     pset.encoding = PQclientencoding(pset.db);
988
989     /* Update variables */
990     SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
991     SetVariable(pset.vars, "USER", PQuser(pset.db));
992     SetVariable(pset.vars, "HOST", PQhost(pset.db));
993     SetVariable(pset.vars, "PORT", PQport(pset.db));
994
995         return success;
996 }
997
998
999
1000 /*
1001  * do_edit -- handler for \e
1002  *
1003  * If you do not specify a filename, the current query buffer will be copied
1004  * into a temporary one.
1005  */
1006
1007 static bool
1008 editFile(const char *fname)
1009 {
1010         char       *editorName;
1011         char       *sys;
1012         int                     result;
1013
1014 #ifdef USE_ASSERT_CHECKING
1015         assert(fname);
1016 #else
1017         if (!fname)
1018                 return false;
1019 #endif
1020
1021         /* Find an editor to use */
1022         editorName = getenv("PSQL_EDITOR");
1023         if (!editorName)
1024                 editorName = getenv("EDITOR");
1025         if (!editorName)
1026                 editorName = getenv("VISUAL");
1027         if (!editorName)
1028                 editorName = DEFAULT_EDITOR;
1029
1030         sys = malloc(strlen(editorName) + strlen(fname) + 32 + 1);
1031         if (!sys)
1032                 return false;
1033         sprintf(sys, "exec %s %s", editorName, fname);
1034         result = system(sys);
1035         if (result == -1)
1036         psql_error("could not start editor\n");
1037     else if (result == 127)
1038                 psql_error("could not start /bin/sh\n");
1039         free(sys);
1040
1041         return result == 0;
1042 }
1043
1044
1045 /* call this one */
1046 static bool
1047 do_edit(const char *filename_arg, PQExpBuffer query_buf)
1048 {
1049         char            fnametmp[MAXPGPATH];
1050         FILE       *stream;
1051         const char *fname;
1052         bool            error = false;
1053
1054 #ifndef WIN32
1055         struct stat before,
1056                                 after;
1057
1058 #endif
1059
1060 #ifdef USE_ASSERT_CHECKING
1061         assert(query_buf);
1062 #else
1063         if (!query_buf)
1064                 return false;
1065 #endif
1066
1067
1068         if (filename_arg)
1069                 fname = filename_arg;
1070
1071         else
1072         {
1073                 /* make a temp file to edit */
1074 #ifndef WIN32
1075                 mode_t          oldumask;
1076         const char *tmpdirenv = getenv("TMPDIR");
1077
1078                 sprintf(fnametmp, "%s/psql.edit.%ld.%ld",
1079                 tmpdirenv ? tmpdirenv : "/tmp",
1080                 (long) geteuid(), (long) getpid());
1081 #else
1082                 GetTempFileName(".", "psql", 0, fnametmp);
1083 #endif
1084                 fname = (const char *) fnametmp;
1085
1086 #ifndef WIN32
1087                 oldumask = umask(0177);
1088 #endif
1089                 stream = fopen(fname, "w");
1090 #ifndef WIN32
1091                 umask(oldumask);
1092 #endif
1093
1094                 if (!stream)
1095                 {
1096             psql_error("couldn't open temp file %s: %s\n", fname, strerror(errno));
1097                         error = true;
1098                 }
1099                 else
1100                 {
1101                         unsigned int ql = query_buf->len;
1102
1103                         if (ql == 0 || query_buf->data[ql - 1] != '\n')
1104                         {
1105                                 appendPQExpBufferChar(query_buf, '\n');
1106                                 ql++;
1107                         }
1108
1109                         if (fwrite(query_buf->data, 1, ql, stream) != ql)
1110                         {
1111                 psql_error("%s: %s\n", fname, strerror(errno));
1112                                 fclose(stream);
1113                                 remove(fname);
1114                                 error = true;
1115                         }
1116                         else
1117                                 fclose(stream);
1118                 }
1119         }
1120
1121 #ifndef WIN32
1122         if (!error && stat(fname, &before) != 0)
1123         {
1124         psql_error("%s: %s\n", fname, strerror(errno));
1125                 error = true;
1126         }
1127 #endif
1128
1129         /* call editor */
1130         if (!error)
1131                 error = !editFile(fname);
1132
1133 #ifndef WIN32
1134         if (!error && stat(fname, &after) != 0)
1135         {
1136         psql_error("%s: %s\n", fname, strerror(errno));
1137                 error = true;
1138         }
1139
1140         if (!error && before.st_mtime != after.st_mtime)
1141         {
1142 #else
1143         if (!error)
1144         {
1145 #endif
1146                 stream = fopen(fname, "r");
1147                 if (!stream)
1148                 {
1149             psql_error("%s: %s\n", fname, strerror(errno));
1150                         error = true;
1151                 }
1152                 else
1153                 {
1154                         /* read file back in */
1155                         char            line[1024];
1156                         size_t          result;
1157
1158                         resetPQExpBuffer(query_buf);
1159                         do
1160                         {
1161                                 result = fread(line, 1, 1024, stream);
1162                                 if (ferror(stream))
1163                                 {
1164                     psql_error("%s: %s\n", fname, strerror(errno));
1165                                         error = true;
1166                                         break;
1167                                 }
1168                                 appendBinaryPQExpBuffer(query_buf, line, result);
1169                         } while (!feof(stream));
1170                         appendPQExpBufferChar(query_buf, '\0');
1171
1172                         fclose(stream);
1173                 }
1174
1175                 /* remove temp file */
1176                 if (!filename_arg)
1177         {
1178                         if (remove(fname)==-1)
1179             {
1180                 psql_error("%s: %s\n", fname, strerror(errno));
1181                 error=true;
1182             }
1183         }
1184     }
1185         return !error;
1186 }
1187
1188
1189
1190 /*
1191  * process_file
1192  *
1193  * Read commands from filename and then them to the main processing loop
1194  * Handler for \i, but can be used for other things as well.
1195  */
1196 bool
1197 process_file(char *filename)
1198 {
1199         FILE       *fd;
1200         int                     result;
1201
1202         if (!filename)
1203                 return false;
1204
1205 #ifdef __CYGWIN32__
1206         fd = fopen(filename, "rb");
1207 #else
1208         fd = fopen(filename, "r");
1209 #endif
1210
1211         if (!fd)
1212         {
1213         psql_error("%s: %s\n", filename, strerror(errno));
1214                 return false;
1215         }
1216
1217     pset.inputfile = filename;
1218         result = MainLoop(fd);
1219         fclose(fd);
1220         pset.inputfile = NULL;
1221         return (result == EXIT_SUCCESS);
1222 }
1223
1224
1225
1226 /*
1227  * do_pset
1228  *
1229  */
1230 static const char *
1231 _align2string(enum printFormat in)
1232 {
1233         switch (in)
1234         {
1235                         case PRINT_NOTHING:
1236                         return "nothing";
1237                         break;
1238                 case PRINT_UNALIGNED:
1239                         return "unaligned";
1240                         break;
1241                 case PRINT_ALIGNED:
1242                         return "aligned";
1243                         break;
1244                 case PRINT_HTML:
1245                         return "html";
1246                         break;
1247                 case PRINT_LATEX:
1248                         return "latex";
1249                         break;
1250         }
1251         return "unknown";
1252 }
1253
1254
1255 bool
1256 do_pset(const char *param, const char *value, printQueryOpt * popt, bool quiet)
1257 {
1258         size_t          vallen = 0;
1259
1260 #ifdef USE_ASSERT_CHECKING
1261         assert(param);
1262 #else
1263         if (!param)
1264                 return false;
1265 #endif
1266
1267         if (value)
1268                 vallen = strlen(value);
1269
1270         /* set format */
1271         if (strcmp(param, "format") == 0)
1272         {
1273                 if (!value)
1274                         ;
1275                 else if (strncasecmp("unaligned", value, vallen) == 0)
1276                         popt->topt.format = PRINT_UNALIGNED;
1277                 else if (strncasecmp("aligned", value, vallen) == 0)
1278                         popt->topt.format = PRINT_ALIGNED;
1279                 else if (strncasecmp("html", value, vallen) == 0)
1280                         popt->topt.format = PRINT_HTML;
1281                 else if (strncasecmp("latex", value, vallen) == 0)
1282                         popt->topt.format = PRINT_LATEX;
1283                 else
1284                 {
1285                         psql_error("\\pset: allowed formats are unaligned, aligned, html, latex\n");
1286                         return false;
1287                 }
1288
1289                 if (!quiet)
1290                         printf("Output format is %s.\n", _align2string(popt->topt.format));
1291         }
1292
1293         /* set border style/width */
1294         else if (strcmp(param, "border") == 0)
1295         {
1296                 if (value)
1297                         popt->topt.border = atoi(value);
1298
1299                 if (!quiet)
1300                         printf("Border style is %d.\n", popt->topt.border);
1301         }
1302
1303         /* set expanded/vertical mode */
1304         else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
1305         {
1306                 popt->topt.expanded = !popt->topt.expanded;
1307                 if (!quiet)
1308                         printf("Expanded display is %s.\n", popt->topt.expanded ? "on" : "off");
1309         }
1310
1311         /* null display */
1312         else if (strcmp(param, "null") == 0)
1313         {
1314                 if (value)
1315                 {
1316                         free(popt->nullPrint);
1317                         popt->nullPrint = xstrdup(value);
1318                 }
1319                 if (!quiet)
1320                         printf("Null display is \"%s\".\n", popt->nullPrint ? popt->nullPrint : "");
1321         }
1322
1323         /* field separator for unaligned text */
1324         else if (strcmp(param, "fieldsep") == 0)
1325         {
1326                 if (value)
1327                 {
1328                         free(popt->topt.fieldSep);
1329                         popt->topt.fieldSep = xstrdup(value);
1330                 }
1331                 if (!quiet)
1332                         printf("Field separator is '%s'.\n", popt->topt.fieldSep);
1333         }
1334
1335         /* record separator for unaligned text */
1336         else if (strcmp(param, "recordsep") == 0)
1337         {
1338                 if (value)
1339                 {
1340                         free(popt->topt.recordSep);
1341                         popt->topt.recordSep = xstrdup(value);
1342                 }
1343                 if (!quiet) {
1344             if (strcmp(popt->topt.recordSep, "\n")==0)
1345                 printf("Record separator is <newline>.");
1346             else
1347                 printf("Record separator is '%s'.\n", popt->topt.recordSep);
1348         }
1349         }
1350
1351         /* toggle between full and barebones format */
1352         else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
1353         {
1354                 popt->topt.tuples_only = !popt->topt.tuples_only;
1355                 if (!quiet)
1356                 {
1357                         if (popt->topt.tuples_only)
1358                                 puts("Showing only tuples.");
1359                         else
1360                                 puts("Tuples only is off.");
1361                 }
1362         }
1363
1364         /* set title override */
1365         else if (strcmp(param, "title") == 0)
1366         {
1367                 free(popt->title);
1368                 if (!value)
1369                         popt->title = NULL;
1370                 else
1371                         popt->title = xstrdup(value);
1372
1373                 if (!quiet)
1374                 {
1375                         if (popt->title)
1376                                 printf("Title is \"%s\".\n", popt->title);
1377                         else
1378                                 printf("Title is unset.\n");
1379                 }
1380         }
1381
1382         /* set HTML table tag options */
1383         else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
1384         {
1385                 free(popt->topt.tableAttr);
1386                 if (!value)
1387                         popt->topt.tableAttr = NULL;
1388                 else
1389                         popt->topt.tableAttr = xstrdup(value);
1390
1391                 if (!quiet)
1392                 {
1393                         if (popt->topt.tableAttr)
1394                                 printf("Table attribute is \"%s\".\n", popt->topt.tableAttr);
1395                         else
1396                                 printf("Table attributes unset.\n");
1397                 }
1398         }
1399
1400         /* toggle use of pager */
1401         else if (strcmp(param, "pager") == 0)
1402         {
1403                 popt->topt.pager = !popt->topt.pager;
1404                 if (!quiet)
1405                 {
1406                         if (popt->topt.pager)
1407                                 puts("Using pager is on.");
1408                         else
1409                                 puts("Using pager is off.");
1410                 }
1411         }
1412
1413
1414         else
1415         {
1416                 psql_error("\\pset: unknown option: %s\n", param);
1417                 return false;
1418         }
1419
1420         return true;
1421 }
1422
1423
1424
1425 #define DEFAULT_SHELL  "/bin/sh"
1426
1427 static bool
1428 do_shell(const char *command)
1429 {
1430         int                     result;
1431
1432         if (!command)
1433         {
1434                 char       *sys;
1435                 char       *shellName;
1436
1437                 shellName = getenv("SHELL");
1438                 if (shellName == NULL)
1439                         shellName = DEFAULT_SHELL;
1440
1441                 sys = malloc(strlen(shellName) + 16);
1442                 if (!sys) {
1443             psql_error("out of memory\n");
1444             if (pset.cur_cmd_interactive)
1445                 return false;
1446             else
1447                 exit(EXIT_FAILURE);
1448         }
1449                 sprintf(sys, "exec %s", shellName);
1450                 result = system(sys);
1451                 free(sys);
1452         }
1453         else
1454                 result = system(command);
1455
1456         if (result == 127 || result == -1)
1457         {
1458         psql_error("\\!: failed\n");
1459                 return false;
1460         }
1461         return true;
1462 }