]> granicus.if.org Git - postgresql/blob - src/bin/psql/command.c
Update copyrights in source tree to 2008.
[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.186 2008/01/01 19:45:55 momjian Exp $
7  */
8 #include "postgres_fe.h"
9 #include "command.h"
10
11 #ifdef __BORLANDC__                             /* needed for BCC */
12 #undef mkdir
13 #endif
14
15 #include <ctype.h>
16 #ifdef HAVE_PWD_H
17 #include <pwd.h>
18 #endif
19 #ifndef WIN32
20 #include <sys/types.h>                  /* for umask() */
21 #include <sys/stat.h>                   /* for stat() */
22 #include <fcntl.h>                              /* open() flags */
23 #include <unistd.h>                             /* for geteuid(), getpid(), stat() */
24 #else
25 #include <win32.h>
26 #include <io.h>
27 #include <fcntl.h>
28 #include <direct.h>
29 #include <sys/types.h>                  /* for umask() */
30 #include <sys/stat.h>                   /* for stat() */
31 #endif
32
33 #include "libpq-fe.h"
34 #include "pqexpbuffer.h"
35 #include "dumputils.h"
36
37 #include "common.h"
38 #include "copy.h"
39 #include "describe.h"
40 #include "help.h"
41 #include "input.h"
42 #include "large_obj.h"
43 #include "mainloop.h"
44 #include "print.h"
45 #include "psqlscan.h"
46 #include "settings.h"
47 #include "variables.h"
48
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) + 100);
1085                 snprintf(prompt_text, strlen(username) + 100,
1086                                  _("Password for user %s: "), username);
1087                 result = simple_prompt(prompt_text, 100, false);
1088                 free(prompt_text);
1089         }
1090
1091         return result;
1092 }
1093
1094 static bool
1095 param_is_newly_set(const char *old_val, const char *new_val)
1096 {
1097         if (new_val == NULL)
1098                 return false;
1099
1100         if (old_val == NULL || strcmp(old_val, new_val) != 0)
1101                 return true;
1102
1103         return false;
1104 }
1105
1106 /*
1107  * do_connect -- handler for \connect
1108  *
1109  * Connects to a database with given parameters. If there exists an
1110  * established connection, NULL values will be replaced with the ones
1111  * in the current connection. Otherwise NULL will be passed for that
1112  * parameter to PQsetdbLogin(), so the libpq defaults will be used.
1113  *
1114  * In interactive mode, if connection fails with the given parameters,
1115  * the old connection will be kept.
1116  */
1117 static bool
1118 do_connect(char *dbname, char *user, char *host, char *port)
1119 {
1120         PGconn     *o_conn = pset.db,
1121                            *n_conn;
1122         char       *password = NULL;
1123
1124         if (!dbname)
1125                 dbname = PQdb(o_conn);
1126         if (!user)
1127                 user = PQuser(o_conn);
1128         if (!host)
1129                 host = PQhost(o_conn);
1130         if (!port)
1131                 port = PQport(o_conn);
1132
1133         /*
1134          * If the user asked to be prompted for a password, ask for one now. If
1135          * not, use the password from the old connection, provided the username
1136          * has not changed. Otherwise, try to connect without a password first,
1137          * and then ask for a password if needed.
1138          *
1139          * XXX: this behavior leads to spurious connection attempts recorded in
1140          * the postmaster's log.  But libpq offers no API that would let us obtain
1141          * a password and then continue with the first connection attempt.
1142          */
1143         if (pset.getPassword)
1144         {
1145                 password = prompt_for_password(user);
1146         }
1147         else if (o_conn && user && strcmp(PQuser(o_conn), user) == 0)
1148         {
1149                 password = strdup(PQpass(o_conn));
1150         }
1151
1152         while (true)
1153         {
1154                 n_conn = PQsetdbLogin(host, port, NULL, NULL,
1155                                                           dbname, user, password);
1156
1157                 /* We can immediately discard the password -- no longer needed */
1158                 if (password)
1159                         free(password);
1160
1161                 if (PQstatus(n_conn) == CONNECTION_OK)
1162                         break;
1163
1164                 /*
1165                  * Connection attempt failed; either retry the connection attempt with
1166                  * a new password, or give up.
1167                  */
1168                 if (!password && PQconnectionNeedsPassword(n_conn))
1169                 {
1170                         PQfinish(n_conn);
1171                         password = prompt_for_password(user);
1172                         continue;
1173                 }
1174
1175                 /*
1176                  * Failed to connect to the database. In interactive mode, keep the
1177                  * previous connection to the DB; in scripting mode, close our
1178                  * previous connection as well.
1179                  */
1180                 if (pset.cur_cmd_interactive)
1181                 {
1182                         psql_error("%s", PQerrorMessage(n_conn));
1183
1184                         /* pset.db is left unmodified */
1185                         if (o_conn)
1186                                 fputs(_("Previous connection kept\n"), stderr);
1187                 }
1188                 else
1189                 {
1190                         psql_error("\\connect: %s", PQerrorMessage(n_conn));
1191                         if (o_conn)
1192                         {
1193                                 PQfinish(o_conn);
1194                                 pset.db = NULL;
1195                         }
1196                 }
1197
1198                 PQfinish(n_conn);
1199                 return false;
1200         }
1201
1202         /*
1203          * Replace the old connection with the new one, and update
1204          * connection-dependent variables.
1205          */
1206         PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
1207         pset.db = n_conn;
1208         SyncVariables();
1209
1210         /* Tell the user about the new connection */
1211         if (!pset.quiet)
1212         {
1213                 printf(_("You are now connected to database \"%s\""), PQdb(pset.db));
1214
1215                 if (param_is_newly_set(PQhost(o_conn), PQhost(pset.db)))
1216                         printf(_(" on host \"%s\""), PQhost(pset.db));
1217
1218                 if (param_is_newly_set(PQport(o_conn), PQport(pset.db)))
1219                         printf(_(" at port \"%s\""), PQport(pset.db));
1220
1221                 if (param_is_newly_set(PQuser(o_conn), PQuser(pset.db)))
1222                         printf(_(" as user \"%s\""), PQuser(pset.db));
1223
1224                 printf(".\n");
1225         }
1226
1227         if (o_conn)
1228                 PQfinish(o_conn);
1229         return true;
1230 }
1231
1232
1233 /*
1234  * SyncVariables
1235  *
1236  * Make psql's internal variables agree with connection state upon
1237  * establishing a new connection.
1238  */
1239 void
1240 SyncVariables(void)
1241 {
1242         /* get stuff from connection */
1243         pset.encoding = PQclientEncoding(pset.db);
1244         pset.popt.topt.encoding = pset.encoding;
1245         pset.sversion = PQserverVersion(pset.db);
1246
1247         SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
1248         SetVariable(pset.vars, "USER", PQuser(pset.db));
1249         SetVariable(pset.vars, "HOST", PQhost(pset.db));
1250         SetVariable(pset.vars, "PORT", PQport(pset.db));
1251         SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
1252
1253         /* send stuff to it, too */
1254         PQsetErrorVerbosity(pset.db, pset.verbosity);
1255 }
1256
1257 /*
1258  * UnsyncVariables
1259  *
1260  * Clear variables that should be not be set when there is no connection.
1261  */
1262 void
1263 UnsyncVariables(void)
1264 {
1265         SetVariable(pset.vars, "DBNAME", NULL);
1266         SetVariable(pset.vars, "USER", NULL);
1267         SetVariable(pset.vars, "HOST", NULL);
1268         SetVariable(pset.vars, "PORT", NULL);
1269         SetVariable(pset.vars, "ENCODING", NULL);
1270 }
1271
1272
1273 /*
1274  * do_edit -- handler for \e
1275  *
1276  * If you do not specify a filename, the current query buffer will be copied
1277  * into a temporary one.
1278  */
1279
1280 static bool
1281 editFile(const char *fname)
1282 {
1283         const char *editorName;
1284         char       *sys;
1285         int                     result;
1286
1287         psql_assert(fname);
1288
1289         /* Find an editor to use */
1290         editorName = getenv("PSQL_EDITOR");
1291         if (!editorName)
1292                 editorName = getenv("EDITOR");
1293         if (!editorName)
1294                 editorName = getenv("VISUAL");
1295         if (!editorName)
1296                 editorName = DEFAULT_EDITOR;
1297
1298         /*
1299          * On Unix the EDITOR value should *not* be quoted, since it might include
1300          * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
1301          * if necessary.  But this policy is not very workable on Windows, due to
1302          * severe brain damage in their command shell plus the fact that standard
1303          * program paths include spaces.
1304          */
1305         sys = pg_malloc(strlen(editorName) + strlen(fname) + 10 + 1);
1306 #ifndef WIN32
1307         sprintf(sys, "exec %s '%s'", editorName, fname);
1308 #else
1309         sprintf(sys, "%s\"%s\" \"%s\"%s",
1310                         SYSTEMQUOTE, editorName, fname, SYSTEMQUOTE);
1311 #endif
1312         result = system(sys);
1313         if (result == -1)
1314                 psql_error("could not start editor \"%s\"\n", editorName);
1315         else if (result == 127)
1316                 psql_error("could not start /bin/sh\n");
1317         free(sys);
1318
1319         return result == 0;
1320 }
1321
1322
1323 /* call this one */
1324 static bool
1325 do_edit(const char *filename_arg, PQExpBuffer query_buf)
1326 {
1327         char            fnametmp[MAXPGPATH];
1328         FILE       *stream = NULL;
1329         const char *fname;
1330         bool            error = false;
1331         int                     fd;
1332
1333         struct stat before,
1334                                 after;
1335
1336         if (filename_arg)
1337                 fname = filename_arg;
1338         else
1339         {
1340                 /* make a temp file to edit */
1341 #ifndef WIN32
1342                 const char *tmpdir = getenv("TMPDIR");
1343
1344                 if (!tmpdir)
1345                         tmpdir = "/tmp";
1346 #else
1347                 char            tmpdir[MAXPGPATH];
1348                 int                     ret;
1349
1350                 ret = GetTempPath(MAXPGPATH, tmpdir);
1351                 if (ret == 0 || ret > MAXPGPATH)
1352                 {
1353                         psql_error("cannot locate temporary directory: %s",
1354                                            !ret ? strerror(errno) : "");
1355                         return false;
1356                 }
1357
1358                 /*
1359                  * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
1360                  * current directory to the supplied path unless we use only
1361                  * backslashes, so we do that.
1362                  */
1363 #endif
1364 #ifndef WIN32
1365                 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
1366                                  "/", (int) getpid());
1367 #else
1368                 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
1369                            "" /* trailing separator already present */ , (int) getpid());
1370 #endif
1371
1372                 fname = (const char *) fnametmp;
1373
1374                 fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
1375                 if (fd != -1)
1376                         stream = fdopen(fd, "w");
1377
1378                 if (fd == -1 || !stream)
1379                 {
1380                         psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
1381                         error = true;
1382                 }
1383                 else
1384                 {
1385                         unsigned int ql = query_buf->len;
1386
1387                         if (ql == 0 || query_buf->data[ql - 1] != '\n')
1388                         {
1389                                 appendPQExpBufferChar(query_buf, '\n');
1390                                 ql++;
1391                         }
1392
1393                         if (fwrite(query_buf->data, 1, ql, stream) != ql)
1394                         {
1395                                 psql_error("%s: %s\n", fname, strerror(errno));
1396                                 fclose(stream);
1397                                 remove(fname);
1398                                 error = true;
1399                         }
1400                         else if (fclose(stream) != 0)
1401                         {
1402                                 psql_error("%s: %s\n", fname, strerror(errno));
1403                                 remove(fname);
1404                                 error = true;
1405                         }
1406                 }
1407         }
1408
1409         if (!error && stat(fname, &before) != 0)
1410         {
1411                 psql_error("%s: %s\n", fname, strerror(errno));
1412                 error = true;
1413         }
1414
1415         /* call editor */
1416         if (!error)
1417                 error = !editFile(fname);
1418
1419         if (!error && stat(fname, &after) != 0)
1420         {
1421                 psql_error("%s: %s\n", fname, strerror(errno));
1422                 error = true;
1423         }
1424
1425         if (!error && before.st_mtime != after.st_mtime)
1426         {
1427                 stream = fopen(fname, PG_BINARY_R);
1428                 if (!stream)
1429                 {
1430                         psql_error("%s: %s\n", fname, strerror(errno));
1431                         error = true;
1432                 }
1433                 else
1434                 {
1435                         /* read file back into query_buf */
1436                         char            line[1024];
1437
1438                         resetPQExpBuffer(query_buf);
1439                         while (fgets(line, sizeof(line), stream) != NULL)
1440                                 appendPQExpBufferStr(query_buf, line);
1441
1442                         if (ferror(stream))
1443                         {
1444                                 psql_error("%s: %s\n", fname, strerror(errno));
1445                                 error = true;
1446                         }
1447
1448                         fclose(stream);
1449                 }
1450
1451         }
1452
1453         /* remove temp file */
1454         if (!filename_arg)
1455         {
1456                 if (remove(fname) == -1)
1457                 {
1458                         psql_error("%s: %s\n", fname, strerror(errno));
1459                         error = true;
1460                 }
1461         }
1462
1463         return !error;
1464 }
1465
1466
1467
1468 /*
1469  * process_file
1470  *
1471  * Read commands from filename and then them to the main processing loop
1472  * Handler for \i, but can be used for other things as well.  Returns
1473  * MainLoop() error code.
1474  */
1475 int
1476 process_file(char *filename, bool single_txn)
1477 {
1478         FILE       *fd;
1479         int                     result;
1480         char       *oldfilename;
1481         PGresult   *res;
1482
1483         if (!filename)
1484                 return EXIT_FAILURE;
1485
1486         canonicalize_path(filename);
1487         fd = fopen(filename, PG_BINARY_R);
1488
1489         if (!fd)
1490         {
1491                 psql_error("%s: %s\n", filename, strerror(errno));
1492                 return EXIT_FAILURE;
1493         }
1494
1495         oldfilename = pset.inputfile;
1496         pset.inputfile = filename;
1497
1498         if (single_txn)
1499                 res = PSQLexec("BEGIN", false);
1500         result = MainLoop(fd);
1501         if (single_txn)
1502                 res = PSQLexec("COMMIT", false);
1503
1504         fclose(fd);
1505         pset.inputfile = oldfilename;
1506         return result;
1507 }
1508
1509
1510
1511 /*
1512  * do_pset
1513  *
1514  */
1515 static const char *
1516 _align2string(enum printFormat in)
1517 {
1518         switch (in)
1519         {
1520                 case PRINT_NOTHING:
1521                         return "nothing";
1522                         break;
1523                 case PRINT_UNALIGNED:
1524                         return "unaligned";
1525                         break;
1526                 case PRINT_ALIGNED:
1527                         return "aligned";
1528                         break;
1529                 case PRINT_HTML:
1530                         return "html";
1531                         break;
1532                 case PRINT_LATEX:
1533                         return "latex";
1534                         break;
1535                 case PRINT_TROFF_MS:
1536                         return "troff-ms";
1537                         break;
1538         }
1539         return "unknown";
1540 }
1541
1542
1543 bool
1544 do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
1545 {
1546         size_t          vallen = 0;
1547
1548         psql_assert(param);
1549
1550         if (value)
1551                 vallen = strlen(value);
1552
1553         /* set format */
1554         if (strcmp(param, "format") == 0)
1555         {
1556                 if (!value)
1557                         ;
1558                 else if (pg_strncasecmp("unaligned", value, vallen) == 0)
1559                         popt->topt.format = PRINT_UNALIGNED;
1560                 else if (pg_strncasecmp("aligned", value, vallen) == 0)
1561                         popt->topt.format = PRINT_ALIGNED;
1562                 else if (pg_strncasecmp("html", value, vallen) == 0)
1563                         popt->topt.format = PRINT_HTML;
1564                 else if (pg_strncasecmp("latex", value, vallen) == 0)
1565                         popt->topt.format = PRINT_LATEX;
1566                 else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
1567                         popt->topt.format = PRINT_TROFF_MS;
1568                 else
1569                 {
1570                         psql_error("\\pset: allowed formats are unaligned, aligned, html, latex, troff-ms\n");
1571                         return false;
1572                 }
1573
1574                 if (!quiet)
1575                         printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
1576         }
1577
1578         /* set border style/width */
1579         else if (strcmp(param, "border") == 0)
1580         {
1581                 if (value)
1582                         popt->topt.border = atoi(value);
1583
1584                 if (!quiet)
1585                         printf(_("Border style is %d.\n"), popt->topt.border);
1586         }
1587
1588         /* set expanded/vertical mode */
1589         else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
1590         {
1591                 if (value)
1592                         popt->topt.expanded = ParseVariableBool(value);
1593                 else
1594                         popt->topt.expanded = !popt->topt.expanded;
1595                 if (!quiet)
1596                         printf(popt->topt.expanded
1597                                    ? _("Expanded display is on.\n")
1598                                    : _("Expanded display is off.\n"));
1599         }
1600
1601         /* locale-aware numeric output */
1602         else if (strcmp(param, "numericlocale") == 0)
1603         {
1604                 if (value)
1605                         popt->topt.numericLocale = ParseVariableBool(value);
1606                 else
1607                         popt->topt.numericLocale = !popt->topt.numericLocale;
1608                 if (!quiet)
1609                 {
1610                         if (popt->topt.numericLocale)
1611                                 puts(_("Showing locale-adjusted numeric output."));
1612                         else
1613                                 puts(_("Locale-adjusted numeric output is off."));
1614                 }
1615         }
1616
1617         /* null display */
1618         else if (strcmp(param, "null") == 0)
1619         {
1620                 if (value)
1621                 {
1622                         free(popt->nullPrint);
1623                         popt->nullPrint = pg_strdup(value);
1624                 }
1625                 if (!quiet)
1626                         printf(_("Null display is \"%s\".\n"), popt->nullPrint ? popt->nullPrint : "");
1627         }
1628
1629         /* field separator for unaligned text */
1630         else if (strcmp(param, "fieldsep") == 0)
1631         {
1632                 if (value)
1633                 {
1634                         free(popt->topt.fieldSep);
1635                         popt->topt.fieldSep = pg_strdup(value);
1636                 }
1637                 if (!quiet)
1638                         printf(_("Field separator is \"%s\".\n"), popt->topt.fieldSep);
1639         }
1640
1641         /* record separator for unaligned text */
1642         else if (strcmp(param, "recordsep") == 0)
1643         {
1644                 if (value)
1645                 {
1646                         free(popt->topt.recordSep);
1647                         popt->topt.recordSep = pg_strdup(value);
1648                 }
1649                 if (!quiet)
1650                 {
1651                         if (strcmp(popt->topt.recordSep, "\n") == 0)
1652                                 printf(_("Record separator is <newline>."));
1653                         else
1654                                 printf(_("Record separator is \"%s\".\n"), popt->topt.recordSep);
1655                 }
1656         }
1657
1658         /* toggle between full and tuples-only format */
1659         else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
1660         {
1661                 if (value)
1662                         popt->topt.tuples_only = ParseVariableBool(value);
1663                 else
1664                         popt->topt.tuples_only = !popt->topt.tuples_only;
1665                 if (!quiet)
1666                 {
1667                         if (popt->topt.tuples_only)
1668                                 puts(_("Showing only tuples."));
1669                         else
1670                                 puts(_("Tuples only is off."));
1671                 }
1672         }
1673
1674         /* set title override */
1675         else if (strcmp(param, "title") == 0)
1676         {
1677                 free(popt->title);
1678                 if (!value)
1679                         popt->title = NULL;
1680                 else
1681                         popt->title = pg_strdup(value);
1682
1683                 if (!quiet)
1684                 {
1685                         if (popt->title)
1686                                 printf(_("Title is \"%s\".\n"), popt->title);
1687                         else
1688                                 printf(_("Title is unset.\n"));
1689                 }
1690         }
1691
1692         /* set HTML table tag options */
1693         else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
1694         {
1695                 free(popt->topt.tableAttr);
1696                 if (!value)
1697                         popt->topt.tableAttr = NULL;
1698                 else
1699                         popt->topt.tableAttr = pg_strdup(value);
1700
1701                 if (!quiet)
1702                 {
1703                         if (popt->topt.tableAttr)
1704                                 printf(_("Table attribute is \"%s\".\n"), popt->topt.tableAttr);
1705                         else
1706                                 printf(_("Table attributes unset.\n"));
1707                 }
1708         }
1709
1710         /* toggle use of pager */
1711         else if (strcmp(param, "pager") == 0)
1712         {
1713                 if (value && pg_strcasecmp(value, "always") == 0)
1714                         popt->topt.pager = 2;
1715                 else if (value)
1716                         if (ParseVariableBool(value))
1717                                 popt->topt.pager = 1;
1718                         else
1719                                 popt->topt.pager = 0;
1720                 else if (popt->topt.pager == 1)
1721                         popt->topt.pager = 0;
1722                 else
1723                         popt->topt.pager = 1;
1724                 if (!quiet)
1725                 {
1726                         if (popt->topt.pager == 1)
1727                                 puts(_("Pager is used for long output."));
1728                         else if (popt->topt.pager == 2)
1729                                 puts(_("Pager is always used."));
1730                         else
1731                                 puts(_("Pager usage is off."));
1732                 }
1733         }
1734
1735         /* disable "(x rows)" footer */
1736         else if (strcmp(param, "footer") == 0)
1737         {
1738                 if (value)
1739                         popt->default_footer = ParseVariableBool(value);
1740                 else
1741                         popt->default_footer = !popt->default_footer;
1742                 if (!quiet)
1743                 {
1744                         if (popt->default_footer)
1745                                 puts(_("Default footer is on."));
1746                         else
1747                                 puts(_("Default footer is off."));
1748                 }
1749         }
1750
1751         else
1752         {
1753                 psql_error("\\pset: unknown option: %s\n", param);
1754                 return false;
1755         }
1756
1757         return true;
1758 }
1759
1760
1761
1762 #ifndef WIN32
1763 #define DEFAULT_SHELL "/bin/sh"
1764 #else
1765 /*
1766  *      CMD.EXE is in different places in different Win32 releases so we
1767  *      have to rely on the path to find it.
1768  */
1769 #define DEFAULT_SHELL "cmd.exe"
1770 #endif
1771
1772 static bool
1773 do_shell(const char *command)
1774 {
1775         int                     result;
1776
1777         if (!command)
1778         {
1779                 char       *sys;
1780                 const char *shellName;
1781
1782                 shellName = getenv("SHELL");
1783 #ifdef WIN32
1784                 if (shellName == NULL)
1785                         shellName = getenv("COMSPEC");
1786 #endif
1787                 if (shellName == NULL)
1788                         shellName = DEFAULT_SHELL;
1789
1790                 sys = pg_malloc(strlen(shellName) + 16);
1791 #ifndef WIN32
1792                 sprintf(sys,
1793                 /* See EDITOR handling comment for an explaination */
1794                                 "exec %s", shellName);
1795 #else
1796                 sprintf(sys,
1797                 /* See EDITOR handling comment for an explaination */
1798                                 "%s\"%s\"%s", SYSTEMQUOTE, shellName, SYSTEMQUOTE);
1799 #endif
1800                 result = system(sys);
1801                 free(sys);
1802         }
1803         else
1804                 result = system(command);
1805
1806         if (result == 127 || result == -1)
1807         {
1808                 psql_error("\\!: failed\n");
1809                 return false;
1810         }
1811         return true;
1812 }