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