]> granicus.if.org Git - postgresql/blob - src/bin/psql/command.c
Revert "psql: fix \connect with URIs and conninfo strings"
[postgresql] / src / bin / psql / command.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2015, PostgreSQL Global Development Group
5  *
6  * src/bin/psql/command.c
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 #include <time.h>
17 #ifdef HAVE_PWD_H
18 #include <pwd.h>
19 #endif
20 #ifndef WIN32
21 #include <sys/types.h>                  /* for umask() */
22 #include <sys/stat.h>                   /* for stat() */
23 #include <fcntl.h>                              /* open() flags */
24 #include <unistd.h>                             /* for geteuid(), getpid(), stat() */
25 #else
26 #include <win32.h>
27 #include <io.h>
28 #include <fcntl.h>
29 #include <direct.h>
30 #include <sys/types.h>                  /* for umask() */
31 #include <sys/stat.h>                   /* for stat() */
32 #endif
33
34 #include "portability/instr_time.h"
35
36 #include "libpq-fe.h"
37 #include "pqexpbuffer.h"
38 #include "dumputils.h"
39
40 #include "common.h"
41 #include "copy.h"
42 #include "describe.h"
43 #include "help.h"
44 #include "input.h"
45 #include "large_obj.h"
46 #include "mainloop.h"
47 #include "print.h"
48 #include "psqlscan.h"
49 #include "settings.h"
50 #include "variables.h"
51
52
53 /* functions for use in this file */
54 static backslashResult exec_command(const char *cmd,
55                          PsqlScanState scan_state,
56                          PQExpBuffer query_buf);
57 static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
58                 int lineno, bool *edited);
59 static bool do_connect(char *dbname, char *user, char *host, char *port);
60 static bool do_shell(const char *command);
61 static bool do_watch(PQExpBuffer query_buf, long sleep);
62 static bool lookup_function_oid(const char *desc, Oid *foid);
63 static bool get_create_function_cmd(Oid oid, PQExpBuffer buf);
64 static int      strip_lineno_from_funcdesc(char *func);
65 static void minimal_error_message(PGresult *res);
66
67 static void printSSLInfo(void);
68 static bool printPsetInfo(const char *param, struct printQueryOpt *popt);
69 static char *pset_value_string(const char *param, struct printQueryOpt *popt);
70
71 #ifdef WIN32
72 static void checkWin32Codepage(void);
73 #endif
74
75
76
77 /*----------
78  * HandleSlashCmds:
79  *
80  * Handles all the different commands that start with '\'.
81  * Ordinarily called by MainLoop().
82  *
83  * scan_state is a lexer working state that is set to continue scanning
84  * just after the '\'.  The lexer is advanced past the command and all
85  * arguments on return.
86  *
87  * 'query_buf' contains the query-so-far, which may be modified by
88  * execution of the backslash command (for example, \r clears it).
89  * query_buf can be NULL if there is no query so far.
90  *
91  * Returns a status code indicating what action is desired, see command.h.
92  *----------
93  */
94
95 backslashResult
96 HandleSlashCmds(PsqlScanState scan_state,
97                                 PQExpBuffer query_buf)
98 {
99         backslashResult status = PSQL_CMD_SKIP_LINE;
100         char       *cmd;
101         char       *arg;
102
103         Assert(scan_state != NULL);
104
105         /* Parse off the command name */
106         cmd = psql_scan_slash_command(scan_state);
107
108         /* And try to execute it */
109         status = exec_command(cmd, scan_state, query_buf);
110
111         if (status == PSQL_CMD_UNKNOWN)
112         {
113                 if (pset.cur_cmd_interactive)
114                         psql_error("Invalid command \\%s. Try \\? for help.\n", cmd);
115                 else
116                         psql_error("invalid command \\%s\n", cmd);
117                 status = PSQL_CMD_ERROR;
118         }
119
120         if (status != PSQL_CMD_ERROR)
121         {
122                 /* eat any remaining arguments after a valid command */
123                 /* note we suppress evaluation of backticks here */
124                 while ((arg = psql_scan_slash_option(scan_state,
125                                                                                          OT_NO_EVAL, NULL, false)))
126                 {
127                         psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
128                         free(arg);
129                 }
130         }
131         else
132         {
133                 /* silently throw away rest of line after an erroneous command */
134                 while ((arg = psql_scan_slash_option(scan_state,
135                                                                                          OT_WHOLE_LINE, NULL, false)))
136                         free(arg);
137         }
138
139         /* if there is a trailing \\, swallow it */
140         psql_scan_slash_command_end(scan_state);
141
142         free(cmd);
143
144         /* some commands write to queryFout, so make sure output is sent */
145         fflush(pset.queryFout);
146
147         return status;
148 }
149
150 /*
151  * Read and interpret an argument to the \connect slash command.
152  */
153 static char *
154 read_connect_arg(PsqlScanState scan_state)
155 {
156         char       *result;
157         char            quote;
158
159         /*
160          * Ideally we should treat the arguments as SQL identifiers.  But for
161          * backwards compatibility with 7.2 and older pg_dump files, we have to
162          * take unquoted arguments verbatim (don't downcase them). For now,
163          * double-quoted arguments may be stripped of double quotes (as if SQL
164          * identifiers).  By 7.4 or so, pg_dump files can be expected to
165          * double-quote all mixed-case \connect arguments, and then we can get rid
166          * of OT_SQLIDHACK.
167          */
168         result = psql_scan_slash_option(scan_state, OT_SQLIDHACK, &quote, true);
169
170         if (!result)
171                 return NULL;
172
173         if (quote)
174                 return result;
175
176         if (*result == '\0' || strcmp(result, "-") == 0)
177                 return NULL;
178
179         return result;
180 }
181
182
183 /*
184  * Subroutine to actually try to execute a backslash command.
185  */
186 static backslashResult
187 exec_command(const char *cmd,
188                          PsqlScanState scan_state,
189                          PQExpBuffer query_buf)
190 {
191         bool            success = true; /* indicate here if the command ran ok or
192                                                                  * failed */
193         backslashResult status = PSQL_CMD_SKIP_LINE;
194
195         /*
196          * \a -- toggle field alignment This makes little sense but we keep it
197          * around.
198          */
199         if (strcmp(cmd, "a") == 0)
200         {
201                 if (pset.popt.topt.format != PRINT_ALIGNED)
202                         success = do_pset("format", "aligned", &pset.popt, pset.quiet);
203                 else
204                         success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
205         }
206
207         /* \C -- override table title (formerly change HTML caption) */
208         else if (strcmp(cmd, "C") == 0)
209         {
210                 char       *opt = psql_scan_slash_option(scan_state,
211                                                                                                  OT_NORMAL, NULL, true);
212
213                 success = do_pset("title", opt, &pset.popt, pset.quiet);
214                 free(opt);
215         }
216
217         /*
218          * \c or \connect -- connect to database using the specified parameters.
219          *
220          * \c dbname user host port
221          *
222          * If any of these parameters are omitted or specified as '-', the current
223          * value of the parameter will be used instead. If the parameter has no
224          * current value, the default value for that parameter will be used. Some
225          * examples:
226          *
227          * \c - - hst           Connect to current database on current port of host
228          * "hst" as current user. \c - usr - prt   Connect to current database on
229          * "prt" port of current host as user "usr". \c dbs                       Connect to
230          * "dbs" database on current port of current host as current user.
231          */
232         else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
233         {
234                 char       *opt1,
235                                    *opt2,
236                                    *opt3,
237                                    *opt4;
238
239                 opt1 = read_connect_arg(scan_state);
240                 opt2 = read_connect_arg(scan_state);
241                 opt3 = read_connect_arg(scan_state);
242                 opt4 = read_connect_arg(scan_state);
243
244                 success = do_connect(opt1, opt2, opt3, opt4);
245
246                 free(opt1);
247                 free(opt2);
248                 free(opt3);
249                 free(opt4);
250         }
251
252         /* \cd */
253         else if (strcmp(cmd, "cd") == 0)
254         {
255                 char       *opt = psql_scan_slash_option(scan_state,
256                                                                                                  OT_NORMAL, NULL, true);
257                 char       *dir;
258
259                 if (opt)
260                         dir = opt;
261                 else
262                 {
263 #ifndef WIN32
264                         struct passwd *pw;
265                         uid_t           user_id = geteuid();
266
267                         errno = 0;                      /* clear errno before call */
268                         pw = getpwuid(user_id);
269                         if (!pw)
270                         {
271                                 psql_error("could not get home directory for user ID %ld: %s\n",
272                                                    (long) user_id,
273                                                  errno ? strerror(errno) : _("user does not exist"));
274                                 exit(EXIT_FAILURE);
275                         }
276                         dir = pw->pw_dir;
277 #else                                                   /* WIN32 */
278
279                         /*
280                          * On Windows, 'cd' without arguments prints the current
281                          * directory, so if someone wants to code this here instead...
282                          */
283                         dir = "/";
284 #endif   /* WIN32 */
285                 }
286
287                 if (chdir(dir) == -1)
288                 {
289                         psql_error("\\%s: could not change directory to \"%s\": %s\n",
290                                            cmd, dir, strerror(errno));
291                         success = false;
292                 }
293
294                 if (opt)
295                         free(opt);
296         }
297
298         /* \conninfo -- display information about the current connection */
299         else if (strcmp(cmd, "conninfo") == 0)
300         {
301                 char       *db = PQdb(pset.db);
302
303                 if (db == NULL)
304                         printf(_("You are currently not connected to a database.\n"));
305                 else
306                 {
307                         char       *host;
308                         PQconninfoOption *connOptions;
309                         PQconninfoOption *option;
310
311                         host = PQhost(pset.db);
312                         if (host == NULL)
313                                 host = DEFAULT_PGSOCKET_DIR;
314                         /* A usable "hostaddr" overrides the basic sense of host. */
315                         connOptions = PQconninfo(pset.db);
316                         if (connOptions == NULL)
317                         {
318                                 psql_error("out of memory\n");
319                                 exit(EXIT_FAILURE);
320                         }
321                         for (option = connOptions; option && option->keyword; option++)
322                                 if (strcmp(option->keyword, "hostaddr") == 0)
323                                 {
324                                         if (option->val != NULL && option->val[0] != '\0')
325                                                 host = option->val;
326                                         break;
327                                 }
328
329                         /* If the host is an absolute path, the connection is via socket */
330                         if (is_absolute_path(host))
331                                 printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
332                                            db, PQuser(pset.db), host, PQport(pset.db));
333                         else
334                                 printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
335                                            db, PQuser(pset.db), host, PQport(pset.db));
336                         printSSLInfo();
337
338                         PQconninfoFree(connOptions);
339                 }
340         }
341
342         /* \copy */
343         else if (pg_strcasecmp(cmd, "copy") == 0)
344         {
345                 char       *opt = psql_scan_slash_option(scan_state,
346                                                                                                  OT_WHOLE_LINE, NULL, false);
347
348                 success = do_copy(opt);
349                 free(opt);
350         }
351
352         /* \copyright */
353         else if (strcmp(cmd, "copyright") == 0)
354                 print_copyright();
355
356         /* \d* commands */
357         else if (cmd[0] == 'd')
358         {
359                 char       *pattern;
360                 bool            show_verbose,
361                                         show_system;
362
363                 /* We don't do SQLID reduction on the pattern yet */
364                 pattern = psql_scan_slash_option(scan_state,
365                                                                                  OT_NORMAL, NULL, true);
366
367                 show_verbose = strchr(cmd, '+') ? true : false;
368                 show_system = strchr(cmd, 'S') ? true : false;
369
370                 switch (cmd[1])
371                 {
372                         case '\0':
373                         case '+':
374                         case 'S':
375                                 if (pattern)
376                                         success = describeTableDetails(pattern, show_verbose, show_system);
377                                 else
378                                         /* standard listing of interesting things */
379                                         success = listTables("tvmsE", NULL, show_verbose, show_system);
380                                 break;
381                         case 'a':
382                                 success = describeAggregates(pattern, show_verbose, show_system);
383                                 break;
384                         case 'b':
385                                 success = describeTablespaces(pattern, show_verbose);
386                                 break;
387                         case 'c':
388                                 success = listConversions(pattern, show_verbose, show_system);
389                                 break;
390                         case 'C':
391                                 success = listCasts(pattern, show_verbose);
392                                 break;
393                         case 'd':
394                                 if (strncmp(cmd, "ddp", 3) == 0)
395                                         success = listDefaultACLs(pattern);
396                                 else
397                                         success = objectDescription(pattern, show_system);
398                                 break;
399                         case 'D':
400                                 success = listDomains(pattern, show_verbose, show_system);
401                                 break;
402                         case 'f':                       /* function subsystem */
403                                 switch (cmd[2])
404                                 {
405                                         case '\0':
406                                         case '+':
407                                         case 'S':
408                                         case 'a':
409                                         case 'n':
410                                         case 't':
411                                         case 'w':
412                                                 success = describeFunctions(&cmd[2], pattern, show_verbose, show_system);
413                                                 break;
414                                         default:
415                                                 status = PSQL_CMD_UNKNOWN;
416                                                 break;
417                                 }
418                                 break;
419                         case 'g':
420                                 /* no longer distinct from \du */
421                                 success = describeRoles(pattern, show_verbose);
422                                 break;
423                         case 'l':
424                                 success = do_lo_list();
425                                 break;
426                         case 'L':
427                                 success = listLanguages(pattern, show_verbose, show_system);
428                                 break;
429                         case 'n':
430                                 success = listSchemas(pattern, show_verbose, show_system);
431                                 break;
432                         case 'o':
433                                 success = describeOperators(pattern, show_verbose, show_system);
434                                 break;
435                         case 'O':
436                                 success = listCollations(pattern, show_verbose, show_system);
437                                 break;
438                         case 'p':
439                                 success = permissionsList(pattern);
440                                 break;
441                         case 'T':
442                                 success = describeTypes(pattern, show_verbose, show_system);
443                                 break;
444                         case 't':
445                         case 'v':
446                         case 'm':
447                         case 'i':
448                         case 's':
449                         case 'E':
450                                 success = listTables(&cmd[1], pattern, show_verbose, show_system);
451                                 break;
452                         case 'r':
453                                 if (cmd[2] == 'd' && cmd[3] == 's')
454                                 {
455                                         char       *pattern2 = NULL;
456
457                                         if (pattern)
458                                                 pattern2 = psql_scan_slash_option(scan_state,
459                                                                                                           OT_NORMAL, NULL, true);
460                                         success = listDbRoleSettings(pattern, pattern2);
461                                 }
462                                 else
463                                         success = PSQL_CMD_UNKNOWN;
464                                 break;
465                         case 'u':
466                                 success = describeRoles(pattern, show_verbose);
467                                 break;
468                         case 'F':                       /* text search subsystem */
469                                 switch (cmd[2])
470                                 {
471                                         case '\0':
472                                         case '+':
473                                                 success = listTSConfigs(pattern, show_verbose);
474                                                 break;
475                                         case 'p':
476                                                 success = listTSParsers(pattern, show_verbose);
477                                                 break;
478                                         case 'd':
479                                                 success = listTSDictionaries(pattern, show_verbose);
480                                                 break;
481                                         case 't':
482                                                 success = listTSTemplates(pattern, show_verbose);
483                                                 break;
484                                         default:
485                                                 status = PSQL_CMD_UNKNOWN;
486                                                 break;
487                                 }
488                                 break;
489                         case 'e':                       /* SQL/MED subsystem */
490                                 switch (cmd[2])
491                                 {
492                                         case 's':
493                                                 success = listForeignServers(pattern, show_verbose);
494                                                 break;
495                                         case 'u':
496                                                 success = listUserMappings(pattern, show_verbose);
497                                                 break;
498                                         case 'w':
499                                                 success = listForeignDataWrappers(pattern, show_verbose);
500                                                 break;
501                                         case 't':
502                                                 success = listForeignTables(pattern, show_verbose);
503                                                 break;
504                                         default:
505                                                 status = PSQL_CMD_UNKNOWN;
506                                                 break;
507                                 }
508                                 break;
509                         case 'x':                       /* Extensions */
510                                 if (show_verbose)
511                                         success = listExtensionContents(pattern);
512                                 else
513                                         success = listExtensions(pattern);
514                                 break;
515                         case 'y':                       /* Event Triggers */
516                                 success = listEventTriggers(pattern, show_verbose);
517                                 break;
518                         default:
519                                 status = PSQL_CMD_UNKNOWN;
520                 }
521
522                 if (pattern)
523                         free(pattern);
524         }
525
526
527         /*
528          * \e or \edit -- edit the current query buffer, or edit a file and make
529          * it the query buffer
530          */
531         else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
532         {
533                 if (!query_buf)
534                 {
535                         psql_error("no query buffer\n");
536                         status = PSQL_CMD_ERROR;
537                 }
538                 else
539                 {
540                         char       *fname;
541                         char       *ln = NULL;
542                         int                     lineno = -1;
543
544                         fname = psql_scan_slash_option(scan_state,
545                                                                                    OT_NORMAL, NULL, true);
546                         if (fname)
547                         {
548                                 /* try to get separate lineno arg */
549                                 ln = psql_scan_slash_option(scan_state,
550                                                                                         OT_NORMAL, NULL, true);
551                                 if (ln == NULL)
552                                 {
553                                         /* only one arg; maybe it is lineno not fname */
554                                         if (fname[0] &&
555                                                 strspn(fname, "0123456789") == strlen(fname))
556                                         {
557                                                 /* all digits, so assume it is lineno */
558                                                 ln = fname;
559                                                 fname = NULL;
560                                         }
561                                 }
562                         }
563                         if (ln)
564                         {
565                                 lineno = atoi(ln);
566                                 if (lineno < 1)
567                                 {
568                                         psql_error("invalid line number: %s\n", ln);
569                                         status = PSQL_CMD_ERROR;
570                                 }
571                         }
572                         if (status != PSQL_CMD_ERROR)
573                         {
574                                 expand_tilde(&fname);
575                                 if (fname)
576                                         canonicalize_path(fname);
577                                 if (do_edit(fname, query_buf, lineno, NULL))
578                                         status = PSQL_CMD_NEWEDIT;
579                                 else
580                                         status = PSQL_CMD_ERROR;
581                         }
582                         if (fname)
583                                 free(fname);
584                         if (ln)
585                                 free(ln);
586                 }
587         }
588
589         /*
590          * \ef -- edit the named function, or present a blank CREATE FUNCTION
591          * template if no argument is given
592          */
593         else if (strcmp(cmd, "ef") == 0)
594         {
595                 int                     lineno = -1;
596
597                 if (pset.sversion < 80400)
598                 {
599                         psql_error("The server (version %d.%d) does not support editing function source.\n",
600                                            pset.sversion / 10000, (pset.sversion / 100) % 100);
601                         status = PSQL_CMD_ERROR;
602                 }
603                 else if (!query_buf)
604                 {
605                         psql_error("no query buffer\n");
606                         status = PSQL_CMD_ERROR;
607                 }
608                 else
609                 {
610                         char       *func;
611                         Oid                     foid = InvalidOid;
612
613                         func = psql_scan_slash_option(scan_state,
614                                                                                   OT_WHOLE_LINE, NULL, true);
615                         lineno = strip_lineno_from_funcdesc(func);
616                         if (lineno == 0)
617                         {
618                                 /* error already reported */
619                                 status = PSQL_CMD_ERROR;
620                         }
621                         else if (!func)
622                         {
623                                 /* set up an empty command to fill in */
624                                 printfPQExpBuffer(query_buf,
625                                                                   "CREATE FUNCTION ( )\n"
626                                                                   " RETURNS \n"
627                                                                   " LANGUAGE \n"
628                                                                   " -- common options:  IMMUTABLE  STABLE  STRICT  SECURITY DEFINER\n"
629                                                                   "AS $function$\n"
630                                                                   "\n$function$\n");
631                         }
632                         else if (!lookup_function_oid(func, &foid))
633                         {
634                                 /* error already reported */
635                                 status = PSQL_CMD_ERROR;
636                         }
637                         else if (!get_create_function_cmd(foid, query_buf))
638                         {
639                                 /* error already reported */
640                                 status = PSQL_CMD_ERROR;
641                         }
642                         else if (lineno > 0)
643                         {
644                                 /*
645                                  * lineno "1" should correspond to the first line of the
646                                  * function body.  We expect that pg_get_functiondef() will
647                                  * emit that on a line beginning with "AS ", and that there
648                                  * can be no such line before the real start of the function
649                                  * body.  Increment lineno by the number of lines before that
650                                  * line, so that it becomes relative to the first line of the
651                                  * function definition.
652                                  */
653                                 const char *lines = query_buf->data;
654
655                                 while (*lines != '\0')
656                                 {
657                                         if (strncmp(lines, "AS ", 3) == 0)
658                                                 break;
659                                         lineno++;
660                                         /* find start of next line */
661                                         lines = strchr(lines, '\n');
662                                         if (!lines)
663                                                 break;
664                                         lines++;
665                                 }
666                         }
667
668                         if (func)
669                                 free(func);
670                 }
671
672                 if (status != PSQL_CMD_ERROR)
673                 {
674                         bool            edited = false;
675
676                         if (!do_edit(NULL, query_buf, lineno, &edited))
677                                 status = PSQL_CMD_ERROR;
678                         else if (!edited)
679                                 puts(_("No changes"));
680                         else
681                                 status = PSQL_CMD_NEWEDIT;
682                 }
683         }
684
685         /* \echo and \qecho */
686         else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
687         {
688                 char       *value;
689                 char            quoted;
690                 bool            no_newline = false;
691                 bool            first = true;
692                 FILE       *fout;
693
694                 if (strcmp(cmd, "qecho") == 0)
695                         fout = pset.queryFout;
696                 else
697                         fout = stdout;
698
699                 while ((value = psql_scan_slash_option(scan_state,
700                                                                                            OT_NORMAL, &quoted, false)))
701                 {
702                         if (!quoted && strcmp(value, "-n") == 0)
703                                 no_newline = true;
704                         else
705                         {
706                                 if (first)
707                                         first = false;
708                                 else
709                                         fputc(' ', fout);
710                                 fputs(value, fout);
711                         }
712                         free(value);
713                 }
714                 if (!no_newline)
715                         fputs("\n", fout);
716         }
717
718         /* \encoding -- set/show client side encoding */
719         else if (strcmp(cmd, "encoding") == 0)
720         {
721                 char       *encoding = psql_scan_slash_option(scan_state,
722                                                                                                           OT_NORMAL, NULL, false);
723
724                 if (!encoding)
725                 {
726                         /* show encoding */
727                         puts(pg_encoding_to_char(pset.encoding));
728                 }
729                 else
730                 {
731                         /* set encoding */
732                         if (PQsetClientEncoding(pset.db, encoding) == -1)
733                                 psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
734                         else
735                         {
736                                 /* save encoding info into psql internal data */
737                                 pset.encoding = PQclientEncoding(pset.db);
738                                 pset.popt.topt.encoding = pset.encoding;
739                                 SetVariable(pset.vars, "ENCODING",
740                                                         pg_encoding_to_char(pset.encoding));
741                         }
742                         free(encoding);
743                 }
744         }
745
746         /* \f -- change field separator */
747         else if (strcmp(cmd, "f") == 0)
748         {
749                 char       *fname = psql_scan_slash_option(scan_state,
750                                                                                                    OT_NORMAL, NULL, false);
751
752                 success = do_pset("fieldsep", fname, &pset.popt, pset.quiet);
753                 free(fname);
754         }
755
756         /* \g [filename] -- send query, optionally with output to file/pipe */
757         else if (strcmp(cmd, "g") == 0)
758         {
759                 char       *fname = psql_scan_slash_option(scan_state,
760                                                                                                    OT_FILEPIPE, NULL, false);
761
762                 if (!fname)
763                         pset.gfname = NULL;
764                 else
765                 {
766                         expand_tilde(&fname);
767                         pset.gfname = pg_strdup(fname);
768                 }
769                 free(fname);
770                 status = PSQL_CMD_SEND;
771         }
772
773         /* \gset [prefix] -- send query and store result into variables */
774         else if (strcmp(cmd, "gset") == 0)
775         {
776                 char       *prefix = psql_scan_slash_option(scan_state,
777                                                                                                         OT_NORMAL, NULL, false);
778
779                 if (prefix)
780                         pset.gset_prefix = prefix;
781                 else
782                 {
783                         /* we must set a non-NULL prefix to trigger storing */
784                         pset.gset_prefix = pg_strdup("");
785                 }
786                 /* gset_prefix is freed later */
787                 status = PSQL_CMD_SEND;
788         }
789
790         /* help */
791         else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
792         {
793                 char       *opt = psql_scan_slash_option(scan_state,
794                                                                                                  OT_WHOLE_LINE, NULL, false);
795                 size_t          len;
796
797                 /* strip any trailing spaces and semicolons */
798                 if (opt)
799                 {
800                         len = strlen(opt);
801                         while (len > 0 &&
802                                    (isspace((unsigned char) opt[len - 1])
803                                         || opt[len - 1] == ';'))
804                                 opt[--len] = '\0';
805                 }
806
807                 helpSQL(opt, pset.popt.topt.pager);
808                 free(opt);
809         }
810
811         /* HTML mode */
812         else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
813         {
814                 if (pset.popt.topt.format != PRINT_HTML)
815                         success = do_pset("format", "html", &pset.popt, pset.quiet);
816                 else
817                         success = do_pset("format", "aligned", &pset.popt, pset.quiet);
818         }
819
820
821         /* \i and \ir include files */
822         else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0
823                    || strcmp(cmd, "ir") == 0 || strcmp(cmd, "include_relative") == 0)
824         {
825                 char       *fname = psql_scan_slash_option(scan_state,
826                                                                                                    OT_NORMAL, NULL, true);
827
828                 if (!fname)
829                 {
830                         psql_error("\\%s: missing required argument\n", cmd);
831                         success = false;
832                 }
833                 else
834                 {
835                         bool            include_relative;
836
837                         include_relative = (strcmp(cmd, "ir") == 0
838                                                                 || strcmp(cmd, "include_relative") == 0);
839                         expand_tilde(&fname);
840                         success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
841                         free(fname);
842                 }
843         }
844
845         /* \l is list databases */
846         else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0 ||
847                          strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
848         {
849                 char       *pattern;
850                 bool            show_verbose;
851
852                 pattern = psql_scan_slash_option(scan_state,
853                                                                                  OT_NORMAL, NULL, true);
854
855                 show_verbose = strchr(cmd, '+') ? true : false;
856
857                 success = listAllDbs(pattern, show_verbose);
858
859                 if (pattern)
860                         free(pattern);
861         }
862
863         /*
864          * large object things
865          */
866         else if (strncmp(cmd, "lo_", 3) == 0)
867         {
868                 char       *opt1,
869                                    *opt2;
870
871                 opt1 = psql_scan_slash_option(scan_state,
872                                                                           OT_NORMAL, NULL, true);
873                 opt2 = psql_scan_slash_option(scan_state,
874                                                                           OT_NORMAL, NULL, true);
875
876                 if (strcmp(cmd + 3, "export") == 0)
877                 {
878                         if (!opt2)
879                         {
880                                 psql_error("\\%s: missing required argument\n", cmd);
881                                 success = false;
882                         }
883                         else
884                         {
885                                 expand_tilde(&opt2);
886                                 success = do_lo_export(opt1, opt2);
887                         }
888                 }
889
890                 else if (strcmp(cmd + 3, "import") == 0)
891                 {
892                         if (!opt1)
893                         {
894                                 psql_error("\\%s: missing required argument\n", cmd);
895                                 success = false;
896                         }
897                         else
898                         {
899                                 expand_tilde(&opt1);
900                                 success = do_lo_import(opt1, opt2);
901                         }
902                 }
903
904                 else if (strcmp(cmd + 3, "list") == 0)
905                         success = do_lo_list();
906
907                 else if (strcmp(cmd + 3, "unlink") == 0)
908                 {
909                         if (!opt1)
910                         {
911                                 psql_error("\\%s: missing required argument\n", cmd);
912                                 success = false;
913                         }
914                         else
915                                 success = do_lo_unlink(opt1);
916                 }
917
918                 else
919                         status = PSQL_CMD_UNKNOWN;
920
921                 free(opt1);
922                 free(opt2);
923         }
924
925
926         /* \o -- set query output */
927         else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
928         {
929                 char       *fname = psql_scan_slash_option(scan_state,
930                                                                                                    OT_FILEPIPE, NULL, true);
931
932                 expand_tilde(&fname);
933                 success = setQFout(fname);
934                 free(fname);
935         }
936
937         /* \p prints the current query buffer */
938         else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
939         {
940                 if (query_buf && query_buf->len > 0)
941                         puts(query_buf->data);
942                 else if (!pset.quiet)
943                         puts(_("Query buffer is empty."));
944                 fflush(stdout);
945         }
946
947         /* \password -- set user password */
948         else if (strcmp(cmd, "password") == 0)
949         {
950                 char       *pw1;
951                 char       *pw2;
952
953                 pw1 = simple_prompt("Enter new password: ", 100, false);
954                 pw2 = simple_prompt("Enter it again: ", 100, false);
955
956                 if (strcmp(pw1, pw2) != 0)
957                 {
958                         psql_error("Passwords didn't match.\n");
959                         success = false;
960                 }
961                 else
962                 {
963                         char       *opt0 = psql_scan_slash_option(scan_state, OT_SQLID, NULL, true);
964                         char       *user;
965                         char       *encrypted_password;
966
967                         if (opt0)
968                                 user = opt0;
969                         else
970                                 user = PQuser(pset.db);
971
972                         encrypted_password = PQencryptPassword(pw1, user);
973
974                         if (!encrypted_password)
975                         {
976                                 psql_error("Password encryption failed.\n");
977                                 success = false;
978                         }
979                         else
980                         {
981                                 PQExpBufferData buf;
982                                 PGresult   *res;
983
984                                 initPQExpBuffer(&buf);
985                                 printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ",
986                                                                   fmtId(user));
987                                 appendStringLiteralConn(&buf, encrypted_password, pset.db);
988                                 res = PSQLexec(buf.data);
989                                 termPQExpBuffer(&buf);
990                                 if (!res)
991                                         success = false;
992                                 else
993                                         PQclear(res);
994                                 PQfreemem(encrypted_password);
995                         }
996
997                         if (opt0)
998                                 free(opt0);
999                 }
1000
1001                 free(pw1);
1002                 free(pw2);
1003         }
1004
1005         /* \prompt -- prompt and set variable */
1006         else if (strcmp(cmd, "prompt") == 0)
1007         {
1008                 char       *opt,
1009                                    *prompt_text = NULL;
1010                 char       *arg1,
1011                                    *arg2;
1012
1013                 arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
1014                 arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
1015
1016                 if (!arg1)
1017                 {
1018                         psql_error("\\%s: missing required argument\n", cmd);
1019                         success = false;
1020                 }
1021                 else
1022                 {
1023                         char       *result;
1024
1025                         if (arg2)
1026                         {
1027                                 prompt_text = arg1;
1028                                 opt = arg2;
1029                         }
1030                         else
1031                                 opt = arg1;
1032
1033                         if (!pset.inputfile)
1034                                 result = simple_prompt(prompt_text, 4096, true);
1035                         else
1036                         {
1037                                 if (prompt_text)
1038                                 {
1039                                         fputs(prompt_text, stdout);
1040                                         fflush(stdout);
1041                                 }
1042                                 result = gets_fromFile(stdin);
1043                         }
1044
1045                         if (!SetVariable(pset.vars, opt, result))
1046                         {
1047                                 psql_error("\\%s: error while setting variable\n", cmd);
1048                                 success = false;
1049                         }
1050
1051                         free(result);
1052                         if (prompt_text)
1053                                 free(prompt_text);
1054                         free(opt);
1055                 }
1056         }
1057
1058         /* \pset -- set printing parameters */
1059         else if (strcmp(cmd, "pset") == 0)
1060         {
1061                 char       *opt0 = psql_scan_slash_option(scan_state,
1062                                                                                                   OT_NORMAL, NULL, false);
1063                 char       *opt1 = psql_scan_slash_option(scan_state,
1064                                                                                                   OT_NORMAL, NULL, false);
1065
1066                 if (!opt0)
1067                 {
1068                         /* list all variables */
1069
1070                         int                     i;
1071                         static const char *const my_list[] = {
1072                                 "border", "columns", "expanded", "fieldsep", "fieldsep_zero",
1073                                 "footer", "format", "linestyle", "null",
1074                                 "numericlocale", "pager", "pager_min_lines",
1075                                 "recordsep", "recordsep_zero",
1076                                 "tableattr", "title", "tuples_only",
1077                                 "unicode_border_linestyle",
1078                                 "unicode_column_linestyle",
1079                                 "unicode_header_linestyle",
1080                                 NULL
1081                         };
1082
1083                         for (i = 0; my_list[i] != NULL; i++)
1084                         {
1085                                 char   *val = pset_value_string(my_list[i], &pset.popt);
1086                                 printf("%-24s %s\n", my_list[i], val);
1087                                 free(val);
1088                         }
1089
1090                         success = true;
1091                 }
1092                 else
1093                         success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
1094
1095                 free(opt0);
1096                 free(opt1);
1097         }
1098
1099         /* \q or \quit */
1100         else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
1101                 status = PSQL_CMD_TERMINATE;
1102
1103         /* reset(clear) the buffer */
1104         else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
1105         {
1106                 resetPQExpBuffer(query_buf);
1107                 psql_scan_reset(scan_state);
1108                 if (!pset.quiet)
1109                         puts(_("Query buffer reset (cleared)."));
1110         }
1111
1112         /* \s save history in a file or show it on the screen */
1113         else if (strcmp(cmd, "s") == 0)
1114         {
1115                 char       *fname = psql_scan_slash_option(scan_state,
1116                                                                                                    OT_NORMAL, NULL, true);
1117
1118                 expand_tilde(&fname);
1119                 success = printHistory(fname, pset.popt.topt.pager);
1120                 if (success && !pset.quiet && fname)
1121                         printf(_("Wrote history to file \"%s\".\n"), fname);
1122                 if (!fname)
1123                         putchar('\n');
1124                 free(fname);
1125         }
1126
1127         /* \set -- generalized set variable/option command */
1128         else if (strcmp(cmd, "set") == 0)
1129         {
1130                 char       *opt0 = psql_scan_slash_option(scan_state,
1131                                                                                                   OT_NORMAL, NULL, false);
1132
1133                 if (!opt0)
1134                 {
1135                         /* list all variables */
1136                         PrintVariables(pset.vars);
1137                         success = true;
1138                 }
1139                 else
1140                 {
1141                         /*
1142                          * Set variable to the concatenation of the arguments.
1143                          */
1144                         char       *newval;
1145                         char       *opt;
1146
1147                         opt = psql_scan_slash_option(scan_state,
1148                                                                                  OT_NORMAL, NULL, false);
1149                         newval = pg_strdup(opt ? opt : "");
1150                         free(opt);
1151
1152                         while ((opt = psql_scan_slash_option(scan_state,
1153                                                                                                  OT_NORMAL, NULL, false)))
1154                         {
1155                                 newval = pg_realloc(newval, strlen(newval) + strlen(opt) + 1);
1156                                 strcat(newval, opt);
1157                                 free(opt);
1158                         }
1159
1160                         if (!SetVariable(pset.vars, opt0, newval))
1161                         {
1162                                 psql_error("\\%s: error while setting variable\n", cmd);
1163                                 success = false;
1164                         }
1165                         free(newval);
1166                 }
1167                 free(opt0);
1168         }
1169
1170
1171         /* \setenv -- set environment command */
1172         else if (strcmp(cmd, "setenv") == 0)
1173         {
1174                 char       *envvar = psql_scan_slash_option(scan_state,
1175                                                                                                         OT_NORMAL, NULL, false);
1176                 char       *envval = psql_scan_slash_option(scan_state,
1177                                                                                                         OT_NORMAL, NULL, false);
1178
1179                 if (!envvar)
1180                 {
1181                         psql_error("\\%s: missing required argument\n", cmd);
1182                         success = false;
1183                 }
1184                 else if (strchr(envvar, '=') != NULL)
1185                 {
1186                         psql_error("\\%s: environment variable name must not contain \"=\"\n",
1187                                            cmd);
1188                         success = false;
1189                 }
1190                 else if (!envval)
1191                 {
1192                         /* No argument - unset the environment variable */
1193                         unsetenv(envvar);
1194                         success = true;
1195                 }
1196                 else
1197                 {
1198                         /* Set variable to the value of the next argument */
1199                         char       *newval;
1200
1201                         newval = psprintf("%s=%s", envvar, envval);
1202                         putenv(newval);
1203                         success = true;
1204
1205                         /*
1206                          * Do not free newval here, it will screw up the environment if
1207                          * you do. See putenv man page for details. That means we leak a
1208                          * bit of memory here, but not enough to worry about.
1209                          */
1210                 }
1211                 free(envvar);
1212                 free(envval);
1213         }
1214
1215         /* \sf -- show a function's source code */
1216         else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
1217         {
1218                 bool            show_linenumbers = (strcmp(cmd, "sf+") == 0);
1219                 PQExpBuffer func_buf;
1220                 char       *func;
1221                 Oid                     foid = InvalidOid;
1222
1223                 func_buf = createPQExpBuffer();
1224                 func = psql_scan_slash_option(scan_state,
1225                                                                           OT_WHOLE_LINE, NULL, true);
1226                 if (pset.sversion < 80400)
1227                 {
1228                         psql_error("The server (version %d.%d) does not support showing function source.\n",
1229                                            pset.sversion / 10000, (pset.sversion / 100) % 100);
1230                         status = PSQL_CMD_ERROR;
1231                 }
1232                 else if (!func)
1233                 {
1234                         psql_error("function name is required\n");
1235                         status = PSQL_CMD_ERROR;
1236                 }
1237                 else if (!lookup_function_oid(func, &foid))
1238                 {
1239                         /* error already reported */
1240                         status = PSQL_CMD_ERROR;
1241                 }
1242                 else if (!get_create_function_cmd(foid, func_buf))
1243                 {
1244                         /* error already reported */
1245                         status = PSQL_CMD_ERROR;
1246                 }
1247                 else
1248                 {
1249                         FILE       *output;
1250                         bool            is_pager;
1251
1252                         /* Select output stream: stdout, pager, or file */
1253                         if (pset.queryFout == stdout)
1254                         {
1255                                 /* count lines in function to see if pager is needed */
1256                                 int                     lineno = 0;
1257                                 const char *lines = func_buf->data;
1258
1259                                 while (*lines != '\0')
1260                                 {
1261                                         lineno++;
1262                                         /* find start of next line */
1263                                         lines = strchr(lines, '\n');
1264                                         if (!lines)
1265                                                 break;
1266                                         lines++;
1267                                 }
1268
1269                                 output = PageOutput(lineno, &(pset.popt.topt));
1270                                 is_pager = true;
1271                         }
1272                         else
1273                         {
1274                                 /* use previously set output file, without pager */
1275                                 output = pset.queryFout;
1276                                 is_pager = false;
1277                         }
1278
1279                         if (show_linenumbers)
1280                         {
1281                                 bool            in_header = true;
1282                                 int                     lineno = 0;
1283                                 char       *lines = func_buf->data;
1284
1285                                 /*
1286                                  * lineno "1" should correspond to the first line of the
1287                                  * function body.  We expect that pg_get_functiondef() will
1288                                  * emit that on a line beginning with "AS ", and that there
1289                                  * can be no such line before the real start of the function
1290                                  * body.
1291                                  *
1292                                  * Note that this loop scribbles on func_buf.
1293                                  */
1294                                 while (*lines != '\0')
1295                                 {
1296                                         char       *eol;
1297
1298                                         if (in_header && strncmp(lines, "AS ", 3) == 0)
1299                                                 in_header = false;
1300                                         /* increment lineno only for body's lines */
1301                                         if (!in_header)
1302                                                 lineno++;
1303
1304                                         /* find and mark end of current line */
1305                                         eol = strchr(lines, '\n');
1306                                         if (eol != NULL)
1307                                                 *eol = '\0';
1308
1309                                         /* show current line as appropriate */
1310                                         if (in_header)
1311                                                 fprintf(output, "        %s\n", lines);
1312                                         else
1313                                                 fprintf(output, "%-7d %s\n", lineno, lines);
1314
1315                                         /* advance to next line, if any */
1316                                         if (eol == NULL)
1317                                                 break;
1318                                         lines = ++eol;
1319                                 }
1320                         }
1321                         else
1322                         {
1323                                 /* just send the function definition to output */
1324                                 fputs(func_buf->data, output);
1325                         }
1326
1327                         if (is_pager)
1328                                 ClosePager(output);
1329                 }
1330
1331                 if (func)
1332                         free(func);
1333                 destroyPQExpBuffer(func_buf);
1334         }
1335
1336         /* \t -- turn off headers and row count */
1337         else if (strcmp(cmd, "t") == 0)
1338         {
1339                 char       *opt = psql_scan_slash_option(scan_state,
1340                                                                                                  OT_NORMAL, NULL, true);
1341
1342                 success = do_pset("tuples_only", opt, &pset.popt, pset.quiet);
1343                 free(opt);
1344         }
1345
1346         /* \T -- define html <table ...> attributes */
1347         else if (strcmp(cmd, "T") == 0)
1348         {
1349                 char       *value = psql_scan_slash_option(scan_state,
1350                                                                                                    OT_NORMAL, NULL, false);
1351
1352                 success = do_pset("tableattr", value, &pset.popt, pset.quiet);
1353                 free(value);
1354         }
1355
1356         /* \timing -- toggle timing of queries */
1357         else if (strcmp(cmd, "timing") == 0)
1358         {
1359                 char       *opt = psql_scan_slash_option(scan_state,
1360                                                                                                  OT_NORMAL, NULL, false);
1361
1362                 if (opt)
1363                         pset.timing = ParseVariableBool(opt, "\\timing");
1364                 else
1365                         pset.timing = !pset.timing;
1366                 if (!pset.quiet)
1367                 {
1368                         if (pset.timing)
1369                                 puts(_("Timing is on."));
1370                         else
1371                                 puts(_("Timing is off."));
1372                 }
1373                 free(opt);
1374         }
1375
1376         /* \unset */
1377         else if (strcmp(cmd, "unset") == 0)
1378         {
1379                 char       *opt = psql_scan_slash_option(scan_state,
1380                                                                                                  OT_NORMAL, NULL, false);
1381
1382                 if (!opt)
1383                 {
1384                         psql_error("\\%s: missing required argument\n", cmd);
1385                         success = false;
1386                 }
1387                 else if (!SetVariable(pset.vars, opt, NULL))
1388                 {
1389                         psql_error("\\%s: error while setting variable\n", cmd);
1390                         success = false;
1391                 }
1392                 free(opt);
1393         }
1394
1395         /* \w -- write query buffer to file */
1396         else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
1397         {
1398                 FILE       *fd = NULL;
1399                 bool            is_pipe = false;
1400                 char       *fname = NULL;
1401
1402                 if (!query_buf)
1403                 {
1404                         psql_error("no query buffer\n");
1405                         status = PSQL_CMD_ERROR;
1406                 }
1407                 else
1408                 {
1409                         fname = psql_scan_slash_option(scan_state,
1410                                                                                    OT_FILEPIPE, NULL, true);
1411                         expand_tilde(&fname);
1412
1413                         if (!fname)
1414                         {
1415                                 psql_error("\\%s: missing required argument\n", cmd);
1416                                 success = false;
1417                         }
1418                         else
1419                         {
1420                                 if (fname[0] == '|')
1421                                 {
1422                                         is_pipe = true;
1423                                         fd = popen(&fname[1], "w");
1424                                 }
1425                                 else
1426                                 {
1427                                         canonicalize_path(fname);
1428                                         fd = fopen(fname, "w");
1429                                 }
1430                                 if (!fd)
1431                                 {
1432                                         psql_error("%s: %s\n", fname, strerror(errno));
1433                                         success = false;
1434                                 }
1435                         }
1436                 }
1437
1438                 if (fd)
1439                 {
1440                         int                     result;
1441
1442                         if (query_buf && query_buf->len > 0)
1443                                 fprintf(fd, "%s\n", query_buf->data);
1444
1445                         if (is_pipe)
1446                                 result = pclose(fd);
1447                         else
1448                                 result = fclose(fd);
1449
1450                         if (result == EOF)
1451                         {
1452                                 psql_error("%s: %s\n", fname, strerror(errno));
1453                                 success = false;
1454                         }
1455                 }
1456
1457                 free(fname);
1458         }
1459
1460         /* \watch -- execute a query every N seconds */
1461         else if (strcmp(cmd, "watch") == 0)
1462         {
1463                 char       *opt = psql_scan_slash_option(scan_state,
1464                                                                                                  OT_NORMAL, NULL, true);
1465                 long            sleep = 2;
1466
1467                 /* Convert optional sleep-length argument */
1468                 if (opt)
1469                 {
1470                         sleep = strtol(opt, NULL, 10);
1471                         if (sleep <= 0)
1472                                 sleep = 1;
1473                         free(opt);
1474                 }
1475
1476                 success = do_watch(query_buf, sleep);
1477
1478                 /* Reset the query buffer as though for \r */
1479                 resetPQExpBuffer(query_buf);
1480                 psql_scan_reset(scan_state);
1481         }
1482
1483         /* \x -- set or toggle expanded table representation */
1484         else if (strcmp(cmd, "x") == 0)
1485         {
1486                 char       *opt = psql_scan_slash_option(scan_state,
1487                                                                                                  OT_NORMAL, NULL, true);
1488
1489                 success = do_pset("expanded", opt, &pset.popt, pset.quiet);
1490                 free(opt);
1491         }
1492
1493         /* \z -- list table rights (equivalent to \dp) */
1494         else if (strcmp(cmd, "z") == 0)
1495         {
1496                 char       *pattern = psql_scan_slash_option(scan_state,
1497                                                                                                          OT_NORMAL, NULL, true);
1498
1499                 success = permissionsList(pattern);
1500                 if (pattern)
1501                         free(pattern);
1502         }
1503
1504         /* \! -- shell escape */
1505         else if (strcmp(cmd, "!") == 0)
1506         {
1507                 char       *opt = psql_scan_slash_option(scan_state,
1508                                                                                                  OT_WHOLE_LINE, NULL, false);
1509
1510                 success = do_shell(opt);
1511                 free(opt);
1512         }
1513
1514         /* \? -- slash command help */
1515         else if (strcmp(cmd, "?") == 0)
1516         {
1517                 char       *opt0 = psql_scan_slash_option(scan_state,
1518                                                                                                         OT_NORMAL, NULL, false);
1519
1520                 if (!opt0 || strcmp(opt0, "commands") == 0)
1521                         slashUsage(pset.popt.topt.pager);
1522                 else if (strcmp(opt0, "options") == 0)
1523                         usage(pset.popt.topt.pager);
1524                 else if (strcmp(opt0, "variables") == 0)
1525                         helpVariables(pset.popt.topt.pager);
1526                 else
1527                         slashUsage(pset.popt.topt.pager);
1528         }
1529
1530 #if 0
1531
1532         /*
1533          * These commands don't do anything. I just use them to test the parser.
1534          */
1535         else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
1536         {
1537                 int                     i = 0;
1538                 char       *value;
1539
1540                 while ((value = psql_scan_slash_option(scan_state,
1541                                                                                            OT_NORMAL, NULL, true)))
1542                 {
1543                         psql_error("+ opt(%d) = |%s|\n", i++, value);
1544                         free(value);
1545                 }
1546         }
1547 #endif
1548
1549         else
1550                 status = PSQL_CMD_UNKNOWN;
1551
1552         if (!success)
1553                 status = PSQL_CMD_ERROR;
1554
1555         return status;
1556 }
1557
1558 /*
1559  * Ask the user for a password; 'username' is the username the
1560  * password is for, if one has been explicitly specified. Returns a
1561  * malloc'd string.
1562  */
1563 static char *
1564 prompt_for_password(const char *username)
1565 {
1566         char       *result;
1567
1568         if (username == NULL)
1569                 result = simple_prompt("Password: ", 100, false);
1570         else
1571         {
1572                 char       *prompt_text;
1573
1574                 prompt_text = psprintf(_("Password for user %s: "), username);
1575                 result = simple_prompt(prompt_text, 100, false);
1576                 free(prompt_text);
1577         }
1578
1579         return result;
1580 }
1581
1582 static bool
1583 param_is_newly_set(const char *old_val, const char *new_val)
1584 {
1585         if (new_val == NULL)
1586                 return false;
1587
1588         if (old_val == NULL || strcmp(old_val, new_val) != 0)
1589                 return true;
1590
1591         return false;
1592 }
1593
1594 /*
1595  * do_connect -- handler for \connect
1596  *
1597  * Connects to a database with given parameters. If there exists an
1598  * established connection, NULL values will be replaced with the ones
1599  * in the current connection. Otherwise NULL will be passed for that
1600  * parameter to PQconnectdbParams(), so the libpq defaults will be used.
1601  *
1602  * In interactive mode, if connection fails with the given parameters,
1603  * the old connection will be kept.
1604  */
1605 static bool
1606 do_connect(char *dbname, char *user, char *host, char *port)
1607 {
1608         PGconn     *o_conn = pset.db,
1609                            *n_conn;
1610         char       *password = NULL;
1611
1612         if (!o_conn && (!dbname || !user || !host || !port))
1613         {
1614                 /*
1615                  * We don't know the supplied connection parameters and don't want to
1616                  * connect to the wrong database by using defaults, so require all
1617                  * parameters to be specified.
1618                  */
1619                 psql_error("All connection parameters must be supplied because no "
1620                                    "database connection exists\n");
1621                 return false;
1622         }
1623
1624         if (!dbname)
1625                 dbname = PQdb(o_conn);
1626         if (!user)
1627                 user = PQuser(o_conn);
1628         if (!host)
1629                 host = PQhost(o_conn);
1630         if (!port)
1631                 port = PQport(o_conn);
1632
1633         /*
1634          * If the user asked to be prompted for a password, ask for one now. If
1635          * not, use the password from the old connection, provided the username
1636          * has not changed. Otherwise, try to connect without a password first,
1637          * and then ask for a password if needed.
1638          *
1639          * XXX: this behavior leads to spurious connection attempts recorded in
1640          * the postmaster's log.  But libpq offers no API that would let us obtain
1641          * a password and then continue with the first connection attempt.
1642          */
1643         if (pset.getPassword == TRI_YES)
1644         {
1645                 password = prompt_for_password(user);
1646         }
1647         else if (o_conn && user && strcmp(PQuser(o_conn), user) == 0)
1648         {
1649                 password = pg_strdup(PQpass(o_conn));
1650         }
1651
1652         while (true)
1653         {
1654 #define PARAMS_ARRAY_SIZE       8
1655                 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
1656                 const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
1657
1658                 keywords[0] = "host";
1659                 values[0] = host;
1660                 keywords[1] = "port";
1661                 values[1] = port;
1662                 keywords[2] = "user";
1663                 values[2] = user;
1664                 keywords[3] = "password";
1665                 values[3] = password;
1666                 keywords[4] = "dbname";
1667                 values[4] = dbname;
1668                 keywords[5] = "fallback_application_name";
1669                 values[5] = pset.progname;
1670                 keywords[6] = "client_encoding";
1671                 values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
1672                 keywords[7] = NULL;
1673                 values[7] = NULL;
1674
1675                 n_conn = PQconnectdbParams(keywords, values, true);
1676
1677                 free(keywords);
1678                 free(values);
1679
1680                 /* We can immediately discard the password -- no longer needed */
1681                 if (password)
1682                         free(password);
1683
1684                 if (PQstatus(n_conn) == CONNECTION_OK)
1685                         break;
1686
1687                 /*
1688                  * Connection attempt failed; either retry the connection attempt with
1689                  * a new password, or give up.
1690                  */
1691                 if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
1692                 {
1693                         PQfinish(n_conn);
1694                         password = prompt_for_password(user);
1695                         continue;
1696                 }
1697
1698                 /*
1699                  * Failed to connect to the database. In interactive mode, keep the
1700                  * previous connection to the DB; in scripting mode, close our
1701                  * previous connection as well.
1702                  */
1703                 if (pset.cur_cmd_interactive)
1704                 {
1705                         psql_error("%s", PQerrorMessage(n_conn));
1706
1707                         /* pset.db is left unmodified */
1708                         if (o_conn)
1709                                 psql_error("Previous connection kept\n");
1710                 }
1711                 else
1712                 {
1713                         psql_error("\\connect: %s", PQerrorMessage(n_conn));
1714                         if (o_conn)
1715                         {
1716                                 PQfinish(o_conn);
1717                                 pset.db = NULL;
1718                         }
1719                 }
1720
1721                 PQfinish(n_conn);
1722                 return false;
1723         }
1724
1725         /*
1726          * Replace the old connection with the new one, and update
1727          * connection-dependent variables.
1728          */
1729         PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
1730         pset.db = n_conn;
1731         SyncVariables();
1732         connection_warnings(false); /* Must be after SyncVariables */
1733
1734         /* Tell the user about the new connection */
1735         if (!pset.quiet)
1736         {
1737                 if (param_is_newly_set(PQhost(o_conn), PQhost(pset.db)) ||
1738                         param_is_newly_set(PQport(o_conn), PQport(pset.db)))
1739                 {
1740                         char       *host = PQhost(pset.db);
1741
1742                         if (host == NULL)
1743                                 host = DEFAULT_PGSOCKET_DIR;
1744                         /* If the host is an absolute path, the connection is via socket */
1745                         if (is_absolute_path(host))
1746                                 printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
1747                                            PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
1748                         else
1749                                 printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
1750                                            PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
1751                 }
1752                 else
1753                         printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
1754                                    PQdb(pset.db), PQuser(pset.db));
1755         }
1756
1757         if (o_conn)
1758                 PQfinish(o_conn);
1759         return true;
1760 }
1761
1762
1763 void
1764 connection_warnings(bool in_startup)
1765 {
1766         if (!pset.quiet && !pset.notty)
1767         {
1768                 int                     client_ver = PG_VERSION_NUM;
1769
1770                 if (pset.sversion != client_ver)
1771                 {
1772                         const char *server_version;
1773                         char            server_ver_str[16];
1774
1775                         /* Try to get full text form, might include "devel" etc */
1776                         server_version = PQparameterStatus(pset.db, "server_version");
1777                         if (!server_version)
1778                         {
1779                                 snprintf(server_ver_str, sizeof(server_ver_str),
1780                                                  "%d.%d.%d",
1781                                                  pset.sversion / 10000,
1782                                                  (pset.sversion / 100) % 100,
1783                                                  pset.sversion % 100);
1784                                 server_version = server_ver_str;
1785                         }
1786
1787                         printf(_("%s (%s, server %s)\n"),
1788                                    pset.progname, PG_VERSION, server_version);
1789                 }
1790                 /* For version match, only print psql banner on startup. */
1791                 else if (in_startup)
1792                         printf("%s (%s)\n", pset.progname, PG_VERSION);
1793
1794                 if (pset.sversion / 100 > client_ver / 100)
1795                         printf(_("WARNING: %s major version %d.%d, server major version %d.%d.\n"
1796                                          "         Some psql features might not work.\n"),
1797                                  pset.progname, client_ver / 10000, (client_ver / 100) % 100,
1798                                    pset.sversion / 10000, (pset.sversion / 100) % 100);
1799
1800 #ifdef WIN32
1801                 checkWin32Codepage();
1802 #endif
1803                 printSSLInfo();
1804         }
1805 }
1806
1807
1808 /*
1809  * printSSLInfo
1810  *
1811  * Prints information about the current SSL connection, if SSL is in use
1812  */
1813 static void
1814 printSSLInfo(void)
1815 {
1816         const char *protocol;
1817         const char *cipher;
1818         const char *bits;
1819         const char *compression;
1820
1821         if (!PQsslInUse(pset.db))
1822                 return;                                 /* no SSL */
1823
1824         protocol = PQsslAttribute(pset.db, "protocol");
1825         cipher = PQsslAttribute(pset.db, "cipher");
1826         bits = PQsslAttribute(pset.db, "key_bits");
1827         compression = PQsslAttribute(pset.db, "compression");
1828
1829         printf(_("SSL connection (protocol: %s, cipher: %s, bits: %s, compression: %s)\n"),
1830                    protocol ? protocol : _("unknown"),
1831                    cipher ? cipher : _("unknown"),
1832                    bits ? bits : _("unknown"),
1833                    (compression && strcmp(compression, "off") != 0) ? _("on") : _("off"));
1834 }
1835
1836
1837 /*
1838  * checkWin32Codepage
1839  *
1840  * Prints a warning when win32 console codepage differs from Windows codepage
1841  */
1842 #ifdef WIN32
1843 static void
1844 checkWin32Codepage(void)
1845 {
1846         unsigned int wincp,
1847                                 concp;
1848
1849         wincp = GetACP();
1850         concp = GetConsoleCP();
1851         if (wincp != concp)
1852         {
1853                 printf(_("WARNING: Console code page (%u) differs from Windows code page (%u)\n"
1854                                  "         8-bit characters might not work correctly. See psql reference\n"
1855                                  "         page \"Notes for Windows users\" for details.\n"),
1856                            concp, wincp);
1857         }
1858 }
1859 #endif
1860
1861
1862 /*
1863  * SyncVariables
1864  *
1865  * Make psql's internal variables agree with connection state upon
1866  * establishing a new connection.
1867  */
1868 void
1869 SyncVariables(void)
1870 {
1871         /* get stuff from connection */
1872         pset.encoding = PQclientEncoding(pset.db);
1873         pset.popt.topt.encoding = pset.encoding;
1874         pset.sversion = PQserverVersion(pset.db);
1875
1876         SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
1877         SetVariable(pset.vars, "USER", PQuser(pset.db));
1878         SetVariable(pset.vars, "HOST", PQhost(pset.db));
1879         SetVariable(pset.vars, "PORT", PQport(pset.db));
1880         SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
1881
1882         /* send stuff to it, too */
1883         PQsetErrorVerbosity(pset.db, pset.verbosity);
1884 }
1885
1886 /*
1887  * UnsyncVariables
1888  *
1889  * Clear variables that should be not be set when there is no connection.
1890  */
1891 void
1892 UnsyncVariables(void)
1893 {
1894         SetVariable(pset.vars, "DBNAME", NULL);
1895         SetVariable(pset.vars, "USER", NULL);
1896         SetVariable(pset.vars, "HOST", NULL);
1897         SetVariable(pset.vars, "PORT", NULL);
1898         SetVariable(pset.vars, "ENCODING", NULL);
1899 }
1900
1901
1902 /*
1903  * do_edit -- handler for \e
1904  *
1905  * If you do not specify a filename, the current query buffer will be copied
1906  * into a temporary one.
1907  */
1908 static bool
1909 editFile(const char *fname, int lineno)
1910 {
1911         const char *editorName;
1912         const char *editor_lineno_arg = NULL;
1913         char       *sys;
1914         int                     result;
1915
1916         Assert(fname != NULL);
1917
1918         /* Find an editor to use */
1919         editorName = getenv("PSQL_EDITOR");
1920         if (!editorName)
1921                 editorName = getenv("EDITOR");
1922         if (!editorName)
1923                 editorName = getenv("VISUAL");
1924         if (!editorName)
1925                 editorName = DEFAULT_EDITOR;
1926
1927         /* Get line number argument, if we need it. */
1928         if (lineno > 0)
1929         {
1930                 editor_lineno_arg = getenv("PSQL_EDITOR_LINENUMBER_ARG");
1931 #ifdef DEFAULT_EDITOR_LINENUMBER_ARG
1932                 if (!editor_lineno_arg)
1933                         editor_lineno_arg = DEFAULT_EDITOR_LINENUMBER_ARG;
1934 #endif
1935                 if (!editor_lineno_arg)
1936                 {
1937                         psql_error("environment variable PSQL_EDITOR_LINENUMBER_ARG must be set to specify a line number\n");
1938                         return false;
1939                 }
1940         }
1941
1942         /*
1943          * On Unix the EDITOR value should *not* be quoted, since it might include
1944          * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
1945          * if necessary.  But this policy is not very workable on Windows, due to
1946          * severe brain damage in their command shell plus the fact that standard
1947          * program paths include spaces.
1948          */
1949 #ifndef WIN32
1950         if (lineno > 0)
1951                 sys = psprintf("exec %s %s%d '%s'",
1952                                            editorName, editor_lineno_arg, lineno, fname);
1953         else
1954                 sys = psprintf("exec %s '%s'",
1955                                            editorName, fname);
1956 #else
1957         if (lineno > 0)
1958                 sys = psprintf("\"%s\" %s%d \"%s\"",
1959                                            editorName, editor_lineno_arg, lineno, fname);
1960         else
1961                 sys = psprintf("\"%s\" \"%s\"",
1962                                            editorName, fname);
1963 #endif
1964         result = system(sys);
1965         if (result == -1)
1966                 psql_error("could not start editor \"%s\"\n", editorName);
1967         else if (result == 127)
1968                 psql_error("could not start /bin/sh\n");
1969         free(sys);
1970
1971         return result == 0;
1972 }
1973
1974
1975 /* call this one */
1976 static bool
1977 do_edit(const char *filename_arg, PQExpBuffer query_buf,
1978                 int lineno, bool *edited)
1979 {
1980         char            fnametmp[MAXPGPATH];
1981         FILE       *stream = NULL;
1982         const char *fname;
1983         bool            error = false;
1984         int                     fd;
1985
1986         struct stat before,
1987                                 after;
1988
1989         if (filename_arg)
1990                 fname = filename_arg;
1991         else
1992         {
1993                 /* make a temp file to edit */
1994 #ifndef WIN32
1995                 const char *tmpdir = getenv("TMPDIR");
1996
1997                 if (!tmpdir)
1998                         tmpdir = "/tmp";
1999 #else
2000                 char            tmpdir[MAXPGPATH];
2001                 int                     ret;
2002
2003                 ret = GetTempPath(MAXPGPATH, tmpdir);
2004                 if (ret == 0 || ret > MAXPGPATH)
2005                 {
2006                         psql_error("could not locate temporary directory: %s\n",
2007                                            !ret ? strerror(errno) : "");
2008                         return false;
2009                 }
2010
2011                 /*
2012                  * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
2013                  * current directory to the supplied path unless we use only
2014                  * backslashes, so we do that.
2015                  */
2016 #endif
2017 #ifndef WIN32
2018                 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
2019                                  "/", (int) getpid());
2020 #else
2021                 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
2022                            "" /* trailing separator already present */ , (int) getpid());
2023 #endif
2024
2025                 fname = (const char *) fnametmp;
2026
2027                 fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
2028                 if (fd != -1)
2029                         stream = fdopen(fd, "w");
2030
2031                 if (fd == -1 || !stream)
2032                 {
2033                         psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
2034                         error = true;
2035                 }
2036                 else
2037                 {
2038                         unsigned int ql = query_buf->len;
2039
2040                         if (ql == 0 || query_buf->data[ql - 1] != '\n')
2041                         {
2042                                 appendPQExpBufferChar(query_buf, '\n');
2043                                 ql++;
2044                         }
2045
2046                         if (fwrite(query_buf->data, 1, ql, stream) != ql)
2047                         {
2048                                 psql_error("%s: %s\n", fname, strerror(errno));
2049
2050                                 if (fclose(stream) != 0)
2051                                         psql_error("%s: %s\n", fname, strerror(errno));
2052
2053                                 if (remove(fname) != 0)
2054                                         psql_error("%s: %s\n", fname, strerror(errno));
2055
2056                                 error = true;
2057                         }
2058                         else if (fclose(stream) != 0)
2059                         {
2060                                 psql_error("%s: %s\n", fname, strerror(errno));
2061                                 if (remove(fname) != 0)
2062                                         psql_error("%s: %s\n", fname, strerror(errno));
2063                                 error = true;
2064                         }
2065                 }
2066         }
2067
2068         if (!error && stat(fname, &before) != 0)
2069         {
2070                 psql_error("%s: %s\n", fname, strerror(errno));
2071                 error = true;
2072         }
2073
2074         /* call editor */
2075         if (!error)
2076                 error = !editFile(fname, lineno);
2077
2078         if (!error && stat(fname, &after) != 0)
2079         {
2080                 psql_error("%s: %s\n", fname, strerror(errno));
2081                 error = true;
2082         }
2083
2084         if (!error && before.st_mtime != after.st_mtime)
2085         {
2086                 stream = fopen(fname, PG_BINARY_R);
2087                 if (!stream)
2088                 {
2089                         psql_error("%s: %s\n", fname, strerror(errno));
2090                         error = true;
2091                 }
2092                 else
2093                 {
2094                         /* read file back into query_buf */
2095                         char            line[1024];
2096
2097                         resetPQExpBuffer(query_buf);
2098                         while (fgets(line, sizeof(line), stream) != NULL)
2099                                 appendPQExpBufferStr(query_buf, line);
2100
2101                         if (ferror(stream))
2102                         {
2103                                 psql_error("%s: %s\n", fname, strerror(errno));
2104                                 error = true;
2105                         }
2106                         else if (edited)
2107                         {
2108                                 *edited = true;
2109                         }
2110
2111                         fclose(stream);
2112                 }
2113         }
2114
2115         /* remove temp file */
2116         if (!filename_arg)
2117         {
2118                 if (remove(fname) == -1)
2119                 {
2120                         psql_error("%s: %s\n", fname, strerror(errno));
2121                         error = true;
2122                 }
2123         }
2124
2125         return !error;
2126 }
2127
2128
2129
2130 /*
2131  * process_file
2132  *
2133  * Reads commands from filename and passes them to the main processing loop.
2134  * Handler for \i and \ir, but can be used for other things as well.  Returns
2135  * MainLoop() error code.
2136  *
2137  * If use_relative_path is true and filename is not an absolute path, then open
2138  * the file from where the currently processed file (if any) is located.
2139  */
2140 int
2141 process_file(char *filename, bool single_txn, bool use_relative_path)
2142 {
2143         FILE       *fd;
2144         int                     result;
2145         char       *oldfilename;
2146         char            relpath[MAXPGPATH];
2147         PGresult   *res;
2148
2149         if (!filename)
2150         {
2151                 fd = stdin;
2152                 filename = NULL;
2153         }
2154         else if (strcmp(filename, "-") != 0)
2155         {
2156                 canonicalize_path(filename);
2157
2158                 /*
2159                  * If we were asked to resolve the pathname relative to the location
2160                  * of the currently executing script, and there is one, and this is a
2161                  * relative pathname, then prepend all but the last pathname component
2162                  * of the current script to this pathname.
2163                  */
2164                 if (use_relative_path && pset.inputfile &&
2165                         !is_absolute_path(filename) && !has_drive_prefix(filename))
2166                 {
2167                         strlcpy(relpath, pset.inputfile, sizeof(relpath));
2168                         get_parent_directory(relpath);
2169                         join_path_components(relpath, relpath, filename);
2170                         canonicalize_path(relpath);
2171
2172                         filename = relpath;
2173                 }
2174
2175                 fd = fopen(filename, PG_BINARY_R);
2176
2177                 if (!fd)
2178                 {
2179                         psql_error("%s: %s\n", filename, strerror(errno));
2180                         return EXIT_FAILURE;
2181                 }
2182         }
2183         else
2184         {
2185                 fd = stdin;
2186                 filename = "<stdin>";   /* for future error messages */
2187         }
2188
2189         oldfilename = pset.inputfile;
2190         pset.inputfile = filename;
2191
2192         if (single_txn)
2193         {
2194                 if ((res = PSQLexec("BEGIN")) == NULL)
2195                 {
2196                         if (pset.on_error_stop)
2197                         {
2198                                 result = EXIT_USER;
2199                                 goto error;
2200                         }
2201                 }
2202                 else
2203                         PQclear(res);
2204         }
2205
2206         result = MainLoop(fd);
2207
2208         if (single_txn)
2209         {
2210                 if ((res = PSQLexec("COMMIT")) == NULL)
2211                 {
2212                         if (pset.on_error_stop)
2213                         {
2214                                 result = EXIT_USER;
2215                                 goto error;
2216                         }
2217                 }
2218                 else
2219                         PQclear(res);
2220         }
2221
2222 error:
2223         if (fd != stdin)
2224                 fclose(fd);
2225
2226         pset.inputfile = oldfilename;
2227         return result;
2228 }
2229
2230
2231
2232 static const char *
2233 _align2string(enum printFormat in)
2234 {
2235         switch (in)
2236         {
2237                 case PRINT_NOTHING:
2238                         return "nothing";
2239                         break;
2240                 case PRINT_UNALIGNED:
2241                         return "unaligned";
2242                         break;
2243                 case PRINT_ALIGNED:
2244                         return "aligned";
2245                         break;
2246                 case PRINT_WRAPPED:
2247                         return "wrapped";
2248                         break;
2249                 case PRINT_HTML:
2250                         return "html";
2251                         break;
2252                 case PRINT_ASCIIDOC:
2253                         return "asciidoc";
2254                         break;
2255                 case PRINT_LATEX:
2256                         return "latex";
2257                         break;
2258                 case PRINT_LATEX_LONGTABLE:
2259                         return "latex-longtable";
2260                         break;
2261                 case PRINT_TROFF_MS:
2262                         return "troff-ms";
2263                         break;
2264         }
2265         return "unknown";
2266 }
2267
2268 /*
2269  * Parse entered unicode linestyle. Returns true, when entered string is
2270  * known linestyle: single, double else returns false.
2271  */
2272 static bool
2273 set_unicode_line_style(printQueryOpt *popt, const char *value, size_t vallen,
2274                                            unicode_linestyle *linestyle)
2275 {
2276         if (pg_strncasecmp("single", value, vallen) == 0)
2277                 *linestyle = UNICODE_LINESTYLE_SINGLE;
2278         else if (pg_strncasecmp("double", value, vallen) == 0)
2279                 *linestyle = UNICODE_LINESTYLE_DOUBLE;
2280         else
2281                 return false;
2282
2283         /* input is ok, generate new unicode style */
2284         refresh_utf8format(&(popt->topt));
2285
2286         return true;
2287 }
2288
2289 static const char *
2290 _unicode_linestyle2string(int linestyle)
2291 {
2292         switch (linestyle)
2293         {
2294                 case UNICODE_LINESTYLE_SINGLE:
2295                         return "single";
2296                         break;
2297                 case UNICODE_LINESTYLE_DOUBLE:
2298                         return "double";
2299                         break;
2300         }
2301         return "unknown";
2302 }
2303
2304 /*
2305  * do_pset
2306  *
2307  */
2308 bool
2309 do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
2310 {
2311         size_t          vallen = 0;
2312
2313         Assert(param != NULL);
2314
2315         if (value)
2316                 vallen = strlen(value);
2317
2318         /* set format */
2319         if (strcmp(param, "format") == 0)
2320         {
2321                 if (!value)
2322                         ;
2323                 else if (pg_strncasecmp("unaligned", value, vallen) == 0)
2324                         popt->topt.format = PRINT_UNALIGNED;
2325                 else if (pg_strncasecmp("aligned", value, vallen) == 0)
2326                         popt->topt.format = PRINT_ALIGNED;
2327                 else if (pg_strncasecmp("wrapped", value, vallen) == 0)
2328                         popt->topt.format = PRINT_WRAPPED;
2329                 else if (pg_strncasecmp("html", value, vallen) == 0)
2330                         popt->topt.format = PRINT_HTML;
2331                 else if (pg_strncasecmp("asciidoc", value, vallen) == 0)
2332                         popt->topt.format = PRINT_ASCIIDOC;
2333                 else if (pg_strncasecmp("latex", value, vallen) == 0)
2334                         popt->topt.format = PRINT_LATEX;
2335                 else if (pg_strncasecmp("latex-longtable", value, vallen) == 0)
2336                         popt->topt.format = PRINT_LATEX_LONGTABLE;
2337                 else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
2338                         popt->topt.format = PRINT_TROFF_MS;
2339                 else
2340                 {
2341                         psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, asciidoc, latex, troff-ms\n");
2342                         return false;
2343                 }
2344
2345         }
2346
2347         /* set table line style */
2348         else if (strcmp(param, "linestyle") == 0)
2349         {
2350                 if (!value)
2351                         ;
2352                 else if (pg_strncasecmp("ascii", value, vallen) == 0)
2353                         popt->topt.line_style = &pg_asciiformat;
2354                 else if (pg_strncasecmp("old-ascii", value, vallen) == 0)
2355                         popt->topt.line_style = &pg_asciiformat_old;
2356                 else if (pg_strncasecmp("unicode", value, vallen) == 0)
2357                         popt->topt.line_style = &pg_utf8format;
2358                 else
2359                 {
2360                         psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode\n");
2361                         return false;
2362                 }
2363
2364         }
2365
2366         /* set unicode border line style */
2367         else if (strcmp(param, "unicode_border_linestyle") == 0)
2368         {
2369                 if (!value)
2370                         ;
2371                 else if (!set_unicode_line_style(popt, value, vallen,
2372                                                                                  &popt->topt.unicode_border_linestyle))
2373                 {
2374                         psql_error("\\pset: allowed unicode border linestyle are single, double\n");
2375                         return false;
2376                 }
2377         }
2378
2379         /* set unicode column line style */
2380         else if (strcmp(param, "unicode_column_linestyle") == 0)
2381         {
2382                 if (!value)
2383                         ;
2384                 else if (!set_unicode_line_style(popt, value, vallen,
2385                                                                                  &popt->topt.unicode_column_linestyle))
2386                 {
2387                         psql_error("\\pset: allowed unicode column linestyle are single, double\n");
2388                         return false;
2389                 }
2390         }
2391
2392         /* set unicode header line style */
2393         else if (strcmp(param, "unicode_header_linestyle") == 0)
2394         {
2395                 if (!value)
2396                         ;
2397                 else if (!set_unicode_line_style(popt, value, vallen,
2398                                                                                  &popt->topt.unicode_header_linestyle))
2399                 {
2400                         psql_error("\\pset: allowed unicode header linestyle are single, double\n");
2401                         return false;
2402                 }
2403         }
2404
2405         /* set border style/width */
2406         else if (strcmp(param, "border") == 0)
2407         {
2408                 if (value)
2409                         popt->topt.border = atoi(value);
2410
2411         }
2412
2413         /* set expanded/vertical mode */
2414         else if (strcmp(param, "x") == 0 ||
2415                          strcmp(param, "expanded") == 0 ||
2416                          strcmp(param, "vertical") == 0)
2417         {
2418                 if (value && pg_strcasecmp(value, "auto") == 0)
2419                         popt->topt.expanded = 2;
2420                 else if (value)
2421                         popt->topt.expanded = ParseVariableBool(value, param);
2422                 else
2423                         popt->topt.expanded = !popt->topt.expanded;
2424         }
2425
2426         /* locale-aware numeric output */
2427         else if (strcmp(param, "numericlocale") == 0)
2428         {
2429                 if (value)
2430                         popt->topt.numericLocale = ParseVariableBool(value, param);
2431                 else
2432                         popt->topt.numericLocale = !popt->topt.numericLocale;
2433         }
2434
2435         /* null display */
2436         else if (strcmp(param, "null") == 0)
2437         {
2438                 if (value)
2439                 {
2440                         free(popt->nullPrint);
2441                         popt->nullPrint = pg_strdup(value);
2442                 }
2443         }
2444
2445         /* field separator for unaligned text */
2446         else if (strcmp(param, "fieldsep") == 0)
2447         {
2448                 if (value)
2449                 {
2450                         free(popt->topt.fieldSep.separator);
2451                         popt->topt.fieldSep.separator = pg_strdup(value);
2452                         popt->topt.fieldSep.separator_zero = false;
2453                 }
2454         }
2455
2456         else if (strcmp(param, "fieldsep_zero") == 0)
2457         {
2458                 free(popt->topt.fieldSep.separator);
2459                 popt->topt.fieldSep.separator = NULL;
2460                 popt->topt.fieldSep.separator_zero = true;
2461         }
2462
2463         /* record separator for unaligned text */
2464         else if (strcmp(param, "recordsep") == 0)
2465         {
2466                 if (value)
2467                 {
2468                         free(popt->topt.recordSep.separator);
2469                         popt->topt.recordSep.separator = pg_strdup(value);
2470                         popt->topt.recordSep.separator_zero = false;
2471                 }
2472         }
2473
2474         else if (strcmp(param, "recordsep_zero") == 0)
2475         {
2476                 free(popt->topt.recordSep.separator);
2477                 popt->topt.recordSep.separator = NULL;
2478                 popt->topt.recordSep.separator_zero = true;
2479         }
2480
2481         /* toggle between full and tuples-only format */
2482         else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
2483         {
2484                 if (value)
2485                         popt->topt.tuples_only = ParseVariableBool(value, param);
2486                 else
2487                         popt->topt.tuples_only = !popt->topt.tuples_only;
2488         }
2489
2490         /* set title override */
2491         else if (strcmp(param, "title") == 0)
2492         {
2493                 free(popt->title);
2494                 if (!value)
2495                         popt->title = NULL;
2496                 else
2497                         popt->title = pg_strdup(value);
2498         }
2499
2500         /* set HTML table tag options */
2501         else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
2502         {
2503                 free(popt->topt.tableAttr);
2504                 if (!value)
2505                         popt->topt.tableAttr = NULL;
2506                 else
2507                         popt->topt.tableAttr = pg_strdup(value);
2508         }
2509
2510         /* toggle use of pager */
2511         else if (strcmp(param, "pager") == 0)
2512         {
2513                 if (value && pg_strcasecmp(value, "always") == 0)
2514                         popt->topt.pager = 2;
2515                 else if (value)
2516                 {
2517                         if (ParseVariableBool(value, param))
2518                                 popt->topt.pager = 1;
2519                         else
2520                                 popt->topt.pager = 0;
2521                 }
2522                 else if (popt->topt.pager == 1)
2523                         popt->topt.pager = 0;
2524                 else
2525                         popt->topt.pager = 1;
2526         }
2527
2528         /* set minimum lines for pager use */
2529         else if (strcmp(param, "pager_min_lines") == 0)
2530         {
2531                 if (value)
2532                         popt->topt.pager_min_lines = atoi(value);
2533         }
2534
2535         /* disable "(x rows)" footer */
2536         else if (strcmp(param, "footer") == 0)
2537         {
2538                 if (value)
2539                         popt->topt.default_footer = ParseVariableBool(value, param);
2540                 else
2541                         popt->topt.default_footer = !popt->topt.default_footer;
2542         }
2543
2544         /* set border style/width */
2545         else if (strcmp(param, "columns") == 0)
2546         {
2547                 if (value)
2548                         popt->topt.columns = atoi(value);
2549         }
2550         else
2551         {
2552                 psql_error("\\pset: unknown option: %s\n", param);
2553                 return false;
2554         }
2555
2556         if (!quiet)
2557                 printPsetInfo(param, &pset.popt);
2558
2559         return true;
2560 }
2561
2562
2563 static bool
2564 printPsetInfo(const char *param, struct printQueryOpt *popt)
2565 {
2566         Assert(param != NULL);
2567
2568         /* show border style/width */
2569         if (strcmp(param, "border") == 0)
2570                 printf(_("Border style is %d.\n"), popt->topt.border);
2571
2572         /* show the target width for the wrapped format */
2573         else if (strcmp(param, "columns") == 0)
2574         {
2575                 if (!popt->topt.columns)
2576                         printf(_("Target width is unset.\n"));
2577                 else
2578                         printf(_("Target width is %d.\n"), popt->topt.columns);
2579         }
2580
2581         /* show expanded/vertical mode */
2582         else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
2583         {
2584                 if (popt->topt.expanded == 1)
2585                         printf(_("Expanded display is on.\n"));
2586                 else if (popt->topt.expanded == 2)
2587                         printf(_("Expanded display is used automatically.\n"));
2588                 else
2589                         printf(_("Expanded display is off.\n"));
2590         }
2591
2592         /* show field separator for unaligned text */
2593         else if (strcmp(param, "fieldsep") == 0)
2594         {
2595                 if (popt->topt.fieldSep.separator_zero)
2596                         printf(_("Field separator is zero byte.\n"));
2597                 else
2598                         printf(_("Field separator is \"%s\".\n"),
2599                                    popt->topt.fieldSep.separator);
2600         }
2601
2602         else if (strcmp(param, "fieldsep_zero") == 0)
2603         {
2604                 printf(_("Field separator is zero byte.\n"));
2605         }
2606
2607         /* show disable "(x rows)" footer */
2608         else if (strcmp(param, "footer") == 0)
2609         {
2610                 if (popt->topt.default_footer)
2611                         printf(_("Default footer is on.\n"));
2612                 else
2613                         printf(_("Default footer is off.\n"));
2614         }
2615
2616         /* show format */
2617         else if (strcmp(param, "format") == 0)
2618         {
2619                 printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
2620         }
2621
2622         /* show table line style */
2623         else if (strcmp(param, "linestyle") == 0)
2624         {
2625                 printf(_("Line style is %s.\n"),
2626                            get_line_style(&popt->topt)->name);
2627         }
2628
2629         /* show null display */
2630         else if (strcmp(param, "null") == 0)
2631         {
2632                 printf(_("Null display is \"%s\".\n"),
2633                            popt->nullPrint ? popt->nullPrint : "");
2634         }
2635
2636         /* show locale-aware numeric output */
2637         else if (strcmp(param, "numericlocale") == 0)
2638         {
2639                 if (popt->topt.numericLocale)
2640                         printf(_("Locale-adjusted numeric output is on.\n"));
2641                 else
2642                         printf(_("Locale-adjusted numeric output is off.\n"));
2643         }
2644
2645         /* show toggle use of pager */
2646         else if (strcmp(param, "pager") == 0)
2647         {
2648                 if (popt->topt.pager == 1)
2649                         printf(_("Pager is used for long output.\n"));
2650                 else if (popt->topt.pager == 2)
2651                         printf(_("Pager is always used.\n"));
2652                 else
2653                         printf(_("Pager usage is off.\n"));
2654         }
2655
2656         /* show minimum lines for pager use */
2657         else if (strcmp(param, "pager_min_lines") == 0)
2658         {
2659                 printf(_("Pager won't be used for less than %d lines\n"),
2660                            popt->topt.pager_min_lines);
2661         }
2662
2663         /* show record separator for unaligned text */
2664         else if (strcmp(param, "recordsep") == 0)
2665         {
2666                 if (popt->topt.recordSep.separator_zero)
2667                         printf(_("Record separator is zero byte.\n"));
2668                 else if (strcmp(popt->topt.recordSep.separator, "\n") == 0)
2669                         printf(_("Record separator is <newline>.\n"));
2670                 else
2671                         printf(_("Record separator is \"%s\".\n"),
2672                                    popt->topt.recordSep.separator);
2673         }
2674
2675         else if (strcmp(param, "recordsep_zero") == 0)
2676         {
2677                 printf(_("Record separator is zero byte.\n"));
2678         }
2679
2680         /* show HTML table tag options */
2681         else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
2682         {
2683                 if (popt->topt.tableAttr)
2684                         printf(_("Table attributes are \"%s\".\n"),
2685                                    popt->topt.tableAttr);
2686                 else
2687                         printf(_("Table attributes unset.\n"));
2688         }
2689
2690         /* show title override */
2691         else if (strcmp(param, "title") == 0)
2692         {
2693                 if (popt->title)
2694                         printf(_("Title is \"%s\".\n"), popt->title);
2695                 else
2696                         printf(_("Title is unset.\n"));
2697         }
2698
2699         /* show toggle between full and tuples-only format */
2700         else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
2701         {
2702                 if (popt->topt.tuples_only)
2703                         printf(_("Tuples only is on.\n"));
2704                 else
2705                         printf(_("Tuples only is off.\n"));
2706         }
2707
2708         /* unicode style formatting */
2709         else if (strcmp(param, "unicode_border_linestyle") == 0)
2710         {
2711                 printf(_("Unicode border linestyle is \"%s\".\n"),
2712                                 _unicode_linestyle2string(popt->topt.unicode_border_linestyle));
2713         }
2714
2715         else if (strcmp(param, "unicode_column_linestyle") == 0)
2716         {
2717                 printf(_("Unicode column linestyle is \"%s\".\n"),
2718                                 _unicode_linestyle2string(popt->topt.unicode_column_linestyle));
2719         }
2720
2721         else if (strcmp(param, "unicode_header_linestyle") == 0)
2722         {
2723                 printf(_("Unicode border linestyle is \"%s\".\n"),
2724                                 _unicode_linestyle2string(popt->topt.unicode_header_linestyle));
2725         }
2726
2727         else
2728         {
2729                 psql_error("\\pset: unknown option: %s\n", param);
2730                 return false;
2731         }
2732
2733         return true;
2734 }
2735
2736
2737 static const char *
2738 pset_bool_string(bool val)
2739 {
2740         return val ? "on" : "off";
2741 }
2742
2743
2744 static char *
2745 pset_quoted_string(const char *str)
2746 {
2747         char       *ret = pg_malloc(strlen(str) * 2 + 3);
2748         char       *r = ret;
2749
2750         *r++ = '\'';
2751
2752         for (; *str; str++)
2753         {
2754                 if (*str == '\n')
2755                 {
2756                         *r++ = '\\';
2757                         *r++ = 'n';
2758                 }
2759                 else if (*str == '\'')
2760                 {
2761                         *r++ = '\\';
2762                         *r++ = '\'';
2763                 }
2764                 else
2765                         *r++ = *str;
2766         }
2767
2768         *r++ = '\'';
2769         *r = '\0';
2770
2771         return ret;
2772 }
2773
2774
2775 /*
2776  * Return a malloc'ed string for the \pset value.
2777  *
2778  * Note that for some string parameters, print.c distinguishes between unset
2779  * and empty string, but for others it doesn't.  This function should produce
2780  * output that produces the correct setting when fed back into \pset.
2781  */
2782 static char *
2783 pset_value_string(const char *param, struct printQueryOpt *popt)
2784 {
2785         Assert(param != NULL);
2786
2787         if (strcmp(param, "border") == 0)
2788                 return psprintf("%d", popt->topt.border);
2789         else if (strcmp(param, "columns") == 0)
2790                 return psprintf("%d", popt->topt.columns);
2791         else if (strcmp(param, "expanded") == 0)
2792                 return pstrdup(popt->topt.expanded == 2
2793                                            ? "auto"
2794                                            : pset_bool_string(popt->topt.expanded));
2795         else if (strcmp(param, "fieldsep") == 0)
2796                 return pset_quoted_string(popt->topt.fieldSep.separator
2797                                                                   ? popt->topt.fieldSep.separator
2798                                                                   : "");
2799         else if (strcmp(param, "fieldsep_zero") == 0)
2800                 return pstrdup(pset_bool_string(popt->topt.fieldSep.separator_zero));
2801         else if (strcmp(param, "footer") == 0)
2802                 return pstrdup(pset_bool_string(popt->topt.default_footer));
2803         else if (strcmp(param, "format") == 0)
2804                 return psprintf("%s", _align2string(popt->topt.format));
2805         else if (strcmp(param, "linestyle") == 0)
2806                 return psprintf("%s", get_line_style(&popt->topt)->name);
2807         else if (strcmp(param, "null") == 0)
2808                 return pset_quoted_string(popt->nullPrint
2809                                                                   ? popt->nullPrint
2810                                                                   : "");
2811         else if (strcmp(param, "numericlocale") == 0)
2812                 return pstrdup(pset_bool_string(popt->topt.numericLocale));
2813         else if (strcmp(param, "pager") == 0)
2814                 return psprintf("%d", popt->topt.pager);
2815         else if (strcmp(param, "pager_min_lines") == 0)
2816                 return psprintf("%d", popt->topt.pager_min_lines);
2817         else if (strcmp(param, "recordsep") == 0)
2818                 return pset_quoted_string(popt->topt.recordSep.separator
2819                                                                   ? popt->topt.recordSep.separator
2820                                                                   : "");
2821         else if (strcmp(param, "recordsep_zero") == 0)
2822                 return pstrdup(pset_bool_string(popt->topt.recordSep.separator_zero));
2823         else if (strcmp(param, "tableattr") == 0)
2824                 return popt->topt.tableAttr ? pset_quoted_string(popt->topt.tableAttr) : pstrdup("");
2825         else if (strcmp(param, "title") == 0)
2826                 return popt->title ? pset_quoted_string(popt->title) : pstrdup("");
2827         else if (strcmp(param, "tuples_only") == 0)
2828                 return pstrdup(pset_bool_string(popt->topt.tuples_only));
2829         else if (strcmp(param, "unicode_border_linestyle") == 0)
2830                 return pstrdup(_unicode_linestyle2string(popt->topt.unicode_border_linestyle));
2831         else if (strcmp(param, "unicode_column_linestyle") == 0)
2832                 return pstrdup(_unicode_linestyle2string(popt->topt.unicode_column_linestyle));
2833         else if (strcmp(param, "unicode_header_linestyle") == 0)
2834                 return pstrdup(_unicode_linestyle2string(popt->topt.unicode_header_linestyle));
2835         else
2836                 return pstrdup("ERROR");
2837 }
2838
2839
2840
2841 #ifndef WIN32
2842 #define DEFAULT_SHELL "/bin/sh"
2843 #else
2844 /*
2845  *      CMD.EXE is in different places in different Win32 releases so we
2846  *      have to rely on the path to find it.
2847  */
2848 #define DEFAULT_SHELL "cmd.exe"
2849 #endif
2850
2851 static bool
2852 do_shell(const char *command)
2853 {
2854         int                     result;
2855
2856         if (!command)
2857         {
2858                 char       *sys;
2859                 const char *shellName;
2860
2861                 shellName = getenv("SHELL");
2862 #ifdef WIN32
2863                 if (shellName == NULL)
2864                         shellName = getenv("COMSPEC");
2865 #endif
2866                 if (shellName == NULL)
2867                         shellName = DEFAULT_SHELL;
2868
2869                 /* See EDITOR handling comment for an explanation */
2870 #ifndef WIN32
2871                 sys = psprintf("exec %s", shellName);
2872 #else
2873                 sys = psprintf("\"%s\"", shellName);
2874 #endif
2875                 result = system(sys);
2876                 free(sys);
2877         }
2878         else
2879                 result = system(command);
2880
2881         if (result == 127 || result == -1)
2882         {
2883                 psql_error("\\!: failed\n");
2884                 return false;
2885         }
2886         return true;
2887 }
2888
2889 /*
2890  * do_watch -- handler for \watch
2891  *
2892  * We break this out of exec_command to avoid having to plaster "volatile"
2893  * onto a bunch of exec_command's variables to silence stupider compilers.
2894  */
2895 static bool
2896 do_watch(PQExpBuffer query_buf, long sleep)
2897 {
2898         printQueryOpt myopt = pset.popt;
2899         char            title[50];
2900
2901         if (!query_buf || query_buf->len <= 0)
2902         {
2903                 psql_error(_("\\watch cannot be used with an empty query\n"));
2904                 return false;
2905         }
2906
2907         /*
2908          * Set up rendering options, in particular, disable the pager, because
2909          * nobody wants to be prompted while watching the output of 'watch'.
2910          */
2911         myopt.topt.pager = 0;
2912
2913         for (;;)
2914         {
2915                 int     res;
2916                 time_t          timer;
2917                 long            i;
2918
2919                 /*
2920                  * Prepare title for output.  XXX would it be better to use the time
2921                  * of completion of the command?
2922                  */
2923                 timer = time(NULL);
2924                 snprintf(title, sizeof(title), _("Watch every %lds\t%s"),
2925                                  sleep, asctime(localtime(&timer)));
2926                 myopt.title = title;
2927
2928                 /* Run the query and print out the results */
2929                 res = PSQLexecWatch(query_buf->data, &myopt);
2930
2931                 /*
2932                  * PSQLexecWatch handles the case where we can no longer
2933                  * repeat the query, and returns 0 or -1.
2934                  */
2935                 if (res == 0)
2936                         break;
2937                 if (res == -1)
2938                         return false;
2939
2940                 /*
2941                  * Set up cancellation of 'watch' via SIGINT.  We redo this each time
2942                  * through the loop since it's conceivable something inside
2943                  * PSQLexecWatch could change sigint_interrupt_jmp.
2944                  */
2945                 if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
2946                         break;
2947
2948                 /*
2949                  * Enable 'watch' cancellations and wait a while before running the
2950                  * query again.  Break the sleep into short intervals since pg_usleep
2951                  * isn't interruptible on some platforms.
2952                  */
2953                 sigint_interrupt_enabled = true;
2954                 for (i = 0; i < sleep; i++)
2955                 {
2956                         pg_usleep(1000000L);
2957                         if (cancel_pressed)
2958                                 break;
2959                 }
2960                 sigint_interrupt_enabled = false;
2961         }
2962
2963         return true;
2964 }
2965
2966 /*
2967  * a little code borrowed from PSQLexec() to manage ECHO_HIDDEN output.
2968  * returns true unless we have ECHO_HIDDEN_NOEXEC.
2969  */
2970 static bool
2971 lookup_function_echo_hidden(char * query)
2972 {
2973         if (pset.echo_hidden != PSQL_ECHO_HIDDEN_OFF)
2974         {
2975                 printf(_("********* QUERY **********\n"
2976                                  "%s\n"
2977                                  "**************************\n\n"), query);
2978                 fflush(stdout);
2979                 if (pset.logfile)
2980                 {
2981                         fprintf(pset.logfile,
2982                                         _("********* QUERY **********\n"
2983                                           "%s\n"
2984                                           "**************************\n\n"), query);
2985                         fflush(pset.logfile);
2986                 }
2987
2988                 if (pset.echo_hidden == PSQL_ECHO_HIDDEN_NOEXEC)
2989                         return false;
2990         }
2991         return true;
2992 }
2993
2994 /*
2995  * This function takes a function description, e.g. "x" or "x(int)", and
2996  * issues a query on the given connection to retrieve the function's OID
2997  * using a cast to regproc or regprocedure (as appropriate). The result,
2998  * if there is one, is returned at *foid.  Note that we'll fail if the
2999  * function doesn't exist OR if there are multiple matching candidates
3000  * OR if there's something syntactically wrong with the function description;
3001  * unfortunately it can be hard to tell the difference.
3002  */
3003 static bool
3004 lookup_function_oid(const char *desc, Oid *foid)
3005 {
3006         bool            result = true;
3007         PQExpBuffer query;
3008         PGresult   *res;
3009
3010         query = createPQExpBuffer();
3011         appendPQExpBufferStr(query, "SELECT ");
3012         appendStringLiteralConn(query, desc, pset.db);
3013         appendPQExpBuffer(query, "::pg_catalog.%s::pg_catalog.oid",
3014                                           strchr(desc, '(') ? "regprocedure" : "regproc");
3015         if (!lookup_function_echo_hidden(query->data))
3016         {
3017                 destroyPQExpBuffer(query);
3018                 return false;
3019         }
3020         res = PQexec(pset.db, query->data);
3021         if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
3022                 *foid = atooid(PQgetvalue(res, 0, 0));
3023         else
3024         {
3025                 minimal_error_message(res);
3026                 result = false;
3027         }
3028
3029         PQclear(res);
3030         destroyPQExpBuffer(query);
3031
3032         return result;
3033 }
3034
3035 /*
3036  * Fetches the "CREATE OR REPLACE FUNCTION ..." command that describes the
3037  * function with the given OID.  If successful, the result is stored in buf.
3038  */
3039 static bool
3040 get_create_function_cmd(Oid oid, PQExpBuffer buf)
3041 {
3042         bool            result = true;
3043         PQExpBuffer query;
3044         PGresult   *res;
3045
3046         query = createPQExpBuffer();
3047         printfPQExpBuffer(query, "SELECT pg_catalog.pg_get_functiondef(%u)", oid);
3048
3049         if (!lookup_function_echo_hidden(query->data))
3050         {
3051                 destroyPQExpBuffer(query);
3052                 return false;
3053         }
3054         res = PQexec(pset.db, query->data);
3055         if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
3056         {
3057                 resetPQExpBuffer(buf);
3058                 appendPQExpBufferStr(buf, PQgetvalue(res, 0, 0));
3059         }
3060         else
3061         {
3062                 minimal_error_message(res);
3063                 result = false;
3064         }
3065
3066         PQclear(res);
3067         destroyPQExpBuffer(query);
3068
3069         return result;
3070 }
3071
3072 /*
3073  * If the given argument of \ef ends with a line number, delete the line
3074  * number from the argument string and return it as an integer.  (We need
3075  * this kluge because we're too lazy to parse \ef's function name argument
3076  * carefully --- we just slop it up in OT_WHOLE_LINE mode.)
3077  *
3078  * Returns -1 if no line number is present, 0 on error, or a positive value
3079  * on success.
3080  */
3081 static int
3082 strip_lineno_from_funcdesc(char *func)
3083 {
3084         char       *c;
3085         int                     lineno;
3086
3087         if (!func || func[0] == '\0')
3088                 return -1;
3089
3090         c = func + strlen(func) - 1;
3091
3092         /*
3093          * This business of parsing backwards is dangerous as can be in a
3094          * multibyte environment: there is no reason to believe that we are
3095          * looking at the first byte of a character, nor are we necessarily
3096          * working in a "safe" encoding.  Fortunately the bitpatterns we are
3097          * looking for are unlikely to occur as non-first bytes, but beware of
3098          * trying to expand the set of cases that can be recognized.  We must
3099          * guard the <ctype.h> macros by using isascii() first, too.
3100          */
3101
3102         /* skip trailing whitespace */
3103         while (c > func && isascii((unsigned char) *c) && isspace((unsigned char) *c))
3104                 c--;
3105
3106         /* must have a digit as last non-space char */
3107         if (c == func || !isascii((unsigned char) *c) || !isdigit((unsigned char) *c))
3108                 return -1;
3109
3110         /* find start of digit string */
3111         while (c > func && isascii((unsigned char) *c) && isdigit((unsigned char) *c))
3112                 c--;
3113
3114         /* digits must be separated from func name by space or closing paren */
3115         /* notice also that we are not allowing an empty func name ... */
3116         if (c == func || !isascii((unsigned char) *c) ||
3117                 !(isspace((unsigned char) *c) || *c == ')'))
3118                 return -1;
3119
3120         /* parse digit string */
3121         c++;
3122         lineno = atoi(c);
3123         if (lineno < 1)
3124         {
3125                 psql_error("invalid line number: %s\n", c);
3126                 return 0;
3127         }
3128
3129         /* strip digit string from func */
3130         *c = '\0';
3131
3132         return lineno;
3133 }
3134
3135 /*
3136  * Report just the primary error; this is to avoid cluttering the output
3137  * with, for instance, a redisplay of the internally generated query
3138  */
3139 static void
3140 minimal_error_message(PGresult *res)
3141 {
3142         PQExpBuffer msg;
3143         const char *fld;
3144
3145         msg = createPQExpBuffer();
3146
3147         fld = PQresultErrorField(res, PG_DIAG_SEVERITY);
3148         if (fld)
3149                 printfPQExpBuffer(msg, "%s:  ", fld);
3150         else
3151                 printfPQExpBuffer(msg, "ERROR:  ");
3152         fld = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
3153         if (fld)
3154                 appendPQExpBufferStr(msg, fld);
3155         else
3156                 appendPQExpBufferStr(msg, "(not available)");
3157         appendPQExpBufferStr(msg, "\n");
3158
3159         psql_error("%s", msg->data);
3160
3161         destroyPQExpBuffer(msg);
3162 }