]> granicus.if.org Git - postgresql/blob - src/bin/psql/command.c
Add optional on/off argument to \timing.
[postgresql] / src / bin / psql / command.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.190 2008/06/11 10:48:17 heikki 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 "portability/instr_time.h"
34
35 #include "libpq-fe.h"
36 #include "pqexpbuffer.h"
37 #include "dumputils.h"
38
39 #include "common.h"
40 #include "copy.h"
41 #include "describe.h"
42 #include "help.h"
43 #include "input.h"
44 #include "large_obj.h"
45 #include "mainloop.h"
46 #include "print.h"
47 #include "psqlscan.h"
48 #include "settings.h"
49 #include "variables.h"
50
51
52 /* functions for use in this file */
53 static backslashResult exec_command(const char *cmd,
54                          PsqlScanState scan_state,
55                          PQExpBuffer query_buf);
56 static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
57 static bool do_connect(char *dbname, char *user, char *host, char *port);
58 static bool do_shell(const char *command);
59
60
61 /*----------
62  * HandleSlashCmds:
63  *
64  * Handles all the different commands that start with '\'.
65  * Ordinarily called by MainLoop().
66  *
67  * scan_state is a lexer working state that is set to continue scanning
68  * just after the '\'.  The lexer is advanced past the command and all
69  * arguments on return.
70  *
71  * 'query_buf' contains the query-so-far, which may be modified by
72  * execution of the backslash command (for example, \r clears it).
73  * query_buf can be NULL if there is no query so far.
74  *
75  * Returns a status code indicating what action is desired, see command.h.
76  *----------
77  */
78
79 backslashResult
80 HandleSlashCmds(PsqlScanState scan_state,
81                                 PQExpBuffer query_buf)
82 {
83         backslashResult status = PSQL_CMD_SKIP_LINE;
84         char       *cmd;
85         char       *arg;
86
87         psql_assert(scan_state);
88
89         /* Parse off the command name */
90         cmd = psql_scan_slash_command(scan_state);
91
92         /* And try to execute it */
93         status = exec_command(cmd, scan_state, query_buf);
94
95         if (status == PSQL_CMD_UNKNOWN)
96         {
97                 if (pset.cur_cmd_interactive)
98                         fprintf(stderr, _("Invalid command \\%s. Try \\? for help.\n"), cmd);
99                 else
100                         psql_error("invalid command \\%s\n", cmd);
101                 status = PSQL_CMD_ERROR;
102         }
103
104         if (status != PSQL_CMD_ERROR)
105         {
106                 /* eat any remaining arguments after a valid command */
107                 /* note we suppress evaluation of backticks here */
108                 while ((arg = psql_scan_slash_option(scan_state,
109                                                                                          OT_VERBATIM, NULL, false)))
110                 {
111                         psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
112                         free(arg);
113                 }
114         }
115         else
116         {
117                 /* silently throw away rest of line after an erroneous command */
118                 while ((arg = psql_scan_slash_option(scan_state,
119                                                                                          OT_WHOLE_LINE, NULL, false)))
120                         free(arg);
121         }
122
123         /* if there is a trailing \\, swallow it */
124         psql_scan_slash_command_end(scan_state);
125
126         free(cmd);
127
128         /* some commands write to queryFout, so make sure output is sent */
129         fflush(pset.queryFout);
130
131         return status;
132 }
133
134 /*
135  * Read and interpret an argument to the \connect slash command.
136  */
137 static char *
138 read_connect_arg(PsqlScanState scan_state)
139 {
140         char       *result;
141         char            quote;
142
143         /*
144          * Ideally we should treat the arguments as SQL identifiers.  But for
145          * backwards compatibility with 7.2 and older pg_dump files, we have to
146          * take unquoted arguments verbatim (don't downcase them). For now,
147          * double-quoted arguments may be stripped of double quotes (as if SQL
148          * identifiers).  By 7.4 or so, pg_dump files can be expected to
149          * double-quote all mixed-case \connect arguments, and then we can get rid
150          * of OT_SQLIDHACK.
151          */
152         result = psql_scan_slash_option(scan_state, OT_SQLIDHACK, &quote, true);
153
154         if (!result)
155                 return NULL;
156
157         if (quote)
158                 return result;
159
160         if (*result == '\0' || strcmp(result, "-") == 0)
161                 return NULL;
162
163         return result;
164 }
165
166
167 /*
168  * Subroutine to actually try to execute a backslash command.
169  */
170 static backslashResult
171 exec_command(const char *cmd,
172                          PsqlScanState scan_state,
173                          PQExpBuffer query_buf)
174 {
175         bool            success = true; /* indicate here if the command ran ok or
176                                                                  * failed */
177         backslashResult status = PSQL_CMD_SKIP_LINE;
178
179         /*
180          * \a -- toggle field alignment This makes little sense but we keep it
181          * around.
182          */
183         if (strcmp(cmd, "a") == 0)
184         {
185                 if (pset.popt.topt.format != PRINT_ALIGNED)
186                         success = do_pset("format", "aligned", &pset.popt, pset.quiet);
187                 else
188                         success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
189         }
190
191         /* \C -- override table title (formerly change HTML caption) */
192         else if (strcmp(cmd, "C") == 0)
193         {
194                 char       *opt = psql_scan_slash_option(scan_state,
195                                                                                                  OT_NORMAL, NULL, true);
196
197                 success = do_pset("title", opt, &pset.popt, pset.quiet);
198                 free(opt);
199         }
200
201         /*
202          * \c or \connect -- connect to database using the specified parameters.
203          *
204          * \c dbname user host port
205          *
206          * If any of these parameters are omitted or specified as '-', the current
207          * value of the parameter will be used instead. If the parameter has no
208          * current value, the default value for that parameter will be used. Some
209          * examples:
210          *
211          * \c - - hst           Connect to current database on current port of host
212          * "hst" as current user. \c - usr - prt   Connect to current database on
213          * "prt" port of current host as user "usr". \c dbs                       Connect to
214          * "dbs" database on current port of current host as current user.
215          */
216         else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
217         {
218                 char       *opt1,
219                                    *opt2,
220                                    *opt3,
221                                    *opt4;
222
223                 opt1 = read_connect_arg(scan_state);
224                 opt2 = read_connect_arg(scan_state);
225                 opt3 = read_connect_arg(scan_state);
226                 opt4 = read_connect_arg(scan_state);
227
228                 success = do_connect(opt1, opt2, opt3, opt4);
229
230                 free(opt1);
231                 free(opt2);
232                 free(opt3);
233                 free(opt4);
234         }
235
236         /* \cd */
237         else if (strcmp(cmd, "cd") == 0)
238         {
239                 char       *opt = psql_scan_slash_option(scan_state,
240                                                                                                  OT_NORMAL, NULL, true);
241                 char       *dir;
242
243                 if (opt)
244                         dir = opt;
245                 else
246                 {
247 #ifndef WIN32
248                         struct passwd *pw;
249
250                         pw = getpwuid(geteuid());
251                         if (!pw)
252                         {
253                                 psql_error("could not get home directory: %s\n", strerror(errno));
254                                 exit(EXIT_FAILURE);
255                         }
256                         dir = pw->pw_dir;
257 #else                                                   /* WIN32 */
258
259                         /*
260                          * On Windows, 'cd' without arguments prints the current
261                          * directory, so if someone wants to code this here instead...
262                          */
263                         dir = "/";
264 #endif   /* WIN32 */
265                 }
266
267                 if (chdir(dir) == -1)
268                 {
269                         psql_error("\\%s: could not change directory to \"%s\": %s\n",
270                                            cmd, dir, strerror(errno));
271                         success = false;
272                 }
273
274                 if (pset.dirname)
275                         free(pset.dirname);
276                 pset.dirname = pg_strdup(dir);
277                 canonicalize_path(pset.dirname);
278
279                 if (opt)
280                         free(opt);
281         }
282
283         /* \copy */
284         else if (pg_strcasecmp(cmd, "copy") == 0)
285         {
286                 /* Default fetch-it-all-and-print mode */
287                 instr_time      before,
288                                         after;
289
290                 char       *opt = psql_scan_slash_option(scan_state,
291                                                                                                  OT_WHOLE_LINE, NULL, false);
292
293                 if (pset.timing)
294                         INSTR_TIME_SET_CURRENT(before);
295
296                 success = do_copy(opt);
297
298                 if (pset.timing && success)
299                 {
300                         INSTR_TIME_SET_CURRENT(after);
301                         INSTR_TIME_SUBTRACT(after, before);
302                         printf(_("Time: %.3f ms\n"), INSTR_TIME_GET_MILLISEC(after));
303                 }
304
305                 free(opt);
306         }
307
308         /* \copyright */
309         else if (strcmp(cmd, "copyright") == 0)
310                 print_copyright();
311
312         /* \d* commands */
313         else if (cmd[0] == 'd')
314         {
315                 char       *pattern;
316                 bool            show_verbose;
317
318                 /* We don't do SQLID reduction on the pattern yet */
319                 pattern = psql_scan_slash_option(scan_state,
320                                                                                  OT_NORMAL, NULL, true);
321
322                 show_verbose = strchr(cmd, '+') ? true : false;
323
324                 switch (cmd[1])
325                 {
326                         case '\0':
327                         case '+':
328                                 if (pattern)
329                                         success = describeTableDetails(pattern, show_verbose);
330                                 else
331                                         /* standard listing of interesting things */
332                                         success = listTables("tvs", NULL, show_verbose);
333                                 break;
334                         case 'a':
335                                 success = describeAggregates(pattern, show_verbose);
336                                 break;
337                         case 'b':
338                                 success = describeTablespaces(pattern, show_verbose);
339                                 break;
340                         case 'c':
341                                 success = listConversions(pattern);
342                                 break;
343                         case 'C':
344                                 success = listCasts(pattern);
345                                 break;
346                         case 'd':
347                                 success = objectDescription(pattern);
348                                 break;
349                         case 'D':
350                                 success = listDomains(pattern);
351                                 break;
352                         case 'f':
353                                 success = describeFunctions(pattern, show_verbose);
354                                 break;
355                         case 'g':
356                                 /* no longer distinct from \du */
357                                 success = describeRoles(pattern, show_verbose);
358                                 break;
359                         case 'l':
360                                 success = do_lo_list();
361                                 break;
362                         case 'n':
363                                 success = listSchemas(pattern, show_verbose);
364                                 break;
365                         case 'o':
366                                 success = describeOperators(pattern);
367                                 break;
368                         case 'p':
369                                 success = permissionsList(pattern);
370                                 break;
371                         case 'T':
372                                 success = describeTypes(pattern, show_verbose);
373                                 break;
374                         case 't':
375                         case 'v':
376                         case 'i':
377                         case 's':
378                         case 'S':
379                                 success = listTables(&cmd[1], pattern, show_verbose);
380                                 break;
381                         case 'u':
382                                 success = describeRoles(pattern, show_verbose);
383                                 break;
384                         case 'F':                       /* text search subsystem */
385                                 switch (cmd[2])
386                                 {
387                                         case '\0':
388                                         case '+':
389                                                 success = listTSConfigs(pattern, show_verbose);
390                                                 break;
391                                         case 'p':
392                                                 success = listTSParsers(pattern, show_verbose);
393                                                 break;
394                                         case 'd':
395                                                 success = listTSDictionaries(pattern, show_verbose);
396                                                 break;
397                                         case 't':
398                                                 success = listTSTemplates(pattern, show_verbose);
399                                                 break;
400                                         default:
401                                                 status = PSQL_CMD_UNKNOWN;
402                                                 break;
403                                 }
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         /* \prompt -- prompt and set variable */
713         else if (strcmp(cmd, "prompt") == 0)
714         {
715                 char       *opt,
716                                    *prompt_text = NULL;
717                 char       *arg1,
718                                    *arg2;
719
720                 arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
721                 arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
722
723                 if (!arg1)
724                 {
725                         psql_error("\\%s: missing required argument\n", cmd);
726                         success = false;
727                 }
728                 else
729                 {
730                         char       *result;
731
732                         if (arg2)
733                         {
734                                 prompt_text = arg1;
735                                 opt = arg2;
736                         }
737                         else
738                                 opt = arg1;
739
740                         if (!pset.inputfile)
741                                 result = simple_prompt(prompt_text, 4096, true);
742                         else
743                         {
744                                 if (prompt_text)
745                                 {
746                                         fputs(prompt_text, stdout);
747                                         fflush(stdout);
748                                 }
749                                 result = gets_fromFile(stdin);
750                         }
751
752                         if (!SetVariable(pset.vars, opt, result))
753                         {
754                                 psql_error("\\%s: error\n", cmd);
755                                 success = false;
756                         }
757
758                         free(result);
759                         if (prompt_text)
760                                 free(prompt_text);
761                         free(opt);
762                 }
763         }
764
765         /* \pset -- set printing parameters */
766         else if (strcmp(cmd, "pset") == 0)
767         {
768                 char       *opt0 = psql_scan_slash_option(scan_state,
769                                                                                                   OT_NORMAL, NULL, false);
770                 char       *opt1 = psql_scan_slash_option(scan_state,
771                                                                                                   OT_NORMAL, NULL, false);
772
773                 if (!opt0)
774                 {
775                         psql_error("\\%s: missing required argument\n", cmd);
776                         success = false;
777                 }
778                 else
779                         success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
780
781                 free(opt0);
782                 free(opt1);
783         }
784
785         /* \q or \quit */
786         else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
787                 status = PSQL_CMD_TERMINATE;
788
789         /* reset(clear) the buffer */
790         else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
791         {
792                 resetPQExpBuffer(query_buf);
793                 psql_scan_reset(scan_state);
794                 if (!pset.quiet)
795                         puts(_("Query buffer reset (cleared)."));
796         }
797
798         /* \s save history in a file or show it on the screen */
799         else if (strcmp(cmd, "s") == 0)
800         {
801                 char       *fname = psql_scan_slash_option(scan_state,
802                                                                                                    OT_NORMAL, NULL, true);
803
804                 expand_tilde(&fname);
805                 /* This scrolls off the screen when using /dev/tty */
806                 success = saveHistory(fname ? fname : DEVTTY, false);
807                 if (success && !pset.quiet && fname)
808                         printf(gettext("Wrote history to file \"%s/%s\".\n"),
809                                    pset.dirname ? pset.dirname : ".", fname);
810                 if (!fname)
811                         putchar('\n');
812                 free(fname);
813         }
814
815         /* \set -- generalized set variable/option command */
816         else if (strcmp(cmd, "set") == 0)
817         {
818                 char       *opt0 = psql_scan_slash_option(scan_state,
819                                                                                                   OT_NORMAL, NULL, false);
820
821                 if (!opt0)
822                 {
823                         /* list all variables */
824                         PrintVariables(pset.vars);
825                         success = true;
826                 }
827                 else
828                 {
829                         /*
830                          * Set variable to the concatenation of the arguments.
831                          */
832                         char       *newval;
833                         char       *opt;
834
835                         opt = psql_scan_slash_option(scan_state,
836                                                                                  OT_NORMAL, NULL, false);
837                         newval = pg_strdup(opt ? opt : "");
838                         free(opt);
839
840                         while ((opt = psql_scan_slash_option(scan_state,
841                                                                                                  OT_NORMAL, NULL, false)))
842                         {
843                                 newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
844                                 if (!newval)
845                                 {
846                                         psql_error("out of memory\n");
847                                         exit(EXIT_FAILURE);
848                                 }
849                                 strcat(newval, opt);
850                                 free(opt);
851                         }
852
853                         if (!SetVariable(pset.vars, opt0, newval))
854                         {
855                                 psql_error("\\%s: error\n", cmd);
856                                 success = false;
857                         }
858                         free(newval);
859                 }
860                 free(opt0);
861         }
862
863         /* \t -- turn off headers and row count */
864         else if (strcmp(cmd, "t") == 0)
865         {
866                 char       *opt = psql_scan_slash_option(scan_state,
867                                                                                                  OT_NORMAL, NULL, true);
868
869                 success = do_pset("tuples_only", opt, &pset.popt, pset.quiet);
870                 free(opt);
871         }
872
873
874         /* \T -- define html <table ...> attributes */
875         else if (strcmp(cmd, "T") == 0)
876         {
877                 char       *value = psql_scan_slash_option(scan_state,
878                                                                                                    OT_NORMAL, NULL, false);
879
880                 success = do_pset("tableattr", value, &pset.popt, pset.quiet);
881                 free(value);
882         }
883
884         /* \timing -- toggle timing of queries */
885         else if (strcmp(cmd, "timing") == 0)
886         {
887                 char       *opt = psql_scan_slash_option(scan_state,
888                                                                                              OT_NORMAL, NULL, false);
889                 if (opt)
890                         pset.timing = ParseVariableBool(opt);
891                 else
892                         pset.timing = !pset.timing;
893                 if (!pset.quiet)
894                 {
895                         if (pset.timing)
896                                 puts(_("Timing is on."));
897                         else
898                                 puts(_("Timing is off."));
899                 }
900                 free(opt);
901         }
902
903         /* \unset */
904         else if (strcmp(cmd, "unset") == 0)
905         {
906                 char       *opt = psql_scan_slash_option(scan_state,
907                                                                                                  OT_NORMAL, NULL, false);
908
909                 if (!opt)
910                 {
911                         psql_error("\\%s: missing required argument\n", cmd);
912                         success = false;
913                 }
914                 else if (!SetVariable(pset.vars, opt, NULL))
915                 {
916                         psql_error("\\%s: error\n", cmd);
917                         success = false;
918                 }
919                 free(opt);
920         }
921
922         /* \w -- write query buffer to file */
923         else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
924         {
925                 FILE       *fd = NULL;
926                 bool            is_pipe = false;
927                 char       *fname = NULL;
928
929                 if (!query_buf)
930                 {
931                         psql_error("no query buffer\n");
932                         status = PSQL_CMD_ERROR;
933                 }
934                 else
935                 {
936                         fname = psql_scan_slash_option(scan_state,
937                                                                                    OT_FILEPIPE, NULL, true);
938                         expand_tilde(&fname);
939
940                         if (!fname)
941                         {
942                                 psql_error("\\%s: missing required argument\n", cmd);
943                                 success = false;
944                         }
945                         else
946                         {
947                                 if (fname[0] == '|')
948                                 {
949                                         is_pipe = true;
950                                         fd = popen(&fname[1], "w");
951                                 }
952                                 else
953                                 {
954                                         canonicalize_path(fname);
955                                         fd = fopen(fname, "w");
956                                 }
957                                 if (!fd)
958                                 {
959                                         psql_error("%s: %s\n", fname, strerror(errno));
960                                         success = false;
961                                 }
962                         }
963                 }
964
965                 if (fd)
966                 {
967                         int                     result;
968
969                         if (query_buf && query_buf->len > 0)
970                                 fprintf(fd, "%s\n", query_buf->data);
971
972                         if (is_pipe)
973                                 result = pclose(fd);
974                         else
975                                 result = fclose(fd);
976
977                         if (result == EOF)
978                         {
979                                 psql_error("%s: %s\n", fname, strerror(errno));
980                                 success = false;
981                         }
982                 }
983
984                 free(fname);
985         }
986
987         /* \x -- toggle expanded table representation */
988         else if (strcmp(cmd, "x") == 0)
989         {
990                 char       *opt = psql_scan_slash_option(scan_state,
991                                                                                                  OT_NORMAL, NULL, true);
992
993                 success = do_pset("expanded", opt, &pset.popt, pset.quiet);
994                 free(opt);
995         }
996
997         /* \z -- list table rights (equivalent to \dp) */
998         else if (strcmp(cmd, "z") == 0)
999         {
1000                 char       *pattern = psql_scan_slash_option(scan_state,
1001                                                                                                          OT_NORMAL, NULL, true);
1002
1003                 success = permissionsList(pattern);
1004                 if (pattern)
1005                         free(pattern);
1006         }
1007
1008         /* \! -- shell escape */
1009         else if (strcmp(cmd, "!") == 0)
1010         {
1011                 char       *opt = psql_scan_slash_option(scan_state,
1012                                                                                                  OT_WHOLE_LINE, NULL, false);
1013
1014                 success = do_shell(opt);
1015                 free(opt);
1016         }
1017
1018         /* \? -- slash command help */
1019         else if (strcmp(cmd, "?") == 0)
1020                 slashUsage(pset.popt.topt.pager);
1021
1022 #if 0
1023
1024         /*
1025          * These commands don't do anything. I just use them to test the parser.
1026          */
1027         else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
1028         {
1029                 int                     i = 0;
1030                 char       *value;
1031
1032                 while ((value = psql_scan_slash_option(scan_state,
1033                                                                                            OT_NORMAL, NULL, true)))
1034                 {
1035                         fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
1036                         free(value);
1037                 }
1038         }
1039 #endif
1040
1041         else
1042                 status = PSQL_CMD_UNKNOWN;
1043
1044         if (!success)
1045                 status = PSQL_CMD_ERROR;
1046
1047         return status;
1048 }
1049
1050 /*
1051  * Ask the user for a password; 'username' is the username the
1052  * password is for, if one has been explicitly specified. Returns a
1053  * malloc'd string.
1054  */
1055 static char *
1056 prompt_for_password(const char *username)
1057 {
1058         char       *result;
1059
1060         if (username == NULL)
1061                 result = simple_prompt("Password: ", 100, false);
1062         else
1063         {
1064                 char       *prompt_text;
1065
1066                 prompt_text = malloc(strlen(username) + 100);
1067                 snprintf(prompt_text, strlen(username) + 100,
1068                                  _("Password for user %s: "), username);
1069                 result = simple_prompt(prompt_text, 100, false);
1070                 free(prompt_text);
1071         }
1072
1073         return result;
1074 }
1075
1076 static bool
1077 param_is_newly_set(const char *old_val, const char *new_val)
1078 {
1079         if (new_val == NULL)
1080                 return false;
1081
1082         if (old_val == NULL || strcmp(old_val, new_val) != 0)
1083                 return true;
1084
1085         return false;
1086 }
1087
1088 /*
1089  * do_connect -- handler for \connect
1090  *
1091  * Connects to a database with given parameters. If there exists an
1092  * established connection, NULL values will be replaced with the ones
1093  * in the current connection. Otherwise NULL will be passed for that
1094  * parameter to PQsetdbLogin(), so the libpq defaults will be used.
1095  *
1096  * In interactive mode, if connection fails with the given parameters,
1097  * the old connection will be kept.
1098  */
1099 static bool
1100 do_connect(char *dbname, char *user, char *host, char *port)
1101 {
1102         PGconn     *o_conn = pset.db,
1103                            *n_conn;
1104         char       *password = NULL;
1105
1106         if (!dbname)
1107                 dbname = PQdb(o_conn);
1108         if (!user)
1109                 user = PQuser(o_conn);
1110         if (!host)
1111                 host = PQhost(o_conn);
1112         if (!port)
1113                 port = PQport(o_conn);
1114
1115         /*
1116          * If the user asked to be prompted for a password, ask for one now. If
1117          * not, use the password from the old connection, provided the username
1118          * has not changed. Otherwise, try to connect without a password first,
1119          * and then ask for a password if needed.
1120          *
1121          * XXX: this behavior leads to spurious connection attempts recorded in
1122          * the postmaster's log.  But libpq offers no API that would let us obtain
1123          * a password and then continue with the first connection attempt.
1124          */
1125         if (pset.getPassword)
1126         {
1127                 password = prompt_for_password(user);
1128         }
1129         else if (o_conn && user && strcmp(PQuser(o_conn), user) == 0)
1130         {
1131                 password = strdup(PQpass(o_conn));
1132         }
1133
1134         while (true)
1135         {
1136                 n_conn = PQsetdbLogin(host, port, NULL, NULL,
1137                                                           dbname, user, password);
1138
1139                 /* We can immediately discard the password -- no longer needed */
1140                 if (password)
1141                         free(password);
1142
1143                 if (PQstatus(n_conn) == CONNECTION_OK)
1144                         break;
1145
1146                 /*
1147                  * Connection attempt failed; either retry the connection attempt with
1148                  * a new password, or give up.
1149                  */
1150                 if (!password && PQconnectionNeedsPassword(n_conn))
1151                 {
1152                         PQfinish(n_conn);
1153                         password = prompt_for_password(user);
1154                         continue;
1155                 }
1156
1157                 /*
1158                  * Failed to connect to the database. In interactive mode, keep the
1159                  * previous connection to the DB; in scripting mode, close our
1160                  * previous connection as well.
1161                  */
1162                 if (pset.cur_cmd_interactive)
1163                 {
1164                         psql_error("%s", PQerrorMessage(n_conn));
1165
1166                         /* pset.db is left unmodified */
1167                         if (o_conn)
1168                                 fputs(_("Previous connection kept\n"), stderr);
1169                 }
1170                 else
1171                 {
1172                         psql_error("\\connect: %s", PQerrorMessage(n_conn));
1173                         if (o_conn)
1174                         {
1175                                 PQfinish(o_conn);
1176                                 pset.db = NULL;
1177                         }
1178                 }
1179
1180                 PQfinish(n_conn);
1181                 return false;
1182         }
1183
1184         /*
1185          * Replace the old connection with the new one, and update
1186          * connection-dependent variables.
1187          */
1188         PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
1189         pset.db = n_conn;
1190         SyncVariables();
1191
1192         /* Tell the user about the new connection */
1193         if (!pset.quiet)
1194         {
1195                 printf(_("You are now connected to database \"%s\""), PQdb(pset.db));
1196
1197                 if (param_is_newly_set(PQhost(o_conn), PQhost(pset.db)))
1198                         printf(_(" on host \"%s\""), PQhost(pset.db));
1199
1200                 if (param_is_newly_set(PQport(o_conn), PQport(pset.db)))
1201                         printf(_(" at port \"%s\""), PQport(pset.db));
1202
1203                 if (param_is_newly_set(PQuser(o_conn), PQuser(pset.db)))
1204                         printf(_(" as user \"%s\""), PQuser(pset.db));
1205
1206                 printf(".\n");
1207         }
1208
1209         if (o_conn)
1210                 PQfinish(o_conn);
1211         return true;
1212 }
1213
1214
1215 /*
1216  * SyncVariables
1217  *
1218  * Make psql's internal variables agree with connection state upon
1219  * establishing a new connection.
1220  */
1221 void
1222 SyncVariables(void)
1223 {
1224         /* get stuff from connection */
1225         pset.encoding = PQclientEncoding(pset.db);
1226         pset.popt.topt.encoding = pset.encoding;
1227         pset.sversion = PQserverVersion(pset.db);
1228
1229         SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
1230         SetVariable(pset.vars, "USER", PQuser(pset.db));
1231         SetVariable(pset.vars, "HOST", PQhost(pset.db));
1232         SetVariable(pset.vars, "PORT", PQport(pset.db));
1233         SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
1234
1235         /* send stuff to it, too */
1236         PQsetErrorVerbosity(pset.db, pset.verbosity);
1237 }
1238
1239 /*
1240  * UnsyncVariables
1241  *
1242  * Clear variables that should be not be set when there is no connection.
1243  */
1244 void
1245 UnsyncVariables(void)
1246 {
1247         SetVariable(pset.vars, "DBNAME", NULL);
1248         SetVariable(pset.vars, "USER", NULL);
1249         SetVariable(pset.vars, "HOST", NULL);
1250         SetVariable(pset.vars, "PORT", NULL);
1251         SetVariable(pset.vars, "ENCODING", NULL);
1252 }
1253
1254
1255 /*
1256  * do_edit -- handler for \e
1257  *
1258  * If you do not specify a filename, the current query buffer will be copied
1259  * into a temporary one.
1260  */
1261
1262 static bool
1263 editFile(const char *fname)
1264 {
1265         const char *editorName;
1266         char       *sys;
1267         int                     result;
1268
1269         psql_assert(fname);
1270
1271         /* Find an editor to use */
1272         editorName = getenv("PSQL_EDITOR");
1273         if (!editorName)
1274                 editorName = getenv("EDITOR");
1275         if (!editorName)
1276                 editorName = getenv("VISUAL");
1277         if (!editorName)
1278                 editorName = DEFAULT_EDITOR;
1279
1280         /*
1281          * On Unix the EDITOR value should *not* be quoted, since it might include
1282          * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
1283          * if necessary.  But this policy is not very workable on Windows, due to
1284          * severe brain damage in their command shell plus the fact that standard
1285          * program paths include spaces.
1286          */
1287         sys = pg_malloc(strlen(editorName) + strlen(fname) + 10 + 1);
1288 #ifndef WIN32
1289         sprintf(sys, "exec %s '%s'", editorName, fname);
1290 #else
1291         sprintf(sys, "%s\"%s\" \"%s\"%s",
1292                         SYSTEMQUOTE, editorName, fname, SYSTEMQUOTE);
1293 #endif
1294         result = system(sys);
1295         if (result == -1)
1296                 psql_error("could not start editor \"%s\"\n", editorName);
1297         else if (result == 127)
1298                 psql_error("could not start /bin/sh\n");
1299         free(sys);
1300
1301         return result == 0;
1302 }
1303
1304
1305 /* call this one */
1306 static bool
1307 do_edit(const char *filename_arg, PQExpBuffer query_buf)
1308 {
1309         char            fnametmp[MAXPGPATH];
1310         FILE       *stream = NULL;
1311         const char *fname;
1312         bool            error = false;
1313         int                     fd;
1314
1315         struct stat before,
1316                                 after;
1317
1318         if (filename_arg)
1319                 fname = filename_arg;
1320         else
1321         {
1322                 /* make a temp file to edit */
1323 #ifndef WIN32
1324                 const char *tmpdir = getenv("TMPDIR");
1325
1326                 if (!tmpdir)
1327                         tmpdir = "/tmp";
1328 #else
1329                 char            tmpdir[MAXPGPATH];
1330                 int                     ret;
1331
1332                 ret = GetTempPath(MAXPGPATH, tmpdir);
1333                 if (ret == 0 || ret > MAXPGPATH)
1334                 {
1335                         psql_error("cannot locate temporary directory: %s",
1336                                            !ret ? strerror(errno) : "");
1337                         return false;
1338                 }
1339
1340                 /*
1341                  * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
1342                  * current directory to the supplied path unless we use only
1343                  * backslashes, so we do that.
1344                  */
1345 #endif
1346 #ifndef WIN32
1347                 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
1348                                  "/", (int) getpid());
1349 #else
1350                 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
1351                            "" /* trailing separator already present */ , (int) getpid());
1352 #endif
1353
1354                 fname = (const char *) fnametmp;
1355
1356                 fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
1357                 if (fd != -1)
1358                         stream = fdopen(fd, "w");
1359
1360                 if (fd == -1 || !stream)
1361                 {
1362                         psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
1363                         error = true;
1364                 }
1365                 else
1366                 {
1367                         unsigned int ql = query_buf->len;
1368
1369                         if (ql == 0 || query_buf->data[ql - 1] != '\n')
1370                         {
1371                                 appendPQExpBufferChar(query_buf, '\n');
1372                                 ql++;
1373                         }
1374
1375                         if (fwrite(query_buf->data, 1, ql, stream) != ql)
1376                         {
1377                                 psql_error("%s: %s\n", fname, strerror(errno));
1378                                 fclose(stream);
1379                                 remove(fname);
1380                                 error = true;
1381                         }
1382                         else if (fclose(stream) != 0)
1383                         {
1384                                 psql_error("%s: %s\n", fname, strerror(errno));
1385                                 remove(fname);
1386                                 error = true;
1387                         }
1388                 }
1389         }
1390
1391         if (!error && stat(fname, &before) != 0)
1392         {
1393                 psql_error("%s: %s\n", fname, strerror(errno));
1394                 error = true;
1395         }
1396
1397         /* call editor */
1398         if (!error)
1399                 error = !editFile(fname);
1400
1401         if (!error && stat(fname, &after) != 0)
1402         {
1403                 psql_error("%s: %s\n", fname, strerror(errno));
1404                 error = true;
1405         }
1406
1407         if (!error && before.st_mtime != after.st_mtime)
1408         {
1409                 stream = fopen(fname, PG_BINARY_R);
1410                 if (!stream)
1411                 {
1412                         psql_error("%s: %s\n", fname, strerror(errno));
1413                         error = true;
1414                 }
1415                 else
1416                 {
1417                         /* read file back into query_buf */
1418                         char            line[1024];
1419
1420                         resetPQExpBuffer(query_buf);
1421                         while (fgets(line, sizeof(line), stream) != NULL)
1422                                 appendPQExpBufferStr(query_buf, line);
1423
1424                         if (ferror(stream))
1425                         {
1426                                 psql_error("%s: %s\n", fname, strerror(errno));
1427                                 error = true;
1428                         }
1429
1430                         fclose(stream);
1431                 }
1432
1433         }
1434
1435         /* remove temp file */
1436         if (!filename_arg)
1437         {
1438                 if (remove(fname) == -1)
1439                 {
1440                         psql_error("%s: %s\n", fname, strerror(errno));
1441                         error = true;
1442                 }
1443         }
1444
1445         return !error;
1446 }
1447
1448
1449
1450 /*
1451  * process_file
1452  *
1453  * Read commands from filename and then them to the main processing loop
1454  * Handler for \i, but can be used for other things as well.  Returns
1455  * MainLoop() error code.
1456  */
1457 int
1458 process_file(char *filename, bool single_txn)
1459 {
1460         FILE       *fd;
1461         int                     result;
1462         char       *oldfilename;
1463         PGresult   *res;
1464
1465         if (!filename)
1466                 return EXIT_FAILURE;
1467
1468         canonicalize_path(filename);
1469         fd = fopen(filename, PG_BINARY_R);
1470
1471         if (!fd)
1472         {
1473                 psql_error("%s: %s\n", filename, strerror(errno));
1474                 return EXIT_FAILURE;
1475         }
1476
1477         oldfilename = pset.inputfile;
1478         pset.inputfile = filename;
1479
1480         if (single_txn)
1481                 res = PSQLexec("BEGIN", false);
1482         result = MainLoop(fd);
1483         if (single_txn)
1484                 res = PSQLexec("COMMIT", false);
1485
1486         fclose(fd);
1487         pset.inputfile = oldfilename;
1488         return result;
1489 }
1490
1491
1492
1493 /*
1494  * do_pset
1495  *
1496  */
1497 static const char *
1498 _align2string(enum printFormat in)
1499 {
1500         switch (in)
1501         {
1502                 case PRINT_NOTHING:
1503                         return "nothing";
1504                         break;
1505                 case PRINT_UNALIGNED:
1506                         return "unaligned";
1507                         break;
1508                 case PRINT_ALIGNED:
1509                         return "aligned";
1510                         break;
1511                 case PRINT_WRAPPED:
1512                         return "wrapped";
1513                         break;
1514                 case PRINT_HTML:
1515                         return "html";
1516                         break;
1517                 case PRINT_LATEX:
1518                         return "latex";
1519                         break;
1520                 case PRINT_TROFF_MS:
1521                         return "troff-ms";
1522                         break;
1523         }
1524         return "unknown";
1525 }
1526
1527
1528 bool
1529 do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
1530 {
1531         size_t          vallen = 0;
1532
1533         psql_assert(param);
1534
1535         if (value)
1536                 vallen = strlen(value);
1537
1538         /* set format */
1539         if (strcmp(param, "format") == 0)
1540         {
1541                 if (!value)
1542                         ;
1543                 else if (pg_strncasecmp("unaligned", value, vallen) == 0)
1544                         popt->topt.format = PRINT_UNALIGNED;
1545                 else if (pg_strncasecmp("aligned", value, vallen) == 0)
1546                         popt->topt.format = PRINT_ALIGNED;
1547                 else if (pg_strncasecmp("wrapped", value, vallen) == 0)
1548                         popt->topt.format = PRINT_WRAPPED;
1549                 else if (pg_strncasecmp("html", value, vallen) == 0)
1550                         popt->topt.format = PRINT_HTML;
1551                 else if (pg_strncasecmp("latex", value, vallen) == 0)
1552                         popt->topt.format = PRINT_LATEX;
1553                 else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
1554                         popt->topt.format = PRINT_TROFF_MS;
1555                 else
1556                 {
1557                         psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, latex, troff-ms\n");
1558                         return false;
1559                 }
1560
1561                 if (!quiet)
1562                         printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
1563         }
1564
1565         /* set border style/width */
1566         else if (strcmp(param, "border") == 0)
1567         {
1568                 if (value)
1569                         popt->topt.border = atoi(value);
1570
1571                 if (!quiet)
1572                         printf(_("Border style is %d.\n"), popt->topt.border);
1573         }
1574
1575         /* set expanded/vertical mode */
1576         else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
1577         {
1578                 if (value)
1579                         popt->topt.expanded = ParseVariableBool(value);
1580                 else
1581                         popt->topt.expanded = !popt->topt.expanded;
1582                 if (!quiet)
1583                         printf(popt->topt.expanded
1584                                    ? _("Expanded display is on.\n")
1585                                    : _("Expanded display is off.\n"));
1586         }
1587
1588         /* locale-aware numeric output */
1589         else if (strcmp(param, "numericlocale") == 0)
1590         {
1591                 if (value)
1592                         popt->topt.numericLocale = ParseVariableBool(value);
1593                 else
1594                         popt->topt.numericLocale = !popt->topt.numericLocale;
1595                 if (!quiet)
1596                 {
1597                         if (popt->topt.numericLocale)
1598                                 puts(_("Showing locale-adjusted numeric output."));
1599                         else
1600                                 puts(_("Locale-adjusted numeric output is off."));
1601                 }
1602         }
1603
1604         /* null display */
1605         else if (strcmp(param, "null") == 0)
1606         {
1607                 if (value)
1608                 {
1609                         free(popt->nullPrint);
1610                         popt->nullPrint = pg_strdup(value);
1611                 }
1612                 if (!quiet)
1613                         printf(_("Null display is \"%s\".\n"), popt->nullPrint ? popt->nullPrint : "");
1614         }
1615
1616         /* field separator for unaligned text */
1617         else if (strcmp(param, "fieldsep") == 0)
1618         {
1619                 if (value)
1620                 {
1621                         free(popt->topt.fieldSep);
1622                         popt->topt.fieldSep = pg_strdup(value);
1623                 }
1624                 if (!quiet)
1625                         printf(_("Field separator is \"%s\".\n"), popt->topt.fieldSep);
1626         }
1627
1628         /* record separator for unaligned text */
1629         else if (strcmp(param, "recordsep") == 0)
1630         {
1631                 if (value)
1632                 {
1633                         free(popt->topt.recordSep);
1634                         popt->topt.recordSep = pg_strdup(value);
1635                 }
1636                 if (!quiet)
1637                 {
1638                         if (strcmp(popt->topt.recordSep, "\n") == 0)
1639                                 printf(_("Record separator is <newline>."));
1640                         else
1641                                 printf(_("Record separator is \"%s\".\n"), popt->topt.recordSep);
1642                 }
1643         }
1644
1645         /* toggle between full and tuples-only format */
1646         else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
1647         {
1648                 if (value)
1649                         popt->topt.tuples_only = ParseVariableBool(value);
1650                 else
1651                         popt->topt.tuples_only = !popt->topt.tuples_only;
1652                 if (!quiet)
1653                 {
1654                         if (popt->topt.tuples_only)
1655                                 puts(_("Showing only tuples."));
1656                         else
1657                                 puts(_("Tuples only is off."));
1658                 }
1659         }
1660
1661         /* set title override */
1662         else if (strcmp(param, "title") == 0)
1663         {
1664                 free(popt->title);
1665                 if (!value)
1666                         popt->title = NULL;
1667                 else
1668                         popt->title = pg_strdup(value);
1669
1670                 if (!quiet)
1671                 {
1672                         if (popt->title)
1673                                 printf(_("Title is \"%s\".\n"), popt->title);
1674                         else
1675                                 printf(_("Title is unset.\n"));
1676                 }
1677         }
1678
1679         /* set HTML table tag options */
1680         else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
1681         {
1682                 free(popt->topt.tableAttr);
1683                 if (!value)
1684                         popt->topt.tableAttr = NULL;
1685                 else
1686                         popt->topt.tableAttr = pg_strdup(value);
1687
1688                 if (!quiet)
1689                 {
1690                         if (popt->topt.tableAttr)
1691                                 printf(_("Table attribute is \"%s\".\n"), popt->topt.tableAttr);
1692                         else
1693                                 printf(_("Table attributes unset.\n"));
1694                 }
1695         }
1696
1697         /* toggle use of pager */
1698         else if (strcmp(param, "pager") == 0)
1699         {
1700                 if (value && pg_strcasecmp(value, "always") == 0)
1701                         popt->topt.pager = 2;
1702                 else if (value)
1703                         if (ParseVariableBool(value))
1704                                 popt->topt.pager = 1;
1705                         else
1706                                 popt->topt.pager = 0;
1707                 else if (popt->topt.pager == 1)
1708                         popt->topt.pager = 0;
1709                 else
1710                         popt->topt.pager = 1;
1711                 if (!quiet)
1712                 {
1713                         if (popt->topt.pager == 1)
1714                                 puts(_("Pager is used for long output."));
1715                         else if (popt->topt.pager == 2)
1716                                 puts(_("Pager is always used."));
1717                         else
1718                                 puts(_("Pager usage is off."));
1719                 }
1720         }
1721
1722         /* disable "(x rows)" footer */
1723         else if (strcmp(param, "footer") == 0)
1724         {
1725                 if (value)
1726                         popt->default_footer = ParseVariableBool(value);
1727                 else
1728                         popt->default_footer = !popt->default_footer;
1729                 if (!quiet)
1730                 {
1731                         if (popt->default_footer)
1732                                 puts(_("Default footer is on."));
1733                         else
1734                                 puts(_("Default footer is off."));
1735                 }
1736         }
1737
1738         /* set border style/width */
1739         else if (strcmp(param, "columns") == 0)
1740         {
1741                 if (value)
1742                         popt->topt.columns = atoi(value);
1743
1744                 if (!quiet)
1745                         printf(_("Target width for \"wrapped\" format is %d.\n"), popt->topt.columns);
1746         }
1747
1748         else
1749         {
1750                 psql_error("\\pset: unknown option: %s\n", param);
1751                 return false;
1752         }
1753
1754         return true;
1755 }
1756
1757
1758
1759 #ifndef WIN32
1760 #define DEFAULT_SHELL "/bin/sh"
1761 #else
1762 /*
1763  *      CMD.EXE is in different places in different Win32 releases so we
1764  *      have to rely on the path to find it.
1765  */
1766 #define DEFAULT_SHELL "cmd.exe"
1767 #endif
1768
1769 static bool
1770 do_shell(const char *command)
1771 {
1772         int                     result;
1773
1774         if (!command)
1775         {
1776                 char       *sys;
1777                 const char *shellName;
1778
1779                 shellName = getenv("SHELL");
1780 #ifdef WIN32
1781                 if (shellName == NULL)
1782                         shellName = getenv("COMSPEC");
1783 #endif
1784                 if (shellName == NULL)
1785                         shellName = DEFAULT_SHELL;
1786
1787                 sys = pg_malloc(strlen(shellName) + 16);
1788 #ifndef WIN32
1789                 sprintf(sys,
1790                 /* See EDITOR handling comment for an explaination */
1791                                 "exec %s", shellName);
1792 #else
1793                 sprintf(sys,
1794                 /* See EDITOR handling comment for an explaination */
1795                                 "%s\"%s\"%s", SYSTEMQUOTE, shellName, SYSTEMQUOTE);
1796 #endif
1797                 result = system(sys);
1798                 free(sys);
1799         }
1800         else
1801                 result = system(command);
1802
1803         if (result == 127 || result == -1)
1804         {
1805                 psql_error("\\!: failed\n");
1806                 return false;
1807         }
1808         return true;
1809 }