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