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