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