]> granicus.if.org Git - postgresql/blob - src/bin/psql/command.c
TODO marked as done:
[postgresql] / src / bin / psql / command.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright 2000-2002 by PostgreSQL Global Development Group
5  *
6  * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.86 2002/12/12 21:02:21 momjian Exp $
7  */
8 #include "postgres_fe.h"
9 #include "command.h"
10
11 #include <errno.h>
12 #include <assert.h>
13 #include <ctype.h>
14 #ifdef HAVE_PWD_H
15 #include <pwd.h>
16 #endif
17 #ifndef WIN32
18 #include <sys/types.h>                  /* for umask() */
19 #include <sys/stat.h>                   /* for stat() */
20 #include <fcntl.h>                              /* open() flags */
21 #include <unistd.h>                             /* for geteuid(), getpid(), stat() */
22 #else
23 #include <win32.h>
24 #include <io.h>
25 #include <fcntl.h>
26 #include <direct.h>
27 #endif
28
29 #include "libpq-fe.h"
30 #include "pqexpbuffer.h"
31
32 #include "common.h"
33 #include "copy.h"
34 #include "describe.h"
35 #include "help.h"
36 #include "input.h"
37 #include "large_obj.h"
38 #include "mainloop.h"
39 #include "print.h"
40 #include "settings.h"
41 #include "variables.h"
42 #include "mb/pg_wchar.h"
43
44 /* functions for use in this file */
45
46 static backslashResult exec_command(const char *cmd,
47                          const char *options_string,
48                          const char **continue_parse,
49                          PQExpBuffer query_buf,
50                          volatile int *paren_level);
51
52 /* different ways for scan_option to handle parameter words */
53 enum option_type
54 {
55         OT_NORMAL,                                      /* normal case */
56         OT_SQLID,                                       /* treat as SQL identifier */
57         OT_SQLIDHACK,                           /* SQL identifier, but don't downcase */
58         OT_FILEPIPE                                     /* it's a filename or pipe */
59 };
60
61 static char *scan_option(char **string, enum option_type type,
62                         char *quote, bool semicolon);
63 static char *unescape(const unsigned char *source, size_t len);
64
65 static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
66 static bool do_connect(const char *new_dbname, const char *new_user);
67 static bool do_shell(const char *command);
68
69
70
71 /*----------
72  * HandleSlashCmds:
73  *
74  * Handles all the different commands that start with '\',
75  * ordinarily called by MainLoop().
76  *
77  * 'line' is the current input line, which should not start with a '\'
78  * but with the actual command name
79  * (that is taken care of by MainLoop)
80  *
81  * 'query_buf' contains the query-so-far, which may be modified by
82  * execution of the backslash command (for example, \r clears it)
83  * query_buf can be NULL if there is no query so far.
84  *
85  * Returns a status code indicating what action is desired, see command.h.
86  *----------
87  */
88
89 backslashResult
90 HandleSlashCmds(const char *line,
91                                 PQExpBuffer query_buf,
92                                 const char **end_of_cmd,
93                                 volatile int *paren_level)
94 {
95         backslashResult status = CMD_SKIP_LINE;
96         char       *my_line;
97         char       *options_string = NULL;
98         size_t          blank_loc;
99         const char *continue_parse = NULL;      /* tell the mainloop where the
100                                                                                  * backslash command ended */
101
102 #ifdef USE_ASSERT_CHECKING
103         assert(line);
104 #endif
105
106         my_line = xstrdup(line);
107
108         /*
109          * Find the first whitespace. line[blank_loc] will now be the
110          * whitespace character or the \0 at the end
111          *
112          * Also look for a backslash, so stuff like \p\g works.
113          */
114         blank_loc = strcspn(my_line, " \t\n\r\\");
115
116         if (my_line[blank_loc] == '\\')
117         {
118                 continue_parse = &my_line[blank_loc];
119                 my_line[blank_loc] = '\0';
120                 /* If it's a double backslash, we skip it. */
121                 if (my_line[blank_loc + 1] == '\\')
122                         continue_parse += 2;
123         }
124         /* do we have an option string? */
125         else if (my_line[blank_loc] != '\0')
126         {
127                 options_string = &my_line[blank_loc + 1];
128                 my_line[blank_loc] = '\0';
129         }
130
131         status = exec_command(my_line, options_string, &continue_parse, query_buf, paren_level);
132
133         if (status == CMD_UNKNOWN)
134         {
135                 /*
136                  * If the command was not recognized, try to parse it as a
137                  * one-letter command with immediately following argument (a
138                  * still-supported, but no longer encouraged, syntax).
139                  */
140                 char            new_cmd[2];
141
142                 new_cmd[0] = my_line[0];
143                 new_cmd[1] = '\0';
144
145                 /* use line for options, because my_line was clobbered above */
146                 status = exec_command(new_cmd, line + 1, &continue_parse, query_buf, paren_level);
147
148                 /*
149                  * continue_parse must be relative to my_line for calculation
150                  * below
151                  */
152                 continue_parse += my_line - line;
153
154 #if 0                                                   /* turned out to be too annoying */
155                 if (status != CMD_UNKNOWN && isalpha((unsigned char) new_cmd[0]))
156                         psql_error("Warning: This syntax is deprecated.\n");
157 #endif
158         }
159
160         if (status == CMD_UNKNOWN)
161         {
162                 if (pset.cur_cmd_interactive)
163                         fprintf(stderr, gettext("Invalid command \\%s. Try \\? for help.\n"), my_line);
164                 else
165                         psql_error("invalid command \\%s\n", my_line);
166                 status = CMD_ERROR;
167         }
168
169         if (continue_parse && *continue_parse && *(continue_parse + 1) == '\\')
170                 continue_parse += 2;
171
172         if (end_of_cmd)
173         {
174                 if (continue_parse)
175                         *end_of_cmd = line + (continue_parse - my_line);
176                 else
177                         *end_of_cmd = line + strlen(line);
178         }
179
180         free(my_line);
181
182         return status;
183 }
184
185
186
187 static backslashResult
188 exec_command(const char *cmd,
189                          const char *options_string,
190                          const char **continue_parse,
191                          PQExpBuffer query_buf,
192                          volatile int *paren_level)
193 {
194         bool            success = true; /* indicate here if the command ran ok or
195                                                                  * failed */
196         bool            quiet = QUIET();
197         backslashResult status = CMD_SKIP_LINE;
198         char       *string,
199                            *string_cpy,
200                            *val;
201
202         /*
203          * The 'string' variable will be overwritten to point to the next
204          * token, hence we need an extra pointer so we can free this at the
205          * end.
206          */
207         if (options_string)
208                 string = string_cpy = xstrdup(options_string);
209         else
210                 string = string_cpy = NULL;
211
212         /*
213          * \a -- toggle field alignment This makes little sense but we keep it
214          * around.
215          */
216         if (strcmp(cmd, "a") == 0)
217         {
218                 if (pset.popt.topt.format != PRINT_ALIGNED)
219                         success = do_pset("format", "aligned", &pset.popt, quiet);
220                 else
221                         success = do_pset("format", "unaligned", &pset.popt, quiet);
222         }
223
224         /* \C -- override table title (formerly change HTML caption) */
225         else if (strcmp(cmd, "C") == 0)
226         {
227                 char       *opt = scan_option(&string, OT_NORMAL, NULL, true);
228
229                 success = do_pset("title", opt, &pset.popt, quiet);
230                 free(opt);
231         }
232
233         /*----------
234          * \c or \connect -- connect to new database or as different user
235          *
236          * \c foo bar  connect to db "foo" as user "bar"
237          * \c foo [-]  connect to db "foo" as current user
238          * \c - bar    connect to current db as user "bar"
239          * \c              connect to default db as default user
240          *----------
241          */
242         else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
243         {
244                 char       *opt1,
245                                    *opt2;
246                 char            opt1q,
247                                         opt2q;
248
249                 /*
250                  * Ideally we should treat the arguments as SQL identifiers.  But
251                  * for backwards compatibility with 7.2 and older pg_dump files,
252                  * we have to take unquoted arguments verbatim (don't downcase
253                  * them). For now, double-quoted arguments may be stripped of
254                  * double quotes (as if SQL identifiers).  By 7.4 or so, pg_dump
255                  * files can be expected to double-quote all mixed-case \connect
256                  * arguments, and then we can get rid of OT_SQLIDHACK.
257                  */
258                 opt1 = scan_option(&string, OT_SQLIDHACK, &opt1q, true);
259                 opt2 = scan_option(&string, OT_SQLIDHACK, &opt2q, true);
260
261                 if (opt2)
262                         /* gave username */
263                         success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || strcmp(opt1, "") == 0) ? "" : opt1,
264                                                                  !opt2q && (strcmp(opt2, "-") == 0 || strcmp(opt2, "") == 0) ? "" : opt2);
265                 else if (opt1)
266                         /* gave database name */
267                         success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || strcmp(opt1, "") == 0) ? "" : opt1, "");
268                 else
269                         /* connect to default db as default user */
270                         success = do_connect(NULL, NULL);
271
272                 free(opt1);
273                 free(opt2);
274         }
275
276         /* \cd */
277         else if (strcmp(cmd, "cd") == 0)
278         {
279                 char       *opt = scan_option(&string, OT_NORMAL, NULL, true);
280                 char       *dir;
281
282                 if (opt)
283                         dir = opt;
284                 else
285                 {
286 #ifndef WIN32
287                         struct passwd *pw;
288
289                         pw = getpwuid(geteuid());
290                         if (!pw)
291                         {
292                                 psql_error("could not get home directory: %s\n", strerror(errno));
293                                 exit(EXIT_FAILURE);
294                         }
295                         dir = pw->pw_dir;
296 #else                                                   /* WIN32 */
297
298                         /*
299                          * On Windows, 'cd' without arguments prints the current
300                          * directory, so if someone wants to code this here instead...
301                          */
302                         dir = "/";
303 #endif   /* WIN32 */
304                 }
305
306                 if (chdir(dir) == -1)
307                 {
308                         psql_error("\\%s: could not change directory to '%s': %s\n",
309                                            cmd, dir, strerror(errno));
310                         success = false;
311                 }
312
313                 if (opt)
314                         free(opt);
315         }
316
317         /* \copy */
318         else if (strcasecmp(cmd, "copy") == 0)
319         {
320                 success = do_copy(options_string);
321                 if (options_string)
322                         string += strlen(string);
323         }
324
325         /* \copyright */
326         else if (strcmp(cmd, "copyright") == 0)
327                 print_copyright();
328
329         /* \d* commands */
330         else if (cmd[0] == 'd')
331         {
332                 char       *pattern;
333                 bool            show_verbose;
334
335                 /* We don't do SQLID reduction on the pattern yet */
336                 pattern = scan_option(&string, OT_NORMAL, NULL, true);
337
338                 show_verbose = strchr(cmd, '+') ? true : false;
339
340                 switch (cmd[1])
341                 {
342                         case '\0':
343                         case '+':
344                                 if (pattern)
345                                         success = describeTableDetails(pattern, show_verbose);
346                                 else
347                                         /* standard listing of interesting things */
348                                         success = listTables("tvs", NULL, show_verbose);
349                                 break;
350                         case 'a':
351                                 success = describeAggregates(pattern, show_verbose);
352                                 break;
353                         case 'd':
354                                 success = objectDescription(pattern);
355                                 break;
356                         case 'f':
357                                 success = describeFunctions(pattern, show_verbose);
358                                 break;
359                         case 'l':
360                                 success = do_lo_list();
361                                 break;
362                         case 'o':
363                                 success = describeOperators(pattern);
364                                 break;
365                         case 'p':
366                                 success = permissionsList(pattern);
367                                 break;
368                         case 'T':
369                                 success = describeTypes(pattern, show_verbose);
370                                 break;
371                         case 't':
372                         case 'v':
373                         case 'i':
374                         case 's':
375                         case 'S':
376                                 success = listTables(&cmd[1], pattern, show_verbose);
377                                 break;
378                         case 'u':
379                                 success = describeUsers(pattern);
380                                 break;
381                         case 'D':
382                                 success = listDomains(pattern);
383                                 break;
384                         case 'c':
385                                 success = listConversions(pattern);
386                                 break;
387                         case 'C':
388                                 success = listCasts(pattern);
389                                 break;
390                                 
391                         default:
392                                 status = CMD_UNKNOWN;
393                 }
394
395                 if (pattern)
396                         free(pattern);
397         }
398
399
400         /*
401          * \e or \edit -- edit the current query buffer (or a file and make it
402          * the query buffer
403          */
404         else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
405         {
406                 char       *fname;
407
408                 if (!query_buf)
409                 {
410                         psql_error("no query buffer\n");
411                         status = CMD_ERROR;
412                 }
413                 else
414                 {
415                         fname = scan_option(&string, OT_NORMAL, NULL, true);
416                         status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;
417                         free(fname);
418                 }
419         }
420
421         /* \echo and \qecho */
422         else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
423         {
424                 char       *value;
425                 char            quoted;
426                 bool            no_newline = false;
427                 bool            first = true;
428                 FILE       *fout;
429
430                 if (strcmp(cmd, "qecho") == 0)
431                         fout = pset.queryFout;
432                 else
433                         fout = stdout;
434
435                 while ((value = scan_option(&string, OT_NORMAL, &quoted, false)))
436                 {
437                         if (!quoted && strcmp(value, "-n") == 0)
438                                 no_newline = true;
439                         else
440                         {
441                                 if (first)
442                                         first = false;
443                                 else
444                                         fputc(' ', fout);
445                                 fputs(value, fout);
446                         }
447                         free(value);
448                 }
449                 if (!no_newline)
450                         fputs("\n", fout);
451         }
452
453         /* \encoding -- set/show client side encoding */
454         else if (strcmp(cmd, "encoding") == 0)
455         {
456                 char       *encoding = scan_option(&string, OT_NORMAL, NULL, false);
457
458                 if (!encoding)
459                         /* show encoding */
460                         puts(pg_encoding_to_char(pset.encoding));
461                 else
462                 {
463                         /* set encoding */
464                         if (PQsetClientEncoding(pset.db, encoding) == -1)
465                                 psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
466
467                         else
468                         {
469                                 /* save encoding info into psql internal data */
470                                 pset.encoding = PQclientEncoding(pset.db);
471                                 SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
472                         }
473                         free(encoding);
474                 }
475         }
476
477         /* \f -- change field separator */
478         else if (strcmp(cmd, "f") == 0)
479         {
480                 char       *fname = scan_option(&string, OT_NORMAL, NULL, false);
481
482                 success = do_pset("fieldsep", fname, &pset.popt, quiet);
483                 free(fname);
484         }
485
486         /* \g means send query */
487         else if (strcmp(cmd, "g") == 0)
488         {
489                 char       *fname = scan_option(&string, OT_FILEPIPE, NULL, false);
490
491                 if (!fname)
492                         pset.gfname = NULL;
493                 else
494                         pset.gfname = xstrdup(fname);
495                 free(fname);
496                 status = CMD_SEND;
497         }
498
499         /* help */
500         else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
501         {
502                 helpSQL(options_string ? &options_string[strspn(options_string, " \t\n\r")] : NULL,
503                                 pset.popt.topt.pager);
504                 /* set pointer to end of line */
505                 if (string)
506                         string += strlen(string);
507         }
508
509         /* HTML mode */
510         else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
511         {
512                 if (pset.popt.topt.format != PRINT_HTML)
513                         success = do_pset("format", "html", &pset.popt, quiet);
514                 else
515                         success = do_pset("format", "aligned", &pset.popt, quiet);
516         }
517
518
519         /* \i is include file */
520         else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
521         {
522                 char       *fname = scan_option(&string, OT_NORMAL, NULL, true);
523
524                 if (!fname)
525                 {
526                         psql_error("\\%s: missing required argument\n", cmd);
527                         success = false;
528                 }
529                 else
530                 {
531                         success = (process_file(fname) == EXIT_SUCCESS);
532                         free(fname);
533                 }
534         }
535
536         /* \l is list databases */
537         else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
538                 success = listAllDbs(false);
539         else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
540                 success = listAllDbs(true);
541
542         /*
543          * large object things
544          */
545         else if (strncmp(cmd, "lo_", 3) == 0)
546         {
547                 char       *opt1,
548                                    *opt2;
549
550                 opt1 = scan_option(&string, OT_NORMAL, NULL, true);
551                 opt2 = scan_option(&string, OT_NORMAL, NULL, true);
552
553                 if (strcmp(cmd + 3, "export") == 0)
554                 {
555                         if (!opt2)
556                         {
557                                 psql_error("\\%s: missing required argument\n", cmd);
558                                 success = false;
559                         }
560                         else
561                                 success = do_lo_export(opt1, opt2);
562                 }
563
564                 else if (strcmp(cmd + 3, "import") == 0)
565                 {
566                         if (!opt1)
567                         {
568                                 psql_error("\\%s: missing required argument\n", cmd);
569                                 success = false;
570                         }
571                         else
572                                 success = do_lo_import(opt1, opt2);
573                 }
574
575                 else if (strcmp(cmd + 3, "list") == 0)
576                         success = do_lo_list();
577
578                 else if (strcmp(cmd + 3, "unlink") == 0)
579                 {
580                         if (!opt1)
581                         {
582                                 psql_error("\\%s: missing required argument\n", cmd);
583                                 success = false;
584                         }
585                         else
586                                 success = do_lo_unlink(opt1);
587                 }
588
589                 else
590                         status = CMD_UNKNOWN;
591
592                 free(opt1);
593                 free(opt2);
594         }
595
596
597         /* \o -- set query output */
598         else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
599         {
600                 char       *fname = scan_option(&string, OT_FILEPIPE, NULL, true);
601
602                 success = setQFout(fname);
603                 free(fname);
604         }
605
606         /* \p prints the current query buffer */
607         else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
608         {
609                 if (query_buf && query_buf->len > 0)
610                         puts(query_buf->data);
611                 else if (!quiet)
612                         puts(gettext("Query buffer is empty."));
613                 fflush(stdout);
614         }
615
616         /* \pset -- set printing parameters */
617         else if (strcmp(cmd, "pset") == 0)
618         {
619                 char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);
620                 char       *opt1 = scan_option(&string, OT_NORMAL, NULL, false);
621
622                 if (!opt0)
623                 {
624                         psql_error("\\%s: missing required argument\n", cmd);
625                         success = false;
626                 }
627                 else
628                         success = do_pset(opt0, opt1, &pset.popt, quiet);
629
630                 free(opt0);
631                 free(opt1);
632         }
633
634         /* \q or \quit */
635         else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
636                 status = CMD_TERMINATE;
637
638         /* reset(clear) the buffer */
639         else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
640         {
641                 resetPQExpBuffer(query_buf);
642                 if (paren_level)
643                         *paren_level = 0;
644                 if (!quiet)
645                         puts(gettext("Query buffer reset (cleared)."));
646         }
647
648         /* \s save history in a file or show it on the screen */
649         else if (strcmp(cmd, "s") == 0)
650         {
651                 char       *fname = scan_option(&string, OT_NORMAL, NULL, true);
652
653                 success = saveHistory(fname ? fname : "/dev/tty");
654
655                 if (success && !quiet && fname)
656                         printf(gettext("Wrote history to %s.\n"), fname);
657                 free(fname);
658         }
659
660         /* \set -- generalized set variable/option command */
661         else if (strcmp(cmd, "set") == 0)
662         {
663                 char       *opt0 = scan_option(&string, OT_NORMAL, NULL, false);
664
665                 if (!opt0)
666                 {
667                         /* list all variables */
668
669                         /*
670                          * XXX This is in utter violation of the GetVariable
671                          * abstraction, but I have not bothered to do it better.
672                          */
673                         struct _variable *ptr;
674
675                         for (ptr = pset.vars; ptr->next; ptr = ptr->next)
676                                 fprintf(stdout, "%s = '%s'\n", ptr->next->name, ptr->next->value);
677                         success = true;
678                 }
679                 else
680                 {
681                         /*
682                          * Set variable to the concatenation of the arguments.
683                          */
684                         char       *newval = NULL;
685                         char       *opt;
686
687                         opt = scan_option(&string, OT_NORMAL, NULL, false);
688                         newval = xstrdup(opt ? opt : "");
689                         free(opt);
690
691                         while ((opt = scan_option(&string, OT_NORMAL, NULL, false)))
692                         {
693                                 newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
694                                 if (!newval)
695                                 {
696                                         psql_error("out of memory\n");
697                                         exit(EXIT_FAILURE);
698                                 }
699                                 strcat(newval, opt);
700                                 free(opt);
701                         }
702
703                         if (!SetVariable(pset.vars, opt0, newval))
704                         {
705                                 psql_error("\\%s: error\n", cmd);
706                                 success = false;
707                         }
708                         free(newval);
709                 }
710                 free(opt0);
711         }
712
713         /* \t -- turn off headers and row count */
714         else if (strcmp(cmd, "t") == 0)
715                 success = do_pset("tuples_only", NULL, &pset.popt, quiet);
716
717
718         /* \T -- define html <table ...> attributes */
719         else if (strcmp(cmd, "T") == 0)
720         {
721                 char       *value = scan_option(&string, OT_NORMAL, NULL, false);
722
723                 success = do_pset("tableattr", value, &pset.popt, quiet);
724                 free(value);
725         }
726
727         /* \timing -- toggle timing of queries */
728         else if (strcmp(cmd, "timing") == 0)
729         {
730                 pset.timing = !pset.timing;
731                 if (!quiet)
732                 {
733                         if (pset.timing)
734                                 puts(gettext(("Timing is on.")));
735                         else
736                         {
737                                 puts(gettext(("Timing is off.")));
738
739                         }
740                 }
741         }
742
743         /* \unset */
744         else if (strcmp(cmd, "unset") == 0)
745         {
746                 char       *opt = scan_option(&string, OT_NORMAL, NULL, false);
747
748                 if (!opt)
749                 {
750                         psql_error("\\%s: missing required argument\n", cmd);
751                         success = false;
752                 }
753                 else if (!SetVariable(pset.vars, opt, NULL))
754                 {
755                         psql_error("\\%s: error\n", cmd);
756                         success = false;
757                 }
758                 free(opt);
759         }
760
761         /* \w -- write query buffer to file */
762         else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
763         {
764                 FILE       *fd = NULL;
765                 bool            is_pipe = false;
766                 char       *fname = NULL;
767
768                 if (!query_buf)
769                 {
770                         psql_error("no query buffer\n");
771                         status = CMD_ERROR;
772                 }
773                 else
774                 {
775                         fname = scan_option(&string, OT_FILEPIPE, NULL, true);
776
777                         if (!fname)
778                         {
779                                 psql_error("\\%s: missing required argument\n", cmd);
780                                 success = false;
781                         }
782                         else
783                         {
784                                 if (fname[0] == '|')
785                                 {
786                                         is_pipe = true;
787                                         fd = popen(&fname[1], "w");
788                                 }
789                                 else
790                                         fd = fopen(fname, "w");
791
792                                 if (!fd)
793                                 {
794                                         psql_error("%s: %s\n", fname, strerror(errno));
795                                         success = false;
796                                 }
797                         }
798                 }
799
800                 if (fd)
801                 {
802                         int                     result;
803
804                         if (query_buf && query_buf->len > 0)
805                                 fprintf(fd, "%s\n", query_buf->data);
806
807                         if (is_pipe)
808                                 result = pclose(fd);
809                         else
810                                 result = fclose(fd);
811
812                         if (result == EOF)
813                         {
814                                 psql_error("%s: %s\n", fname, strerror(errno));
815                                 success = false;
816                         }
817                 }
818
819                 free(fname);
820         }
821
822         /* \x -- toggle expanded table representation */
823         else if (strcmp(cmd, "x") == 0)
824                 success = do_pset("expanded", NULL, &pset.popt, quiet);
825
826
827         /* \z -- list table rights (equivalent to \dp) */
828         else if (strcmp(cmd, "z") == 0)
829         {
830                 char       *pattern = scan_option(&string, OT_NORMAL, NULL, true);
831
832                 success = permissionsList(pattern);
833                 if (pattern)
834                         free(pattern);
835         }
836
837         /* \! -- shell escape */
838         else if (strcmp(cmd, "!") == 0)
839         {
840                 success = do_shell(options_string);
841                 /* wind pointer to end of line */
842                 if (string)
843                         string += strlen(string);
844         }
845
846         /* \? -- slash command help */
847         else if (strcmp(cmd, "?") == 0)
848                 slashUsage(pset.popt.topt.pager);
849
850 #if 0
851
852         /*
853          * These commands don't do anything. I just use them to test the
854          * parser.
855          */
856         else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
857         {
858                 int                     i = 0;
859                 char       *value;
860
861                 fprintf(stderr, "+ optstr = |%s|\n", options_string);
862                 while ((value = scan_option(&string, OT_NORMAL, NULL, true)))
863                 {
864                         fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
865                         free(value);
866                 }
867         }
868 #endif
869
870         else
871                 status = CMD_UNKNOWN;
872
873         if (!success)
874                 status = CMD_ERROR;
875
876         /* eat the rest of the options string */
877         while ((val = scan_option(&string, OT_NORMAL, NULL, false)))
878         {
879                 if (status != CMD_UNKNOWN)
880                         psql_error("\\%s: extra argument '%s' ignored\n", cmd, val);
881         }
882
883         if (options_string && continue_parse)
884                 *continue_parse = options_string + (string - string_cpy);
885         free(string_cpy);
886
887         return status;
888 }
889
890
891
892 /*
893  * scan_option()
894  *
895  * *string points to possible option string on entry; on exit, it's updated
896  * to point past the option string (if any).
897  *
898  * type tells what processing, if any, to perform on the option string;
899  * for example, if it's a SQL identifier, we want to downcase any unquoted
900  * letters.
901  *
902  * if quote is not NULL, *quote is set to 0 if no quoting was found, else
903  * the quote symbol.
904  *
905  * if semicolon is true, trailing semicolon(s) that would otherwise be taken
906  * as part of the option string will be stripped.
907  *
908  * Return value is NULL if no option found, else a malloc'd copy of the
909  * processed option value.
910  */
911 static char *
912 scan_option(char **string, enum option_type type, char *quote, bool semicolon)
913 {
914         unsigned int pos;
915         char       *options_string;
916         char       *return_val;
917
918         if (quote)
919                 *quote = 0;
920
921         if (!string || !(*string))
922                 return NULL;
923
924         options_string = *string;
925         /* skip leading whitespace */
926         pos = strspn(options_string, " \t\n\r");
927
928         switch (options_string[pos])
929         {
930                         /*
931                          * End of line: no option present
932                          */
933                 case '\0':
934                         *string = &options_string[pos];
935                         return NULL;
936
937                         /*
938                          * Next command: treat like end of line
939                          *
940                          * XXX this means we can't conveniently accept options that start
941                          * with a backslash; therefore, option processing that
942                          * encourages use of backslashes is rather broken.
943                          */
944                 case '\\':
945                         *string = &options_string[pos];
946                         return NULL;
947
948                         /*
949                          * A single quote has a psql internal meaning, such as for
950                          * delimiting file names, and it also allows for such escape
951                          * sequences as \t.
952                          */
953                 case '\'':
954                         {
955                                 unsigned int jj;
956                                 unsigned short int bslash_count = 0;
957
958                                 for (jj = pos + 1; options_string[jj]; jj += PQmblen(&options_string[jj], pset.encoding))
959                                 {
960                                         if (options_string[jj] == '\'' && bslash_count % 2 == 0)
961                                                 break;
962
963                                         if (options_string[jj] == '\\')
964                                                 bslash_count++;
965                                         else
966                                                 bslash_count = 0;
967                                 }
968
969                                 if (options_string[jj] == 0)
970                                 {
971                                         psql_error("parse error at the end of line\n");
972                                         *string = &options_string[jj];
973                                         return NULL;
974                                 }
975
976                                 return_val = unescape(&options_string[pos + 1], jj - pos - 1);
977                                 *string = &options_string[jj + 1];
978                                 if (quote)
979                                         *quote = '\'';
980                                 return return_val;
981                         }
982
983                         /*
984                          * Backticks are for command substitution, like in shells
985                          */
986                 case '`':
987                         {
988                                 bool            error = false;
989                                 FILE       *fd;
990                                 char       *file;
991                                 PQExpBufferData output;
992                                 char            buf[512];
993                                 size_t          result,
994                                                         len;
995
996                                 len = strcspn(options_string + pos + 1, "`");
997                                 if (options_string[pos + 1 + len] == 0)
998                                 {
999                                         psql_error("parse error at the end of line\n");
1000                                         *string = &options_string[pos + 1 + len];
1001                                         return NULL;
1002                                 }
1003
1004                                 options_string[pos + 1 + len] = '\0';
1005                                 file = options_string + pos + 1;
1006
1007                                 fd = popen(file, "r");
1008                                 if (!fd)
1009                                 {
1010                                         psql_error("%s: %s\n", file, strerror(errno));
1011                                         error = true;
1012                                 }
1013
1014                                 initPQExpBuffer(&output);
1015
1016                                 if (!error)
1017                                 {
1018                                         do
1019                                         {
1020                                                 result = fread(buf, 1, 512, fd);
1021                                                 if (ferror(fd))
1022                                                 {
1023                                                         psql_error("%s: %s\n", file, strerror(errno));
1024                                                         error = true;
1025                                                         break;
1026                                                 }
1027                                                 appendBinaryPQExpBuffer(&output, buf, result);
1028                                         } while (!feof(fd));
1029                                         appendPQExpBufferChar(&output, '\0');
1030                                 }
1031
1032                                 if (fd && pclose(fd) == -1)
1033                                 {
1034                                         psql_error("%s: %s\n", file, strerror(errno));
1035                                         error = true;
1036                                 }
1037
1038                                 if (!error)
1039                                 {
1040                                         if (output.data[strlen(output.data) - 1] == '\n')
1041                                                 output.data[strlen(output.data) - 1] = '\0';
1042                                         return_val = output.data;
1043                                 }
1044                                 else
1045                                 {
1046                                         return_val = xstrdup("");
1047                                         termPQExpBuffer(&output);
1048                                 }
1049
1050                                 options_string[pos + 1 + len] = '`';
1051                                 *string = options_string + pos + len + 2;
1052                                 if (quote)
1053                                         *quote = '`';
1054                                 return return_val;
1055                         }
1056
1057                         /*
1058                          * Variable substitution
1059                          */
1060                 case ':':
1061                         {
1062                                 size_t          token_end;
1063                                 const char *value;
1064                                 char            save_char;
1065
1066                                 token_end = strcspn(&options_string[pos + 1], " \t\n\r");
1067                                 save_char = options_string[pos + token_end + 1];
1068                                 options_string[pos + token_end + 1] = '\0';
1069                                 value = GetVariable(pset.vars, options_string + pos + 1);
1070                                 if (!value)
1071                                         value = "";
1072                                 return_val = xstrdup(value);
1073                                 options_string[pos + token_end + 1] = save_char;
1074                                 *string = &options_string[pos + token_end + 1];
1075                                 /* XXX should we set *quote to ':' here? */
1076                                 return return_val;
1077                         }
1078
1079                         /*
1080                          * | could be the beginning of a pipe if so, take rest of line
1081                          * as command
1082                          */
1083                 case '|':
1084                         if (type == OT_FILEPIPE)
1085                         {
1086                                 *string += strlen(*string);
1087                                 return xstrdup(options_string + pos);
1088                         }
1089                         /* fallthrough for other option types */
1090
1091                         /*
1092                          * Default case: token extends to next whitespace, except that
1093                          * whitespace within double quotes doesn't end the token.
1094                          *
1095                          * If we are processing the option as a SQL identifier, then
1096                          * downcase unquoted letters and remove double-quotes --- but
1097                          * doubled double-quotes become output double-quotes, per
1098                          * spec.
1099                          *
1100                          * Note that a string like FOO"BAR"BAZ will be converted to
1101                          * fooBARbaz; this is somewhat inconsistent with the SQL spec,
1102                          * which would have us parse it as several identifiers.  But
1103                          * for psql's purposes, we want a string like "foo"."bar" to
1104                          * be treated as one option, so there's little choice.
1105                          */
1106                 default:
1107                         {
1108                                 bool            inquotes = false;
1109                                 size_t          token_len;
1110                                 char       *cp;
1111
1112                                 /* Find end of option */
1113
1114                                 cp = &options_string[pos];
1115                                 for (;;)
1116                                 {
1117                                         /* Find next quote, whitespace, or end of string */
1118                                         cp += strcspn(cp, "\" \t\n\r");
1119                                         if (inquotes)
1120                                         {
1121                                                 if (*cp == '\0')
1122                                                 {
1123                                                         psql_error("parse error at the end of line\n");
1124                                                         *string = cp;
1125                                                         return NULL;
1126                                                 }
1127                                                 if (*cp == '"')
1128                                                         inquotes = false;
1129                                                 cp++;
1130                                         }
1131                                         else
1132                                         {
1133                                                 if (*cp != '"')
1134                                                         break;          /* whitespace or end of string */
1135                                                 if (quote)
1136                                                         *quote = '"';
1137                                                 inquotes = true;
1138                                                 cp++;
1139                                         }
1140                                 }
1141
1142                                 *string = cp;
1143
1144                                 /* Copy the option */
1145                                 token_len = cp - &options_string[pos];
1146
1147                                 return_val = malloc(token_len + 1);
1148                                 if (!return_val)
1149                                 {
1150                                         psql_error("out of memory\n");
1151                                         exit(EXIT_FAILURE);
1152                                 }
1153
1154                                 memcpy(return_val, &options_string[pos], token_len);
1155                                 return_val[token_len] = '\0';
1156
1157                                 /* Strip any trailing semi-colons if requested */
1158                                 if (semicolon)
1159                                 {
1160                                         int                     i;
1161
1162                                         for (i = token_len - 1;
1163                                                  i >= 0 && return_val[i] == ';';
1164                                                  i--)
1165                                                  /* skip */ ;
1166
1167                                         if (i < 0)
1168                                         {
1169                                                 /* nothing left after stripping the semicolon... */
1170                                                 free(return_val);
1171                                                 return NULL;
1172                                         }
1173
1174                                         if (i < (int) token_len - 1)
1175                                                 return_val[i + 1] = '\0';
1176                                 }
1177
1178                                 /*
1179                                  * If SQL identifier processing was requested, then we
1180                                  * strip out excess double quotes and downcase unquoted
1181                                  * letters.
1182                                  */
1183                                 if (type == OT_SQLID || type == OT_SQLIDHACK)
1184                                 {
1185                                         inquotes = false;
1186                                         cp = return_val;
1187
1188                                         while (*cp)
1189                                         {
1190                                                 if (*cp == '"')
1191                                                 {
1192                                                         if (inquotes && cp[1] == '"')
1193                                                         {
1194                                                                 /* Keep the first quote, remove the second */
1195                                                                 cp++;
1196                                                         }
1197                                                         inquotes = !inquotes;
1198                                                         /* Collapse out quote at *cp */
1199                                                         memmove(cp, cp + 1, strlen(cp));
1200                                                         /* do not advance cp */
1201                                                 }
1202                                                 else
1203                                                 {
1204                                                         if (!inquotes && type == OT_SQLID)
1205                                                         {
1206                                                                 if (isupper((unsigned char) *cp))
1207                                                                         *cp = tolower((unsigned char) *cp);
1208                                                         }
1209                                                         cp += PQmblen(cp, pset.encoding);
1210                                                 }
1211                                         }
1212                                 }
1213
1214                                 return return_val;
1215                         }
1216         }
1217 }
1218
1219
1220
1221 /*
1222  * unescape
1223  *
1224  * Replaces \n, \t, and the like.
1225  *
1226  * The return value is malloc()'ed.
1227  */
1228 static char *
1229 unescape(const unsigned char *source, size_t len)
1230 {
1231         const unsigned char *p;
1232         bool            esc = false;    /* Last character we saw was the escape
1233                                                                  * character */
1234         char       *destination,
1235                            *tmp;
1236         size_t          length;
1237
1238 #ifdef USE_ASSERT_CHECKING
1239         assert(source);
1240 #endif
1241
1242         length = Min(len, strlen(source)) + 1;
1243
1244         tmp = destination = malloc(length);
1245         if (!tmp)
1246         {
1247                 psql_error("out of memory\n");
1248                 exit(EXIT_FAILURE);
1249         }
1250
1251         for (p = source; p - source < (int) len && *p; p += PQmblen(p, pset.encoding))
1252         {
1253                 if (esc)
1254                 {
1255                         char            c;
1256
1257                         switch (*p)
1258                         {
1259                                 case 'n':
1260                                         c = '\n';
1261                                         break;
1262                                 case 't':
1263                                         c = '\t';
1264                                         break;
1265                                 case 'b':
1266                                         c = '\b';
1267                                         break;
1268                                 case 'r':
1269                                         c = '\r';
1270                                         break;
1271                                 case 'f':
1272                                         c = '\f';
1273                                         break;
1274                                 case '0':
1275                                 case '1':
1276                                 case '2':
1277                                 case '3':
1278                                 case '4':
1279                                 case '5':
1280                                 case '6':
1281                                 case '7':
1282                                 case '8':
1283                                 case '9':
1284                                         {
1285                                                 long int        l;
1286                                                 char       *end;
1287
1288                                                 l = strtol(p, &end, 0);
1289                                                 c = (char) l;
1290                                                 p = end - 1;
1291                                                 break;
1292                                         }
1293                                 default:
1294                                         c = *p;
1295                         }
1296                         *tmp++ = c;
1297                         esc = false;
1298                 }
1299
1300                 else if (*p == '\\')
1301                         esc = true;
1302
1303                 else
1304                 {
1305                         int                     i;
1306                         const unsigned char *mp = p;
1307
1308                         for (i = 0; i < PQmblen(p, pset.encoding); i++)
1309                                 *tmp++ = *mp++;
1310                         esc = false;
1311                 }
1312         }
1313
1314         *tmp = '\0';
1315         return destination;
1316 }
1317
1318
1319
1320 /* do_connect
1321  * -- handler for \connect
1322  *
1323  * Connects to a database (new_dbname) as a certain user (new_user).
1324  * The new user can be NULL. A db name of "-" is the same as the old one.
1325  * (That is, the one currently in pset. But pset.db can also be NULL. A NULL
1326  * dbname is handled by libpq.)
1327  * Returns true if all ok, false if the new connection couldn't be established.
1328  * The old connection will be kept if the session is interactive.
1329  */
1330 static bool
1331 do_connect(const char *new_dbname, const char *new_user)
1332 {
1333         PGconn     *oldconn = pset.db;
1334         const char *dbparam = NULL;
1335         const char *userparam = NULL;
1336         const char *pwparam = NULL;
1337         char       *prompted_password = NULL;
1338         bool            need_pass;
1339         bool            success = false;
1340
1341         /* Delete variables (in case we fail before setting them anew) */
1342         SetVariable(pset.vars, "DBNAME", NULL);
1343         SetVariable(pset.vars, "USER", NULL);
1344         SetVariable(pset.vars, "HOST", NULL);
1345         SetVariable(pset.vars, "PORT", NULL);
1346         SetVariable(pset.vars, "ENCODING", NULL);
1347
1348         /* If dbname is "" then use old name, else new one (even if NULL) */
1349         if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "") == 0)
1350                 dbparam = PQdb(oldconn);
1351         else
1352                 dbparam = new_dbname;
1353
1354         /* If user is "" then use the old one */
1355         if (new_user && PQuser(oldconn) && strcmp(new_user, "") == 0)
1356                 userparam = PQuser(oldconn);
1357         else
1358                 userparam = new_user;
1359
1360         /* need to prompt for password? */
1361         if (pset.getPassword)
1362                 pwparam = prompted_password = simple_prompt("Password: ", 100, false);
1363
1364         /*
1365          * Use old password (if any) if no new one given and we are
1366          * reconnecting as same user
1367          */
1368         if (!pwparam && oldconn && PQuser(oldconn) && userparam &&
1369                 strcmp(PQuser(oldconn), userparam) == 0)
1370                 pwparam = PQpass(oldconn);
1371
1372         do
1373         {
1374                 need_pass = false;
1375                 pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
1376                                                            NULL, NULL, dbparam, userparam, pwparam);
1377
1378                 if (PQstatus(pset.db) == CONNECTION_BAD &&
1379                         strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0 &&
1380                         !feof(stdin))
1381                 {
1382                         PQfinish(pset.db);
1383                         need_pass = true;
1384                         free(prompted_password);
1385                         prompted_password = NULL;
1386                         pwparam = prompted_password = simple_prompt("Password: ", 100, false);
1387                 }
1388         } while (need_pass);
1389
1390         free(prompted_password);
1391
1392         /*
1393          * If connection failed, try at least keep the old one. That's
1394          * probably more convenient than just kicking you out of the program.
1395          */
1396         if (!pset.db || PQstatus(pset.db) == CONNECTION_BAD)
1397         {
1398                 if (pset.cur_cmd_interactive)
1399                 {
1400                         psql_error("%s", PQerrorMessage(pset.db));
1401                         PQfinish(pset.db);
1402                         if (oldconn)
1403                         {
1404                                 fputs(gettext("Previous connection kept\n"), stderr);
1405                                 pset.db = oldconn;
1406                         }
1407                         else
1408                                 pset.db = NULL;
1409                 }
1410                 else
1411                 {
1412                         /*
1413                          * we don't want unpredictable things to happen in scripting
1414                          * mode
1415                          */
1416                         psql_error("\\connect: %s", PQerrorMessage(pset.db));
1417                         PQfinish(pset.db);
1418                         if (oldconn)
1419                                 PQfinish(oldconn);
1420                         pset.db = NULL;
1421                 }
1422         }
1423         else
1424         {
1425                 if (!QUIET())
1426                 {
1427                         if (userparam != new_user)      /* no new user */
1428                                 printf(gettext("You are now connected to database %s.\n"), dbparam);
1429                         else if (dbparam != new_dbname)         /* no new db */
1430                                 printf(gettext("You are now connected as new user %s.\n"), new_user);
1431                         else
1432 /* both new */
1433                                 printf(gettext("You are now connected to database %s as user %s.\n"),
1434                                            PQdb(pset.db), PQuser(pset.db));
1435                 }
1436
1437                 if (oldconn)
1438                         PQfinish(oldconn);
1439
1440                 success = true;
1441         }
1442
1443         PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
1444         pset.encoding = PQclientEncoding(pset.db);
1445
1446         /* Update variables */
1447         SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
1448         SetVariable(pset.vars, "USER", PQuser(pset.db));
1449         SetVariable(pset.vars, "HOST", PQhost(pset.db));
1450         SetVariable(pset.vars, "PORT", PQport(pset.db));
1451         SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
1452
1453         pset.issuper = test_superuser(PQuser(pset.db));
1454
1455         return success;
1456 }
1457
1458
1459
1460 /*
1461  * Test if the given user is a database superuser.
1462  * (Is used to set up the prompt right.)
1463  */
1464 bool
1465 test_superuser(const char *username)
1466 {
1467         PGresult   *res;
1468         PQExpBufferData buf;
1469         bool            answer;
1470
1471         if (!username)
1472                 return false;
1473
1474         /*
1475          * Use begin/commit to avoid starting a transaction block if server
1476          * has autocommit off by default.
1477          */
1478         initPQExpBuffer(&buf);
1479         printfPQExpBuffer(&buf, "BEGIN; SELECT usesuper FROM pg_catalog.pg_user WHERE usename = '%s'; COMMIT", username);
1480         res = PSQLexec(buf.data, true);
1481         termPQExpBuffer(&buf);
1482
1483         answer =
1484                 (res && PQntuples(res) > 0 && PQnfields(res) > 0
1485                  && !PQgetisnull(res, 0, 0)
1486                  && PQgetvalue(res, 0, 0)
1487                  && strcmp(PQgetvalue(res, 0, 0), "t") == 0);
1488         PQclear(res);
1489         return answer;
1490 }
1491
1492
1493
1494 /*
1495  * do_edit -- handler for \e
1496  *
1497  * If you do not specify a filename, the current query buffer will be copied
1498  * into a temporary one.
1499  */
1500
1501 static bool
1502 editFile(const char *fname)
1503 {
1504         const char *editorName;
1505         char       *sys;
1506         int                     result;
1507
1508 #ifdef USE_ASSERT_CHECKING
1509         assert(fname);
1510 #else
1511         if (!fname)
1512                 return false;
1513 #endif
1514
1515         /* Find an editor to use */
1516         editorName = getenv("PSQL_EDITOR");
1517         if (!editorName)
1518                 editorName = getenv("EDITOR");
1519         if (!editorName)
1520                 editorName = getenv("VISUAL");
1521         if (!editorName)
1522                 editorName = DEFAULT_EDITOR;
1523
1524         sys = malloc(strlen(editorName) + strlen(fname) + 10 + 1);
1525         if (!sys)
1526                 return false;
1527         sprintf(sys, "exec  '%s' '%s'", editorName, fname);
1528         result = system(sys);
1529         if (result == -1)
1530                 psql_error("could not start editor %s\n", editorName);
1531         else if (result == 127)
1532                 psql_error("could not start /bin/sh\n");
1533         free(sys);
1534
1535         return result == 0;
1536 }
1537
1538
1539 /* call this one */
1540 static bool
1541 do_edit(const char *filename_arg, PQExpBuffer query_buf)
1542 {
1543         char            fnametmp[MAXPGPATH];
1544         FILE       *stream = NULL;
1545         const char *fname;
1546         bool            error = false;
1547         int                     fd;
1548
1549 #ifndef WIN32
1550         struct stat before,
1551                                 after;
1552 #endif
1553
1554         if (filename_arg)
1555                 fname = filename_arg;
1556
1557         else
1558         {
1559                 /* make a temp file to edit */
1560 #ifndef WIN32
1561                 const char *tmpdirenv = getenv("TMPDIR");
1562
1563                 snprintf(fnametmp, sizeof(fnametmp), "%s/psql.edit.%ld.%ld",
1564                                  tmpdirenv ? tmpdirenv : "/tmp",
1565                                  (long) geteuid(), (long) getpid());
1566 #else
1567                 GetTempFileName(".", "psql", 0, fnametmp);
1568 #endif
1569                 fname = (const char *) fnametmp;
1570
1571                 fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
1572                 if (fd != -1)
1573                         stream = fdopen(fd, "w");
1574
1575                 if (fd == -1 || !stream)
1576                 {
1577                         psql_error("could not open temporary file %s: %s\n", fname, strerror(errno));
1578                         error = true;
1579                 }
1580                 else
1581                 {
1582                         unsigned int ql = query_buf->len;
1583
1584                         if (ql == 0 || query_buf->data[ql - 1] != '\n')
1585                         {
1586                                 appendPQExpBufferChar(query_buf, '\n');
1587                                 ql++;
1588                         }
1589
1590                         if (fwrite(query_buf->data, 1, ql, stream) != ql)
1591                         {
1592                                 psql_error("%s: %s\n", fname, strerror(errno));
1593                                 fclose(stream);
1594                                 remove(fname);
1595                                 error = true;
1596                         }
1597                         else
1598                                 fclose(stream);
1599                 }
1600         }
1601
1602 #ifndef WIN32
1603         if (!error && stat(fname, &before) != 0)
1604         {
1605                 psql_error("%s: %s\n", fname, strerror(errno));
1606                 error = true;
1607         }
1608 #endif
1609
1610         /* call editor */
1611         if (!error)
1612                 error = !editFile(fname);
1613
1614 #ifndef WIN32
1615         if (!error && stat(fname, &after) != 0)
1616         {
1617                 psql_error("%s: %s\n", fname, strerror(errno));
1618                 error = true;
1619         }
1620
1621         if (!error && before.st_mtime != after.st_mtime)
1622         {
1623 #else
1624         if (!error)
1625         {
1626 #endif
1627                 stream = fopen(fname, "r");
1628                 if (!stream)
1629                 {
1630                         psql_error("%s: %s\n", fname, strerror(errno));
1631                         error = true;
1632                 }
1633                 else
1634                 {
1635                         /* read file back in */
1636                         char            line[1024];
1637
1638                         resetPQExpBuffer(query_buf);
1639                         while (fgets(line, sizeof(line), stream) != NULL)
1640                                 appendPQExpBufferStr(query_buf, line);
1641
1642                         if (ferror(stream))
1643                         {
1644                                 psql_error("%s: %s\n", fname, strerror(errno));
1645                                 error = true;
1646                         }
1647
1648                         fclose(stream);
1649                 }
1650
1651         }
1652
1653         /* remove temp file */
1654         if (!filename_arg)
1655         {
1656                 if (remove(fname) == -1)
1657                 {
1658                         psql_error("%s: %s\n", fname, strerror(errno));
1659                         error = true;
1660                 }
1661         }
1662
1663         return !error;
1664 }
1665
1666
1667
1668 /*
1669  * process_file
1670  *
1671  * Read commands from filename and then them to the main processing loop
1672  * Handler for \i, but can be used for other things as well.
1673  */
1674 int
1675 process_file(char *filename)
1676 {
1677         FILE       *fd;
1678         int                     result;
1679         char       *oldfilename;
1680
1681         if (!filename)
1682                 return false;
1683
1684         fd = fopen(filename, "r");
1685
1686         if (!fd)
1687         {
1688                 psql_error("%s: %s\n", filename, strerror(errno));
1689                 return false;
1690         }
1691
1692         oldfilename = pset.inputfile;
1693         pset.inputfile = filename;
1694         result = MainLoop(fd);
1695         fclose(fd);
1696         pset.inputfile = oldfilename;
1697         return result;
1698 }
1699
1700
1701
1702 /*
1703  * do_pset
1704  *
1705  */
1706 static const char *
1707 _align2string(enum printFormat in)
1708 {
1709         switch (in)
1710         {
1711                 case PRINT_NOTHING:
1712                         return "nothing";
1713                         break;
1714                 case PRINT_UNALIGNED:
1715                         return "unaligned";
1716                         break;
1717                 case PRINT_ALIGNED:
1718                         return "aligned";
1719                         break;
1720                 case PRINT_HTML:
1721                         return "html";
1722                         break;
1723                 case PRINT_LATEX:
1724                         return "latex";
1725                         break;
1726         }
1727         return "unknown";
1728 }
1729
1730
1731 bool
1732 do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
1733 {
1734         size_t          vallen = 0;
1735
1736 #ifdef USE_ASSERT_CHECKING
1737         assert(param);
1738 #else
1739         if (!param)
1740                 return false;
1741 #endif
1742
1743         if (value)
1744                 vallen = strlen(value);
1745
1746         /* set format */
1747         if (strcmp(param, "format") == 0)
1748         {
1749                 if (!value)
1750                         ;
1751                 else if (strncasecmp("unaligned", value, vallen) == 0)
1752                         popt->topt.format = PRINT_UNALIGNED;
1753                 else if (strncasecmp("aligned", value, vallen) == 0)
1754                         popt->topt.format = PRINT_ALIGNED;
1755                 else if (strncasecmp("html", value, vallen) == 0)
1756                         popt->topt.format = PRINT_HTML;
1757                 else if (strncasecmp("latex", value, vallen) == 0)
1758                         popt->topt.format = PRINT_LATEX;
1759                 else
1760                 {
1761                         psql_error("\\pset: allowed formats are unaligned, aligned, html, latex\n");
1762                         return false;
1763                 }
1764
1765                 if (!quiet)
1766                         printf(gettext("Output format is %s.\n"), _align2string(popt->topt.format));
1767         }
1768
1769         /* set border style/width */
1770         else if (strcmp(param, "border") == 0)
1771         {
1772                 if (value)
1773                         popt->topt.border = atoi(value);
1774
1775                 if (!quiet)
1776                         printf(gettext("Border style is %d.\n"), popt->topt.border);
1777         }
1778
1779         /* set expanded/vertical mode */
1780         else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
1781         {
1782                 popt->topt.expanded = !popt->topt.expanded;
1783                 if (!quiet)
1784                         printf(popt->topt.expanded
1785                                    ? gettext("Expanded display is on.\n")
1786                                    : gettext("Expanded display is off.\n"));
1787         }
1788
1789         /* null display */
1790         else if (strcmp(param, "null") == 0)
1791         {
1792                 if (value)
1793                 {
1794                         free(popt->nullPrint);
1795                         popt->nullPrint = xstrdup(value);
1796                 }
1797                 if (!quiet)
1798                         printf(gettext("Null display is '%s'.\n"), popt->nullPrint ? popt->nullPrint : "");
1799         }
1800
1801         /* field separator for unaligned text */
1802         else if (strcmp(param, "fieldsep") == 0)
1803         {
1804                 if (value)
1805                 {
1806                         free(popt->topt.fieldSep);
1807                         popt->topt.fieldSep = xstrdup(value);
1808                 }
1809                 if (!quiet)
1810                         printf(gettext("Field separator is '%s'.\n"), popt->topt.fieldSep);
1811         }
1812
1813         /* record separator for unaligned text */
1814         else if (strcmp(param, "recordsep") == 0)
1815         {
1816                 if (value)
1817                 {
1818                         free(popt->topt.recordSep);
1819                         popt->topt.recordSep = xstrdup(value);
1820                 }
1821                 if (!quiet)
1822                 {
1823                         if (strcmp(popt->topt.recordSep, "\n") == 0)
1824                                 printf(gettext("Record separator is <newline>."));
1825                         else
1826                                 printf(gettext("Record separator is '%s'.\n"), popt->topt.recordSep);
1827                 }
1828         }
1829
1830         /* toggle between full and barebones format */
1831         else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
1832         {
1833                 popt->topt.tuples_only = !popt->topt.tuples_only;
1834                 if (!quiet)
1835                 {
1836                         if (popt->topt.tuples_only)
1837                                 puts(gettext("Showing only tuples."));
1838                         else
1839                                 puts(gettext("Tuples only is off."));
1840                 }
1841         }
1842
1843         /* set title override */
1844         else if (strcmp(param, "title") == 0)
1845         {
1846                 free(popt->title);
1847                 if (!value)
1848                         popt->title = NULL;
1849                 else
1850                         popt->title = xstrdup(value);
1851
1852                 if (!quiet)
1853                 {
1854                         if (popt->title)
1855                                 printf(gettext("Title is \"%s\".\n"), popt->title);
1856                         else
1857                                 printf(gettext("Title is unset.\n"));
1858                 }
1859         }
1860
1861         /* set HTML table tag options */
1862         else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
1863         {
1864                 free(popt->topt.tableAttr);
1865                 if (!value)
1866                         popt->topt.tableAttr = NULL;
1867                 else
1868                         popt->topt.tableAttr = xstrdup(value);
1869
1870                 if (!quiet)
1871                 {
1872                         if (popt->topt.tableAttr)
1873                                 printf(gettext("Table attribute is \"%s\".\n"), popt->topt.tableAttr);
1874                         else
1875                                 printf(gettext("Table attributes unset.\n"));
1876                 }
1877         }
1878
1879         /* toggle use of pager */
1880         else if (strcmp(param, "pager") == 0)
1881         {
1882                 if (value && strcasecmp(value, "always") == 0)
1883                                 popt->topt.pager = 2;
1884                 else if (popt->topt.pager == 1)
1885                                 popt->topt.pager = 0;
1886                 else
1887                                 popt->topt.pager = 1;
1888                 if (!quiet)
1889                 {
1890                         if (popt->topt.pager == 1)
1891                                 puts(gettext("Using pager is on."));
1892                         else if (popt->topt.pager == 2)
1893                                 puts(gettext("Using pager is always."));
1894                         else
1895                                 puts(gettext("Using pager is off."));
1896                 }
1897         }
1898
1899         /* disable "(x rows)" footer */
1900         else if (strcmp(param, "footer") == 0)
1901         {
1902                 popt->default_footer = !popt->default_footer;
1903                 if (!quiet)
1904                 {
1905                         if (popt->default_footer)
1906                                 puts(gettext("Default footer is on."));
1907                         else
1908                                 puts(gettext("Default footer is off."));
1909                 }
1910         }
1911
1912         else
1913         {
1914                 psql_error("\\pset: unknown option: %s\n", param);
1915                 return false;
1916         }
1917
1918         return true;
1919 }
1920
1921
1922
1923 #define DEFAULT_SHELL "/bin/sh"
1924
1925 static bool
1926 do_shell(const char *command)
1927 {
1928         int                     result;
1929
1930         if (!command)
1931         {
1932                 char       *sys;
1933                 const char *shellName;
1934
1935                 shellName = getenv("SHELL");
1936                 if (shellName == NULL)
1937                         shellName = DEFAULT_SHELL;
1938
1939                 sys = malloc(strlen(shellName) + 16);
1940                 if (!sys)
1941                 {
1942                         psql_error("out of memory\n");
1943                         if (pset.cur_cmd_interactive)
1944                                 return false;
1945                         else
1946                                 exit(EXIT_FAILURE);
1947                 }
1948                 sprintf(sys, "exec %s", shellName);
1949                 result = system(sys);
1950                 free(sys);
1951         }
1952         else
1953                 result = system(command);
1954
1955         if (result == 127 || result == -1)
1956         {
1957                 psql_error("\\!: failed\n");
1958                 return false;
1959         }
1960         return true;
1961 }