LCOV - code coverage report
Current view: top level - src/bin/psql - command.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 865 1878 46.1 %
Date: 2017-09-29 13:40:31 Functions: 71 90 78.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * psql - the PostgreSQL interactive terminal
       3             :  *
       4             :  * Copyright (c) 2000-2017, PostgreSQL Global Development Group
       5             :  *
       6             :  * src/bin/psql/command.c
       7             :  */
       8             : #include "postgres_fe.h"
       9             : #include "command.h"
      10             : 
      11             : #include <ctype.h>
      12             : #include <time.h>
      13             : #include <pwd.h>
      14             : #ifndef WIN32
      15             : #include <sys/stat.h>         /* for stat() */
      16             : #include <fcntl.h>                /* open() flags */
      17             : #include <unistd.h>               /* for geteuid(), getpid(), stat() */
      18             : #else
      19             : #include <win32.h>
      20             : #include <io.h>
      21             : #include <fcntl.h>
      22             : #include <direct.h>
      23             : #include <sys/stat.h>         /* for stat() */
      24             : #endif
      25             : 
      26             : #include "catalog/pg_class.h"
      27             : #include "portability/instr_time.h"
      28             : 
      29             : #include "libpq-fe.h"
      30             : #include "pqexpbuffer.h"
      31             : #include "fe_utils/string_utils.h"
      32             : 
      33             : #include "common.h"
      34             : #include "copy.h"
      35             : #include "crosstabview.h"
      36             : #include "describe.h"
      37             : #include "help.h"
      38             : #include "input.h"
      39             : #include "large_obj.h"
      40             : #include "mainloop.h"
      41             : #include "fe_utils/print.h"
      42             : #include "psqlscanslash.h"
      43             : #include "settings.h"
      44             : #include "variables.h"
      45             : 
      46             : /*
      47             :  * Editable database object types.
      48             :  */
      49             : typedef enum EditableObjectType
      50             : {
      51             :     EditableFunction,
      52             :     EditableView
      53             : } EditableObjectType;
      54             : 
      55             : /* local function declarations */
      56             : static backslashResult exec_command(const char *cmd,
      57             :              PsqlScanState scan_state,
      58             :              ConditionalStack cstack,
      59             :              PQExpBuffer query_buf,
      60             :              PQExpBuffer previous_buf);
      61             : static backslashResult exec_command_a(PsqlScanState scan_state, bool active_branch);
      62             : static backslashResult exec_command_C(PsqlScanState scan_state, bool active_branch);
      63             : static backslashResult exec_command_connect(PsqlScanState scan_state, bool active_branch);
      64             : static backslashResult exec_command_cd(PsqlScanState scan_state, bool active_branch,
      65             :                 const char *cmd);
      66             : static backslashResult exec_command_conninfo(PsqlScanState scan_state, bool active_branch);
      67             : static backslashResult exec_command_copy(PsqlScanState scan_state, bool active_branch);
      68             : static backslashResult exec_command_copyright(PsqlScanState scan_state, bool active_branch);
      69             : static backslashResult exec_command_crosstabview(PsqlScanState scan_state, bool active_branch);
      70             : static backslashResult exec_command_d(PsqlScanState scan_state, bool active_branch,
      71             :                const char *cmd);
      72             : static backslashResult exec_command_edit(PsqlScanState scan_state, bool active_branch,
      73             :                   PQExpBuffer query_buf, PQExpBuffer previous_buf);
      74             : static backslashResult exec_command_ef(PsqlScanState scan_state, bool active_branch,
      75             :                 PQExpBuffer query_buf);
      76             : static backslashResult exec_command_ev(PsqlScanState scan_state, bool active_branch,
      77             :                 PQExpBuffer query_buf);
      78             : static backslashResult exec_command_echo(PsqlScanState scan_state, bool active_branch,
      79             :                   const char *cmd);
      80             : static backslashResult exec_command_elif(PsqlScanState scan_state, ConditionalStack cstack,
      81             :                   PQExpBuffer query_buf);
      82             : static backslashResult exec_command_else(PsqlScanState scan_state, ConditionalStack cstack,
      83             :                   PQExpBuffer query_buf);
      84             : static backslashResult exec_command_endif(PsqlScanState scan_state, ConditionalStack cstack,
      85             :                    PQExpBuffer query_buf);
      86             : static backslashResult exec_command_encoding(PsqlScanState scan_state, bool active_branch);
      87             : static backslashResult exec_command_errverbose(PsqlScanState scan_state, bool active_branch);
      88             : static backslashResult exec_command_f(PsqlScanState scan_state, bool active_branch);
      89             : static backslashResult exec_command_g(PsqlScanState scan_state, bool active_branch,
      90             :                const char *cmd);
      91             : static backslashResult exec_command_gexec(PsqlScanState scan_state, bool active_branch);
      92             : static backslashResult exec_command_gset(PsqlScanState scan_state, bool active_branch);
      93             : static backslashResult exec_command_help(PsqlScanState scan_state, bool active_branch);
      94             : static backslashResult exec_command_html(PsqlScanState scan_state, bool active_branch);
      95             : static backslashResult exec_command_include(PsqlScanState scan_state, bool active_branch,
      96             :                      const char *cmd);
      97             : static backslashResult exec_command_if(PsqlScanState scan_state, ConditionalStack cstack,
      98             :                 PQExpBuffer query_buf);
      99             : static backslashResult exec_command_list(PsqlScanState scan_state, bool active_branch,
     100             :                   const char *cmd);
     101             : static backslashResult exec_command_lo(PsqlScanState scan_state, bool active_branch,
     102             :                 const char *cmd);
     103             : static backslashResult exec_command_out(PsqlScanState scan_state, bool active_branch);
     104             : static backslashResult exec_command_print(PsqlScanState scan_state, bool active_branch,
     105             :                    PQExpBuffer query_buf, PQExpBuffer previous_buf);
     106             : static backslashResult exec_command_password(PsqlScanState scan_state, bool active_branch);
     107             : static backslashResult exec_command_prompt(PsqlScanState scan_state, bool active_branch,
     108             :                     const char *cmd);
     109             : static backslashResult exec_command_pset(PsqlScanState scan_state, bool active_branch);
     110             : static backslashResult exec_command_quit(PsqlScanState scan_state, bool active_branch);
     111             : static backslashResult exec_command_reset(PsqlScanState scan_state, bool active_branch,
     112             :                    PQExpBuffer query_buf);
     113             : static backslashResult exec_command_s(PsqlScanState scan_state, bool active_branch);
     114             : static backslashResult exec_command_set(PsqlScanState scan_state, bool active_branch);
     115             : static backslashResult exec_command_setenv(PsqlScanState scan_state, bool active_branch,
     116             :                     const char *cmd);
     117             : static backslashResult exec_command_sf(PsqlScanState scan_state, bool active_branch,
     118             :                 const char *cmd);
     119             : static backslashResult exec_command_sv(PsqlScanState scan_state, bool active_branch,
     120             :                 const char *cmd);
     121             : static backslashResult exec_command_t(PsqlScanState scan_state, bool active_branch);
     122             : static backslashResult exec_command_T(PsqlScanState scan_state, bool active_branch);
     123             : static backslashResult exec_command_timing(PsqlScanState scan_state, bool active_branch);
     124             : static backslashResult exec_command_unset(PsqlScanState scan_state, bool active_branch,
     125             :                    const char *cmd);
     126             : static backslashResult exec_command_write(PsqlScanState scan_state, bool active_branch,
     127             :                    const char *cmd,
     128             :                    PQExpBuffer query_buf, PQExpBuffer previous_buf);
     129             : static backslashResult exec_command_watch(PsqlScanState scan_state, bool active_branch,
     130             :                    PQExpBuffer query_buf, PQExpBuffer previous_buf);
     131             : static backslashResult exec_command_x(PsqlScanState scan_state, bool active_branch);
     132             : static backslashResult exec_command_z(PsqlScanState scan_state, bool active_branch);
     133             : static backslashResult exec_command_shell_escape(PsqlScanState scan_state, bool active_branch);
     134             : static backslashResult exec_command_slash_command_help(PsqlScanState scan_state, bool active_branch);
     135             : static char *read_connect_arg(PsqlScanState scan_state);
     136             : static PQExpBuffer gather_boolean_expression(PsqlScanState scan_state);
     137             : static bool is_true_boolean_expression(PsqlScanState scan_state, const char *name);
     138             : static void ignore_boolean_expression(PsqlScanState scan_state);
     139             : static void ignore_slash_options(PsqlScanState scan_state);
     140             : static void ignore_slash_filepipe(PsqlScanState scan_state);
     141             : static void ignore_slash_whole_line(PsqlScanState scan_state);
     142             : static bool is_branching_command(const char *cmd);
     143             : static void save_query_text_state(PsqlScanState scan_state, ConditionalStack cstack,
     144             :                       PQExpBuffer query_buf);
     145             : static void discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
     146             :                    PQExpBuffer query_buf);
     147             : static void copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf);
     148             : static bool do_connect(enum trivalue reuse_previous_specification,
     149             :            char *dbname, char *user, char *host, char *port);
     150             : static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
     151             :         int lineno, bool *edited);
     152             : static bool do_shell(const char *command);
     153             : static bool do_watch(PQExpBuffer query_buf, double sleep);
     154             : static bool lookup_object_oid(EditableObjectType obj_type, const char *desc,
     155             :                   Oid *obj_oid);
     156             : static bool get_create_object_cmd(EditableObjectType obj_type, Oid oid,
     157             :                       PQExpBuffer buf);
     158             : static int  strip_lineno_from_objdesc(char *obj);
     159             : static int  count_lines_in_buf(PQExpBuffer buf);
     160             : static void print_with_linenumbers(FILE *output, char *lines,
     161             :                        const char *header_keyword);
     162             : static void minimal_error_message(PGresult *res);
     163             : 
     164             : static void printSSLInfo(void);
     165             : static bool printPsetInfo(const char *param, struct printQueryOpt *popt);
     166             : static char *pset_value_string(const char *param, struct printQueryOpt *popt);
     167             : 
     168             : #ifdef WIN32
     169             : static void checkWin32Codepage(void);
     170             : #endif
     171             : 
     172             : 
     173             : 
     174             : /*----------
     175             :  * HandleSlashCmds:
     176             :  *
     177             :  * Handles all the different commands that start with '\'.
     178             :  * Ordinarily called by MainLoop().
     179             :  *
     180             :  * scan_state is a lexer working state that is set to continue scanning
     181             :  * just after the '\'.  The lexer is advanced past the command and all
     182             :  * arguments on return.
     183             :  *
     184             :  * cstack is the current \if stack state.  This will be examined, and
     185             :  * possibly modified by conditional commands.
     186             :  *
     187             :  * query_buf contains the query-so-far, which may be modified by
     188             :  * execution of the backslash command (for example, \r clears it).
     189             :  *
     190             :  * previous_buf contains the query most recently sent to the server
     191             :  * (empty if none yet).  This should not be modified here, but some
     192             :  * commands copy its content into query_buf.
     193             :  *
     194             :  * query_buf and previous_buf will be NULL when executing a "-c"
     195             :  * command-line option.
     196             :  *
     197             :  * Returns a status code indicating what action is desired, see command.h.
     198             :  *----------
     199             :  */
     200             : 
     201             : backslashResult
     202         785 : HandleSlashCmds(PsqlScanState scan_state,
     203             :                 ConditionalStack cstack,
     204             :                 PQExpBuffer query_buf,
     205             :                 PQExpBuffer previous_buf)
     206             : {
     207             :     backslashResult status;
     208             :     char       *cmd;
     209             :     char       *arg;
     210             : 
     211         785 :     Assert(scan_state != NULL);
     212         785 :     Assert(cstack != NULL);
     213             : 
     214             :     /* Parse off the command name */
     215         785 :     cmd = psql_scan_slash_command(scan_state);
     216             : 
     217             :     /* And try to execute it */
     218         785 :     status = exec_command(cmd, scan_state, cstack, query_buf, previous_buf);
     219             : 
     220         785 :     if (status == PSQL_CMD_UNKNOWN)
     221             :     {
     222           0 :         if (pset.cur_cmd_interactive)
     223           0 :             psql_error("Invalid command \\%s. Try \\? for help.\n", cmd);
     224             :         else
     225           0 :             psql_error("invalid command \\%s\n", cmd);
     226           0 :         status = PSQL_CMD_ERROR;
     227             :     }
     228             : 
     229         785 :     if (status != PSQL_CMD_ERROR)
     230             :     {
     231             :         /*
     232             :          * Eat any remaining arguments after a valid command.  We want to
     233             :          * suppress evaluation of backticks in this situation, so transiently
     234             :          * push an inactive conditional-stack entry.
     235             :          */
     236         773 :         bool        active_branch = conditional_active(cstack);
     237             : 
     238         773 :         conditional_stack_push(cstack, IFSTATE_IGNORED);
     239        1550 :         while ((arg = psql_scan_slash_option(scan_state,
     240             :                                              OT_NORMAL, NULL, false)))
     241             :         {
     242           4 :             if (active_branch)
     243           4 :                 psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
     244           4 :             free(arg);
     245             :         }
     246         773 :         conditional_stack_pop(cstack);
     247             :     }
     248             :     else
     249             :     {
     250             :         /* silently throw away rest of line after an erroneous command */
     251          24 :         while ((arg = psql_scan_slash_option(scan_state,
     252             :                                              OT_WHOLE_LINE, NULL, false)))
     253           0 :             free(arg);
     254             :     }
     255             : 
     256             :     /* if there is a trailing \\, swallow it */
     257         785 :     psql_scan_slash_command_end(scan_state);
     258             : 
     259         785 :     free(cmd);
     260             : 
     261             :     /* some commands write to queryFout, so make sure output is sent */
     262         785 :     fflush(pset.queryFout);
     263             : 
     264         785 :     return status;
     265             : }
     266             : 
     267             : 
     268             : /*
     269             :  * Subroutine to actually try to execute a backslash command.
     270             :  *
     271             :  * The typical "success" result code is PSQL_CMD_SKIP_LINE, although some
     272             :  * commands return something else.  Failure results are PSQL_CMD_ERROR,
     273             :  * unless PSQL_CMD_UNKNOWN is more appropriate.
     274             :  */
     275             : static backslashResult
     276         785 : exec_command(const char *cmd,
     277             :              PsqlScanState scan_state,
     278             :              ConditionalStack cstack,
     279             :              PQExpBuffer query_buf,
     280             :              PQExpBuffer previous_buf)
     281             : {
     282             :     backslashResult status;
     283         785 :     bool        active_branch = conditional_active(cstack);
     284             : 
     285             :     /*
     286             :      * In interactive mode, warn when we're ignoring a command within a false
     287             :      * \if-branch.  But we continue on, so as to parse and discard the right
     288             :      * amount of parameter text.  Each individual backslash command subroutine
     289             :      * is responsible for doing nothing after discarding appropriate
     290             :      * arguments, if !active_branch.
     291             :      */
     292         785 :     if (pset.cur_cmd_interactive && !active_branch &&
     293           0 :         !is_branching_command(cmd))
     294             :     {
     295           0 :         psql_error("\\%s command ignored; use \\endif or Ctrl-C to exit current \\if block\n",
     296             :                    cmd);
     297             :     }
     298             : 
     299         785 :     if (strcmp(cmd, "a") == 0)
     300           7 :         status = exec_command_a(scan_state, active_branch);
     301         778 :     else if (strcmp(cmd, "C") == 0)
     302           1 :         status = exec_command_C(scan_state, active_branch);
     303         777 :     else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
     304          34 :         status = exec_command_connect(scan_state, active_branch);
     305         743 :     else if (strcmp(cmd, "cd") == 0)
     306           1 :         status = exec_command_cd(scan_state, active_branch, cmd);
     307         742 :     else if (strcmp(cmd, "conninfo") == 0)
     308           1 :         status = exec_command_conninfo(scan_state, active_branch);
     309         741 :     else if (pg_strcasecmp(cmd, "copy") == 0)
     310          12 :         status = exec_command_copy(scan_state, active_branch);
     311         729 :     else if (strcmp(cmd, "copyright") == 0)
     312           1 :         status = exec_command_copyright(scan_state, active_branch);
     313         728 :     else if (strcmp(cmd, "crosstabview") == 0)
     314          22 :         status = exec_command_crosstabview(scan_state, active_branch);
     315         706 :     else if (cmd[0] == 'd')
     316         302 :         status = exec_command_d(scan_state, active_branch, cmd);
     317         404 :     else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
     318           1 :         status = exec_command_edit(scan_state, active_branch,
     319             :                                    query_buf, previous_buf);
     320         403 :     else if (strcmp(cmd, "ef") == 0)
     321           1 :         status = exec_command_ef(scan_state, active_branch, query_buf);
     322         402 :     else if (strcmp(cmd, "ev") == 0)
     323           1 :         status = exec_command_ev(scan_state, active_branch, query_buf);
     324         401 :     else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
     325          41 :         status = exec_command_echo(scan_state, active_branch, cmd);
     326         360 :     else if (strcmp(cmd, "elif") == 0)
     327           6 :         status = exec_command_elif(scan_state, cstack, query_buf);
     328         354 :     else if (strcmp(cmd, "else") == 0)
     329          18 :         status = exec_command_else(scan_state, cstack, query_buf);
     330         336 :     else if (strcmp(cmd, "endif") == 0)
     331          17 :         status = exec_command_endif(scan_state, cstack, query_buf);
     332         319 :     else if (strcmp(cmd, "encoding") == 0)
     333           1 :         status = exec_command_encoding(scan_state, active_branch);
     334         318 :     else if (strcmp(cmd, "errverbose") == 0)
     335           1 :         status = exec_command_errverbose(scan_state, active_branch);
     336         317 :     else if (strcmp(cmd, "f") == 0)
     337           0 :         status = exec_command_f(scan_state, active_branch);
     338         317 :     else if (strcmp(cmd, "g") == 0 || strcmp(cmd, "gx") == 0)
     339          14 :         status = exec_command_g(scan_state, active_branch, cmd);
     340         303 :     else if (strcmp(cmd, "gexec") == 0)
     341           3 :         status = exec_command_gexec(scan_state, active_branch);
     342         300 :     else if (strcmp(cmd, "gset") == 0)
     343          20 :         status = exec_command_gset(scan_state, active_branch);
     344         280 :     else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
     345           1 :         status = exec_command_help(scan_state, active_branch);
     346         279 :     else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
     347           0 :         status = exec_command_html(scan_state, active_branch);
     348         558 :     else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0 ||
     349         558 :              strcmp(cmd, "ir") == 0 || strcmp(cmd, "include_relative") == 0)
     350           0 :         status = exec_command_include(scan_state, active_branch, cmd);
     351         279 :     else if (strcmp(cmd, "if") == 0)
     352          16 :         status = exec_command_if(scan_state, cstack, query_buf);
     353         526 :     else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0 ||
     354         526 :              strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
     355           0 :         status = exec_command_list(scan_state, active_branch, cmd);
     356         263 :     else if (strncmp(cmd, "lo_", 3) == 0)
     357           6 :         status = exec_command_lo(scan_state, active_branch, cmd);
     358         257 :     else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
     359           1 :         status = exec_command_out(scan_state, active_branch);
     360         256 :     else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
     361           7 :         status = exec_command_print(scan_state, active_branch,
     362             :                                     query_buf, previous_buf);
     363         249 :     else if (strcmp(cmd, "password") == 0)
     364           1 :         status = exec_command_password(scan_state, active_branch);
     365         248 :     else if (strcmp(cmd, "prompt") == 0)
     366           1 :         status = exec_command_prompt(scan_state, active_branch, cmd);
     367         247 :     else if (strcmp(cmd, "pset") == 0)
     368         152 :         status = exec_command_pset(scan_state, active_branch);
     369          95 :     else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
     370           1 :         status = exec_command_quit(scan_state, active_branch);
     371          94 :     else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
     372           4 :         status = exec_command_reset(scan_state, active_branch, query_buf);
     373          90 :     else if (strcmp(cmd, "s") == 0)
     374           1 :         status = exec_command_s(scan_state, active_branch);
     375          89 :     else if (strcmp(cmd, "set") == 0)
     376          64 :         status = exec_command_set(scan_state, active_branch);
     377          25 :     else if (strcmp(cmd, "setenv") == 0)
     378           1 :         status = exec_command_setenv(scan_state, active_branch, cmd);
     379          24 :     else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
     380           1 :         status = exec_command_sf(scan_state, active_branch, cmd);
     381          23 :     else if (strcmp(cmd, "sv") == 0 || strcmp(cmd, "sv+") == 0)
     382           2 :         status = exec_command_sv(scan_state, active_branch, cmd);
     383          21 :     else if (strcmp(cmd, "t") == 0)
     384           7 :         status = exec_command_t(scan_state, active_branch);
     385          14 :     else if (strcmp(cmd, "T") == 0)
     386           1 :         status = exec_command_T(scan_state, active_branch);
     387          13 :     else if (strcmp(cmd, "timing") == 0)
     388           1 :         status = exec_command_timing(scan_state, active_branch);
     389          12 :     else if (strcmp(cmd, "unset") == 0)
     390           5 :         status = exec_command_unset(scan_state, active_branch, cmd);
     391           7 :     else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
     392           2 :         status = exec_command_write(scan_state, active_branch, cmd,
     393             :                                     query_buf, previous_buf);
     394           5 :     else if (strcmp(cmd, "watch") == 0)
     395           1 :         status = exec_command_watch(scan_state, active_branch,
     396             :                                     query_buf, previous_buf);
     397           4 :     else if (strcmp(cmd, "x") == 0)
     398           1 :         status = exec_command_x(scan_state, active_branch);
     399           3 :     else if (strcmp(cmd, "z") == 0)
     400           2 :         status = exec_command_z(scan_state, active_branch);
     401           1 :     else if (strcmp(cmd, "!") == 0)
     402           1 :         status = exec_command_shell_escape(scan_state, active_branch);
     403           0 :     else if (strcmp(cmd, "?") == 0)
     404           0 :         status = exec_command_slash_command_help(scan_state, active_branch);
     405             :     else
     406           0 :         status = PSQL_CMD_UNKNOWN;
     407             : 
     408             :     /*
     409             :      * All the commands that return PSQL_CMD_SEND want to execute previous_buf
     410             :      * if query_buf is empty.  For convenience we implement that here, not in
     411             :      * the individual command subroutines.
     412             :      */
     413         785 :     if (status == PSQL_CMD_SEND)
     414          56 :         copy_previous_query(query_buf, previous_buf);
     415             : 
     416         785 :     return status;
     417             : }
     418             : 
     419             : 
     420             : /*
     421             :  * \a -- toggle field alignment
     422             :  *
     423             :  * This makes little sense but we keep it around.
     424             :  */
     425             : static backslashResult
     426           7 : exec_command_a(PsqlScanState scan_state, bool active_branch)
     427             : {
     428           7 :     bool        success = true;
     429             : 
     430           7 :     if (active_branch)
     431             :     {
     432           6 :         if (pset.popt.topt.format != PRINT_ALIGNED)
     433           3 :             success = do_pset("format", "aligned", &pset.popt, pset.quiet);
     434             :         else
     435           3 :             success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
     436             :     }
     437             : 
     438           7 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
     439             : }
     440             : 
     441             : /*
     442             :  * \C -- override table title (formerly change HTML caption)
     443             :  */
     444             : static backslashResult
     445           1 : exec_command_C(PsqlScanState scan_state, bool active_branch)
     446             : {
     447           1 :     bool        success = true;
     448             : 
     449           1 :     if (active_branch)
     450             :     {
     451           0 :         char       *opt = psql_scan_slash_option(scan_state,
     452             :                                                  OT_NORMAL, NULL, true);
     453             : 
     454           0 :         success = do_pset("title", opt, &pset.popt, pset.quiet);
     455           0 :         free(opt);
     456             :     }
     457             :     else
     458           1 :         ignore_slash_options(scan_state);
     459             : 
     460           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
     461             : }
     462             : 
     463             : /*
     464             :  * \c or \connect -- connect to database using the specified parameters.
     465             :  *
     466             :  * \c [-reuse-previous=BOOL] dbname user host port
     467             :  *
     468             :  * Specifying a parameter as '-' is equivalent to omitting it.  Examples:
     469             :  *
     470             :  * \c - - hst       Connect to current database on current port of
     471             :  *                  host "hst" as current user.
     472             :  * \c - usr - prt   Connect to current database on port "prt" of current host
     473             :  *                  as user "usr".
     474             :  * \c dbs           Connect to database "dbs" on current port of current host
     475             :  *                  as current user.
     476             :  */
     477             : static backslashResult
     478          34 : exec_command_connect(PsqlScanState scan_state, bool active_branch)
     479             : {
     480          34 :     bool        success = true;
     481             : 
     482          34 :     if (active_branch)
     483             :     {
     484             :         static const char prefix[] = "-reuse-previous=";
     485             :         char       *opt1,
     486             :                    *opt2,
     487             :                    *opt3,
     488             :                    *opt4;
     489          33 :         enum trivalue reuse_previous = TRI_DEFAULT;
     490             : 
     491          33 :         opt1 = read_connect_arg(scan_state);
     492          33 :         if (opt1 != NULL && strncmp(opt1, prefix, sizeof(prefix) - 1) == 0)
     493             :         {
     494             :             bool        on_off;
     495             : 
     496           0 :             success = ParseVariableBool(opt1 + sizeof(prefix) - 1,
     497             :                                         "-reuse-previous",
     498             :                                         &on_off);
     499           0 :             if (success)
     500             :             {
     501           0 :                 reuse_previous = on_off ? TRI_YES : TRI_NO;
     502           0 :                 free(opt1);
     503           0 :                 opt1 = read_connect_arg(scan_state);
     504             :             }
     505             :         }
     506             : 
     507          33 :         if (success)            /* give up if reuse_previous was invalid */
     508             :         {
     509          33 :             opt2 = read_connect_arg(scan_state);
     510          33 :             opt3 = read_connect_arg(scan_state);
     511          33 :             opt4 = read_connect_arg(scan_state);
     512             : 
     513          33 :             success = do_connect(reuse_previous, opt1, opt2, opt3, opt4);
     514             : 
     515          33 :             free(opt2);
     516          33 :             free(opt3);
     517          33 :             free(opt4);
     518             :         }
     519          33 :         free(opt1);
     520             :     }
     521             :     else
     522           1 :         ignore_slash_options(scan_state);
     523             : 
     524          34 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
     525             : }
     526             : 
     527             : /*
     528             :  * \cd -- change directory
     529             :  */
     530             : static backslashResult
     531           1 : exec_command_cd(PsqlScanState scan_state, bool active_branch, const char *cmd)
     532             : {
     533           1 :     bool        success = true;
     534             : 
     535           1 :     if (active_branch)
     536             :     {
     537           0 :         char       *opt = psql_scan_slash_option(scan_state,
     538             :                                                  OT_NORMAL, NULL, true);
     539             :         char       *dir;
     540             : 
     541           0 :         if (opt)
     542           0 :             dir = opt;
     543             :         else
     544             :         {
     545             : #ifndef WIN32
     546             :             struct passwd *pw;
     547           0 :             uid_t       user_id = geteuid();
     548             : 
     549           0 :             errno = 0;          /* clear errno before call */
     550           0 :             pw = getpwuid(user_id);
     551           0 :             if (!pw)
     552             :             {
     553           0 :                 psql_error("could not get home directory for user ID %ld: %s\n",
     554             :                            (long) user_id,
     555           0 :                            errno ? strerror(errno) : _("user does not exist"));
     556           0 :                 exit(EXIT_FAILURE);
     557             :             }
     558           0 :             dir = pw->pw_dir;
     559             : #else                           /* WIN32 */
     560             : 
     561             :             /*
     562             :              * On Windows, 'cd' without arguments prints the current
     563             :              * directory, so if someone wants to code this here instead...
     564             :              */
     565             :             dir = "/";
     566             : #endif                          /* WIN32 */
     567             :         }
     568             : 
     569           0 :         if (chdir(dir) == -1)
     570             :         {
     571           0 :             psql_error("\\%s: could not change directory to \"%s\": %s\n",
     572           0 :                        cmd, dir, strerror(errno));
     573           0 :             success = false;
     574             :         }
     575             : 
     576           0 :         if (opt)
     577           0 :             free(opt);
     578             :     }
     579             :     else
     580           1 :         ignore_slash_options(scan_state);
     581             : 
     582           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
     583             : }
     584             : 
     585             : /*
     586             :  * \conninfo -- display information about the current connection
     587             :  */
     588             : static backslashResult
     589           1 : exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
     590             : {
     591           1 :     if (active_branch)
     592             :     {
     593           0 :         char       *db = PQdb(pset.db);
     594             : 
     595           0 :         if (db == NULL)
     596           0 :             printf(_("You are currently not connected to a database.\n"));
     597             :         else
     598             :         {
     599             :             char       *host;
     600             :             PQconninfoOption *connOptions;
     601             :             PQconninfoOption *option;
     602             : 
     603           0 :             host = PQhost(pset.db);
     604             :             /* A usable "hostaddr" overrides the basic sense of host. */
     605           0 :             connOptions = PQconninfo(pset.db);
     606           0 :             if (connOptions == NULL)
     607             :             {
     608           0 :                 psql_error("out of memory\n");
     609           0 :                 exit(EXIT_FAILURE);
     610             :             }
     611           0 :             for (option = connOptions; option && option->keyword; option++)
     612           0 :                 if (strcmp(option->keyword, "hostaddr") == 0)
     613             :                 {
     614           0 :                     if (option->val != NULL && option->val[0] != '\0')
     615           0 :                         host = option->val;
     616           0 :                     break;
     617             :                 }
     618             : 
     619             :             /* If the host is an absolute path, the connection is via socket */
     620           0 :             if (is_absolute_path(host))
     621           0 :                 printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
     622           0 :                        db, PQuser(pset.db), host, PQport(pset.db));
     623             :             else
     624           0 :                 printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
     625           0 :                        db, PQuser(pset.db), host, PQport(pset.db));
     626           0 :             printSSLInfo();
     627             : 
     628           0 :             PQconninfoFree(connOptions);
     629             :         }
     630             :     }
     631             : 
     632           1 :     return PSQL_CMD_SKIP_LINE;
     633             : }
     634             : 
     635             : /*
     636             :  * \copy -- run a COPY command
     637             :  */
     638             : static backslashResult
     639          12 : exec_command_copy(PsqlScanState scan_state, bool active_branch)
     640             : {
     641          12 :     bool        success = true;
     642             : 
     643          12 :     if (active_branch)
     644             :     {
     645          11 :         char       *opt = psql_scan_slash_option(scan_state,
     646             :                                                  OT_WHOLE_LINE, NULL, false);
     647             : 
     648          11 :         success = do_copy(opt);
     649          11 :         free(opt);
     650             :     }
     651             :     else
     652           1 :         ignore_slash_whole_line(scan_state);
     653             : 
     654          12 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
     655             : }
     656             : 
     657             : /*
     658             :  * \copyright -- print copyright notice
     659             :  */
     660             : static backslashResult
     661           1 : exec_command_copyright(PsqlScanState scan_state, bool active_branch)
     662             : {
     663           1 :     if (active_branch)
     664           0 :         print_copyright();
     665             : 
     666           1 :     return PSQL_CMD_SKIP_LINE;
     667             : }
     668             : 
     669             : /*
     670             :  * \crosstabview -- execute a query and display results in crosstab
     671             :  */
     672             : static backslashResult
     673          22 : exec_command_crosstabview(PsqlScanState scan_state, bool active_branch)
     674             : {
     675          22 :     backslashResult status = PSQL_CMD_SKIP_LINE;
     676             : 
     677          22 :     if (active_branch)
     678             :     {
     679             :         int         i;
     680             : 
     681         110 :         for (i = 0; i < lengthof(pset.ctv_args); i++)
     682          88 :             pset.ctv_args[i] = psql_scan_slash_option(scan_state,
     683             :                                                       OT_NORMAL, NULL, true);
     684          22 :         pset.crosstab_flag = true;
     685          22 :         status = PSQL_CMD_SEND;
     686             :     }
     687             :     else
     688           0 :         ignore_slash_options(scan_state);
     689             : 
     690          22 :     return status;
     691             : }
     692             : 
     693             : /*
     694             :  * \d* commands
     695             :  */
     696             : static backslashResult
     697         302 : exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
     698             : {
     699         302 :     backslashResult status = PSQL_CMD_SKIP_LINE;
     700         302 :     bool        success = true;
     701             : 
     702         302 :     if (active_branch)
     703             :     {
     704             :         char       *pattern;
     705             :         bool        show_verbose,
     706             :                     show_system;
     707             : 
     708             :         /* We don't do SQLID reduction on the pattern yet */
     709         301 :         pattern = psql_scan_slash_option(scan_state,
     710             :                                          OT_NORMAL, NULL, true);
     711             : 
     712         301 :         show_verbose = strchr(cmd, '+') ? true : false;
     713         301 :         show_system = strchr(cmd, 'S') ? true : false;
     714             : 
     715         301 :         switch (cmd[1])
     716             :         {
     717             :             case '\0':
     718             :             case '+':
     719             :             case 'S':
     720         240 :                 if (pattern)
     721         240 :                     success = describeTableDetails(pattern, show_verbose, show_system);
     722             :                 else
     723             :                     /* standard listing of interesting things */
     724           0 :                     success = listTables("tvmsE", NULL, show_verbose, show_system);
     725         240 :                 break;
     726             :             case 'A':
     727           0 :                 success = describeAccessMethods(pattern, show_verbose);
     728           0 :                 break;
     729             :             case 'a':
     730           1 :                 success = describeAggregates(pattern, show_verbose, show_system);
     731           1 :                 break;
     732             :             case 'b':
     733           0 :                 success = describeTablespaces(pattern, show_verbose);
     734           0 :                 break;
     735             :             case 'c':
     736           0 :                 success = listConversions(pattern, show_verbose, show_system);
     737           0 :                 break;
     738             :             case 'C':
     739           0 :                 success = listCasts(pattern, show_verbose);
     740           0 :                 break;
     741             :             case 'd':
     742           0 :                 if (strncmp(cmd, "ddp", 3) == 0)
     743           0 :                     success = listDefaultACLs(pattern);
     744             :                 else
     745           0 :                     success = objectDescription(pattern, show_system);
     746           0 :                 break;
     747             :             case 'D':
     748           0 :                 success = listDomains(pattern, show_verbose, show_system);
     749           0 :                 break;
     750             :             case 'f':           /* function subsystem */
     751           2 :                 switch (cmd[2])
     752             :                 {
     753             :                     case '\0':
     754             :                     case '+':
     755             :                     case 'S':
     756             :                     case 'a':
     757             :                     case 'n':
     758             :                     case 't':
     759             :                     case 'w':
     760           2 :                         success = describeFunctions(&cmd[2], pattern, show_verbose, show_system);
     761           2 :                         break;
     762             :                     default:
     763           0 :                         status = PSQL_CMD_UNKNOWN;
     764           0 :                         break;
     765             :                 }
     766           2 :                 break;
     767             :             case 'g':
     768             :                 /* no longer distinct from \du */
     769           0 :                 success = describeRoles(pattern, show_verbose, show_system);
     770           0 :                 break;
     771             :             case 'l':
     772           0 :                 success = do_lo_list();
     773           0 :                 break;
     774             :             case 'L':
     775           0 :                 success = listLanguages(pattern, show_verbose, show_system);
     776           0 :                 break;
     777             :             case 'n':
     778           0 :                 success = listSchemas(pattern, show_verbose, show_system);
     779           0 :                 break;
     780             :             case 'o':
     781           0 :                 success = describeOperators(pattern, show_verbose, show_system);
     782           0 :                 break;
     783             :             case 'O':
     784           0 :                 success = listCollations(pattern, show_verbose, show_system);
     785           0 :                 break;
     786             :             case 'p':
     787           4 :                 success = permissionsList(pattern);
     788           4 :                 break;
     789             :             case 'T':
     790           0 :                 success = describeTypes(pattern, show_verbose, show_system);
     791           0 :                 break;
     792             :             case 't':
     793             :             case 'v':
     794             :             case 'm':
     795             :             case 'i':
     796             :             case 's':
     797             :             case 'E':
     798           1 :                 success = listTables(&cmd[1], pattern, show_verbose, show_system);
     799           1 :                 break;
     800             :             case 'r':
     801           0 :                 if (cmd[2] == 'd' && cmd[3] == 's')
     802           0 :                 {
     803           0 :                     char       *pattern2 = NULL;
     804             : 
     805           0 :                     if (pattern)
     806           0 :                         pattern2 = psql_scan_slash_option(scan_state,
     807             :                                                           OT_NORMAL, NULL, true);
     808           0 :                     success = listDbRoleSettings(pattern, pattern2);
     809             : 
     810           0 :                     if (pattern2)
     811           0 :                         free(pattern2);
     812             :                 }
     813             :                 else
     814           0 :                     status = PSQL_CMD_UNKNOWN;
     815           0 :                 break;
     816             :             case 'R':
     817          15 :                 switch (cmd[2])
     818             :                 {
     819             :                     case 'p':
     820          10 :                         if (show_verbose)
     821           6 :                             success = describePublications(pattern);
     822             :                         else
     823           4 :                             success = listPublications(pattern);
     824          10 :                         break;
     825             :                     case 's':
     826           5 :                         success = describeSubscriptions(pattern, show_verbose);
     827           5 :                         break;
     828             :                     default:
     829           0 :                         status = PSQL_CMD_UNKNOWN;
     830             :                 }
     831          15 :                 break;
     832             :             case 'u':
     833           0 :                 success = describeRoles(pattern, show_verbose, show_system);
     834           0 :                 break;
     835             :             case 'F':           /* text search subsystem */
     836           0 :                 switch (cmd[2])
     837             :                 {
     838             :                     case '\0':
     839             :                     case '+':
     840           0 :                         success = listTSConfigs(pattern, show_verbose);
     841           0 :                         break;
     842             :                     case 'p':
     843           0 :                         success = listTSParsers(pattern, show_verbose);
     844           0 :                         break;
     845             :                     case 'd':
     846           0 :                         success = listTSDictionaries(pattern, show_verbose);
     847           0 :                         break;
     848             :                     case 't':
     849           0 :                         success = listTSTemplates(pattern, show_verbose);
     850           0 :                         break;
     851             :                     default:
     852           0 :                         status = PSQL_CMD_UNKNOWN;
     853           0 :                         break;
     854             :                 }
     855           0 :                 break;
     856             :             case 'e':           /* SQL/MED subsystem */
     857          38 :                 switch (cmd[2])
     858             :                 {
     859             :                     case 's':
     860          12 :                         success = listForeignServers(pattern, show_verbose);
     861          12 :                         break;
     862             :                     case 'u':
     863          10 :                         success = listUserMappings(pattern, show_verbose);
     864          10 :                         break;
     865             :                     case 'w':
     866          15 :                         success = listForeignDataWrappers(pattern, show_verbose);
     867          15 :                         break;
     868             :                     case 't':
     869           1 :                         success = listForeignTables(pattern, show_verbose);
     870           1 :                         break;
     871             :                     default:
     872           0 :                         status = PSQL_CMD_UNKNOWN;
     873           0 :                         break;
     874             :                 }
     875          38 :                 break;
     876             :             case 'x':           /* Extensions */
     877           0 :                 if (show_verbose)
     878           0 :                     success = listExtensionContents(pattern);
     879             :                 else
     880           0 :                     success = listExtensions(pattern);
     881           0 :                 break;
     882             :             case 'y':           /* Event Triggers */
     883           0 :                 success = listEventTriggers(pattern, show_verbose);
     884           0 :                 break;
     885             :             default:
     886           0 :                 status = PSQL_CMD_UNKNOWN;
     887             :         }
     888             : 
     889         301 :         if (pattern)
     890         255 :             free(pattern);
     891             :     }
     892             :     else
     893           1 :         ignore_slash_options(scan_state);
     894             : 
     895         302 :     if (!success)
     896           2 :         status = PSQL_CMD_ERROR;
     897             : 
     898         302 :     return status;
     899             : }
     900             : 
     901             : /*
     902             :  * \e or \edit -- edit the current query buffer, or edit a file and
     903             :  * make it the query buffer
     904             :  */
     905             : static backslashResult
     906           1 : exec_command_edit(PsqlScanState scan_state, bool active_branch,
     907             :                   PQExpBuffer query_buf, PQExpBuffer previous_buf)
     908             : {
     909           1 :     backslashResult status = PSQL_CMD_SKIP_LINE;
     910             : 
     911           1 :     if (active_branch)
     912             :     {
     913           0 :         if (!query_buf)
     914             :         {
     915           0 :             psql_error("no query buffer\n");
     916           0 :             status = PSQL_CMD_ERROR;
     917             :         }
     918             :         else
     919             :         {
     920             :             char       *fname;
     921           0 :             char       *ln = NULL;
     922           0 :             int         lineno = -1;
     923             : 
     924           0 :             fname = psql_scan_slash_option(scan_state,
     925             :                                            OT_NORMAL, NULL, true);
     926           0 :             if (fname)
     927             :             {
     928             :                 /* try to get separate lineno arg */
     929           0 :                 ln = psql_scan_slash_option(scan_state,
     930             :                                             OT_NORMAL, NULL, true);
     931           0 :                 if (ln == NULL)
     932             :                 {
     933             :                     /* only one arg; maybe it is lineno not fname */
     934           0 :                     if (fname[0] &&
     935           0 :                         strspn(fname, "0123456789") == strlen(fname))
     936             :                     {
     937             :                         /* all digits, so assume it is lineno */
     938           0 :                         ln = fname;
     939           0 :                         fname = NULL;
     940             :                     }
     941             :                 }
     942             :             }
     943           0 :             if (ln)
     944             :             {
     945           0 :                 lineno = atoi(ln);
     946           0 :                 if (lineno < 1)
     947             :                 {
     948           0 :                     psql_error("invalid line number: %s\n", ln);
     949           0 :                     status = PSQL_CMD_ERROR;
     950             :                 }
     951             :             }
     952           0 :             if (status != PSQL_CMD_ERROR)
     953             :             {
     954           0 :                 expand_tilde(&fname);
     955           0 :                 if (fname)
     956           0 :                     canonicalize_path(fname);
     957             : 
     958             :                 /* If query_buf is empty, recall previous query for editing */
     959           0 :                 copy_previous_query(query_buf, previous_buf);
     960             : 
     961           0 :                 if (do_edit(fname, query_buf, lineno, NULL))
     962           0 :                     status = PSQL_CMD_NEWEDIT;
     963             :                 else
     964           0 :                     status = PSQL_CMD_ERROR;
     965             :             }
     966           0 :             if (fname)
     967           0 :                 free(fname);
     968           0 :             if (ln)
     969           0 :                 free(ln);
     970             :         }
     971             :     }
     972             :     else
     973           1 :         ignore_slash_options(scan_state);
     974             : 
     975           1 :     return status;
     976             : }
     977             : 
     978             : /*
     979             :  * \ef -- edit the named function, or present a blank CREATE FUNCTION
     980             :  * template if no argument is given
     981             :  */
     982             : static backslashResult
     983           1 : exec_command_ef(PsqlScanState scan_state, bool active_branch,
     984             :                 PQExpBuffer query_buf)
     985             : {
     986           1 :     backslashResult status = PSQL_CMD_SKIP_LINE;
     987             : 
     988           1 :     if (active_branch)
     989             :     {
     990           0 :         char       *func = psql_scan_slash_option(scan_state,
     991             :                                                   OT_WHOLE_LINE, NULL, true);
     992           0 :         int         lineno = -1;
     993             : 
     994           0 :         if (pset.sversion < 80400)
     995             :         {
     996             :             char        sverbuf[32];
     997             : 
     998           0 :             psql_error("The server (version %s) does not support editing function source.\n",
     999             :                        formatPGVersionNumber(pset.sversion, false,
    1000             :                                              sverbuf, sizeof(sverbuf)));
    1001           0 :             status = PSQL_CMD_ERROR;
    1002             :         }
    1003           0 :         else if (!query_buf)
    1004             :         {
    1005           0 :             psql_error("no query buffer\n");
    1006           0 :             status = PSQL_CMD_ERROR;
    1007             :         }
    1008             :         else
    1009             :         {
    1010           0 :             Oid         foid = InvalidOid;
    1011             : 
    1012           0 :             lineno = strip_lineno_from_objdesc(func);
    1013           0 :             if (lineno == 0)
    1014             :             {
    1015             :                 /* error already reported */
    1016           0 :                 status = PSQL_CMD_ERROR;
    1017             :             }
    1018           0 :             else if (!func)
    1019             :             {
    1020             :                 /* set up an empty command to fill in */
    1021           0 :                 printfPQExpBuffer(query_buf,
    1022             :                                   "CREATE FUNCTION ( )\n"
    1023             :                                   " RETURNS \n"
    1024             :                                   " LANGUAGE \n"
    1025             :                                   " -- common options:  IMMUTABLE  STABLE  STRICT  SECURITY DEFINER\n"
    1026             :                                   "AS $function$\n"
    1027             :                                   "\n$function$\n");
    1028             :             }
    1029           0 :             else if (!lookup_object_oid(EditableFunction, func, &foid))
    1030             :             {
    1031             :                 /* error already reported */
    1032           0 :                 status = PSQL_CMD_ERROR;
    1033             :             }
    1034           0 :             else if (!get_create_object_cmd(EditableFunction, foid, query_buf))
    1035             :             {
    1036             :                 /* error already reported */
    1037           0 :                 status = PSQL_CMD_ERROR;
    1038             :             }
    1039           0 :             else if (lineno > 0)
    1040             :             {
    1041             :                 /*
    1042             :                  * lineno "1" should correspond to the first line of the
    1043             :                  * function body.  We expect that pg_get_functiondef() will
    1044             :                  * emit that on a line beginning with "AS ", and that there
    1045             :                  * can be no such line before the real start of the function
    1046             :                  * body.  Increment lineno by the number of lines before that
    1047             :                  * line, so that it becomes relative to the first line of the
    1048             :                  * function definition.
    1049             :                  */
    1050           0 :                 const char *lines = query_buf->data;
    1051             : 
    1052           0 :                 while (*lines != '\0')
    1053             :                 {
    1054           0 :                     if (strncmp(lines, "AS ", 3) == 0)
    1055           0 :                         break;
    1056           0 :                     lineno++;
    1057             :                     /* find start of next line */
    1058           0 :                     lines = strchr(lines, '\n');
    1059           0 :                     if (!lines)
    1060           0 :                         break;
    1061           0 :                     lines++;
    1062             :                 }
    1063             :             }
    1064             :         }
    1065             : 
    1066           0 :         if (status != PSQL_CMD_ERROR)
    1067             :         {
    1068           0 :             bool        edited = false;
    1069             : 
    1070           0 :             if (!do_edit(NULL, query_buf, lineno, &edited))
    1071           0 :                 status = PSQL_CMD_ERROR;
    1072           0 :             else if (!edited)
    1073           0 :                 puts(_("No changes"));
    1074             :             else
    1075           0 :                 status = PSQL_CMD_NEWEDIT;
    1076             :         }
    1077             : 
    1078           0 :         if (func)
    1079           0 :             free(func);
    1080             :     }
    1081             :     else
    1082           1 :         ignore_slash_whole_line(scan_state);
    1083             : 
    1084           1 :     return status;
    1085             : }
    1086             : 
    1087             : /*
    1088             :  * \ev -- edit the named view, or present a blank CREATE VIEW
    1089             :  * template if no argument is given
    1090             :  */
    1091             : static backslashResult
    1092           1 : exec_command_ev(PsqlScanState scan_state, bool active_branch,
    1093             :                 PQExpBuffer query_buf)
    1094             : {
    1095           1 :     backslashResult status = PSQL_CMD_SKIP_LINE;
    1096             : 
    1097           1 :     if (active_branch)
    1098             :     {
    1099           0 :         char       *view = psql_scan_slash_option(scan_state,
    1100             :                                                   OT_WHOLE_LINE, NULL, true);
    1101           0 :         int         lineno = -1;
    1102             : 
    1103           0 :         if (pset.sversion < 70400)
    1104             :         {
    1105             :             char        sverbuf[32];
    1106             : 
    1107           0 :             psql_error("The server (version %s) does not support editing view definitions.\n",
    1108             :                        formatPGVersionNumber(pset.sversion, false,
    1109             :                                              sverbuf, sizeof(sverbuf)));
    1110           0 :             status = PSQL_CMD_ERROR;
    1111             :         }
    1112           0 :         else if (!query_buf)
    1113             :         {
    1114           0 :             psql_error("no query buffer\n");
    1115           0 :             status = PSQL_CMD_ERROR;
    1116             :         }
    1117             :         else
    1118             :         {
    1119           0 :             Oid         view_oid = InvalidOid;
    1120             : 
    1121           0 :             lineno = strip_lineno_from_objdesc(view);
    1122           0 :             if (lineno == 0)
    1123             :             {
    1124             :                 /* error already reported */
    1125           0 :                 status = PSQL_CMD_ERROR;
    1126             :             }
    1127           0 :             else if (!view)
    1128             :             {
    1129             :                 /* set up an empty command to fill in */
    1130           0 :                 printfPQExpBuffer(query_buf,
    1131             :                                   "CREATE VIEW  AS\n"
    1132             :                                   " SELECT \n"
    1133             :                                   "  -- something...\n");
    1134             :             }
    1135           0 :             else if (!lookup_object_oid(EditableView, view, &view_oid))
    1136             :             {
    1137             :                 /* error already reported */
    1138           0 :                 status = PSQL_CMD_ERROR;
    1139             :             }
    1140           0 :             else if (!get_create_object_cmd(EditableView, view_oid, query_buf))
    1141             :             {
    1142             :                 /* error already reported */
    1143           0 :                 status = PSQL_CMD_ERROR;
    1144             :             }
    1145             :         }
    1146             : 
    1147           0 :         if (status != PSQL_CMD_ERROR)
    1148             :         {
    1149           0 :             bool        edited = false;
    1150             : 
    1151           0 :             if (!do_edit(NULL, query_buf, lineno, &edited))
    1152           0 :                 status = PSQL_CMD_ERROR;
    1153           0 :             else if (!edited)
    1154           0 :                 puts(_("No changes"));
    1155             :             else
    1156           0 :                 status = PSQL_CMD_NEWEDIT;
    1157             :         }
    1158             : 
    1159           0 :         if (view)
    1160           0 :             free(view);
    1161             :     }
    1162             :     else
    1163           1 :         ignore_slash_whole_line(scan_state);
    1164             : 
    1165           1 :     return status;
    1166             : }
    1167             : 
    1168             : /*
    1169             :  * \echo and \qecho -- echo arguments to stdout or query output
    1170             :  */
    1171             : static backslashResult
    1172          41 : exec_command_echo(PsqlScanState scan_state, bool active_branch, const char *cmd)
    1173             : {
    1174          41 :     if (active_branch)
    1175             :     {
    1176             :         char       *value;
    1177             :         char        quoted;
    1178          23 :         bool        no_newline = false;
    1179          23 :         bool        first = true;
    1180             :         FILE       *fout;
    1181             : 
    1182          23 :         if (strcmp(cmd, "qecho") == 0)
    1183           0 :             fout = pset.queryFout;
    1184             :         else
    1185          23 :             fout = stdout;
    1186             : 
    1187          77 :         while ((value = psql_scan_slash_option(scan_state,
    1188             :                                                OT_NORMAL, &quoted, false)))
    1189             :         {
    1190          31 :             if (!quoted && strcmp(value, "-n") == 0)
    1191           0 :                 no_newline = true;
    1192             :             else
    1193             :             {
    1194          31 :                 if (first)
    1195          23 :                     first = false;
    1196             :                 else
    1197           8 :                     fputc(' ', fout);
    1198          31 :                 fputs(value, fout);
    1199             :             }
    1200          31 :             free(value);
    1201             :         }
    1202          23 :         if (!no_newline)
    1203          23 :             fputs("\n", fout);
    1204             :     }
    1205             :     else
    1206          18 :         ignore_slash_options(scan_state);
    1207             : 
    1208          41 :     return PSQL_CMD_SKIP_LINE;
    1209             : }
    1210             : 
    1211             : /*
    1212             :  * \encoding -- set/show client side encoding
    1213             :  */
    1214             : static backslashResult
    1215           1 : exec_command_encoding(PsqlScanState scan_state, bool active_branch)
    1216             : {
    1217           1 :     if (active_branch)
    1218             :     {
    1219           0 :         char       *encoding = psql_scan_slash_option(scan_state,
    1220             :                                                       OT_NORMAL, NULL, false);
    1221             : 
    1222           0 :         if (!encoding)
    1223             :         {
    1224             :             /* show encoding */
    1225           0 :             puts(pg_encoding_to_char(pset.encoding));
    1226             :         }
    1227             :         else
    1228             :         {
    1229             :             /* set encoding */
    1230           0 :             if (PQsetClientEncoding(pset.db, encoding) == -1)
    1231           0 :                 psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
    1232             :             else
    1233             :             {
    1234             :                 /* save encoding info into psql internal data */
    1235           0 :                 pset.encoding = PQclientEncoding(pset.db);
    1236           0 :                 pset.popt.topt.encoding = pset.encoding;
    1237           0 :                 SetVariable(pset.vars, "ENCODING",
    1238             :                             pg_encoding_to_char(pset.encoding));
    1239             :             }
    1240           0 :             free(encoding);
    1241             :         }
    1242             :     }
    1243             :     else
    1244           1 :         ignore_slash_options(scan_state);
    1245             : 
    1246           1 :     return PSQL_CMD_SKIP_LINE;
    1247             : }
    1248             : 
    1249             : /*
    1250             :  * \errverbose -- display verbose message from last failed query
    1251             :  */
    1252             : static backslashResult
    1253           1 : exec_command_errverbose(PsqlScanState scan_state, bool active_branch)
    1254             : {
    1255           1 :     if (active_branch)
    1256             :     {
    1257           0 :         if (pset.last_error_result)
    1258             :         {
    1259             :             char       *msg;
    1260             : 
    1261           0 :             msg = PQresultVerboseErrorMessage(pset.last_error_result,
    1262             :                                               PQERRORS_VERBOSE,
    1263             :                                               PQSHOW_CONTEXT_ALWAYS);
    1264           0 :             if (msg)
    1265             :             {
    1266           0 :                 psql_error("%s", msg);
    1267           0 :                 PQfreemem(msg);
    1268             :             }
    1269             :             else
    1270           0 :                 puts(_("out of memory"));
    1271             :         }
    1272             :         else
    1273           0 :             puts(_("There is no previous error."));
    1274             :     }
    1275             : 
    1276           1 :     return PSQL_CMD_SKIP_LINE;
    1277             : }
    1278             : 
    1279             : /*
    1280             :  * \f -- change field separator
    1281             :  */
    1282             : static backslashResult
    1283           0 : exec_command_f(PsqlScanState scan_state, bool active_branch)
    1284             : {
    1285           0 :     bool        success = true;
    1286             : 
    1287           0 :     if (active_branch)
    1288             :     {
    1289           0 :         char       *fname = psql_scan_slash_option(scan_state,
    1290             :                                                    OT_NORMAL, NULL, false);
    1291             : 
    1292           0 :         success = do_pset("fieldsep", fname, &pset.popt, pset.quiet);
    1293           0 :         free(fname);
    1294             :     }
    1295             :     else
    1296           0 :         ignore_slash_options(scan_state);
    1297             : 
    1298           0 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1299             : }
    1300             : 
    1301             : /*
    1302             :  * \g [filename] -- send query, optionally with output to file/pipe
    1303             :  * \gx [filename] -- same as \g, with expanded mode forced
    1304             :  */
    1305             : static backslashResult
    1306          14 : exec_command_g(PsqlScanState scan_state, bool active_branch, const char *cmd)
    1307             : {
    1308          14 :     backslashResult status = PSQL_CMD_SKIP_LINE;
    1309             : 
    1310          14 :     if (active_branch)
    1311             :     {
    1312          12 :         char       *fname = psql_scan_slash_option(scan_state,
    1313             :                                                    OT_FILEPIPE, NULL, false);
    1314             : 
    1315          12 :         if (!fname)
    1316          12 :             pset.gfname = NULL;
    1317             :         else
    1318             :         {
    1319           0 :             expand_tilde(&fname);
    1320           0 :             pset.gfname = pg_strdup(fname);
    1321             :         }
    1322          12 :         free(fname);
    1323          12 :         if (strcmp(cmd, "gx") == 0)
    1324           4 :             pset.g_expanded = true;
    1325          12 :         status = PSQL_CMD_SEND;
    1326             :     }
    1327             :     else
    1328           2 :         ignore_slash_filepipe(scan_state);
    1329             : 
    1330          14 :     return status;
    1331             : }
    1332             : 
    1333             : /*
    1334             :  * \gexec -- send query and execute each field of result
    1335             :  */
    1336             : static backslashResult
    1337           3 : exec_command_gexec(PsqlScanState scan_state, bool active_branch)
    1338             : {
    1339           3 :     backslashResult status = PSQL_CMD_SKIP_LINE;
    1340             : 
    1341           3 :     if (active_branch)
    1342             :     {
    1343           2 :         pset.gexec_flag = true;
    1344           2 :         status = PSQL_CMD_SEND;
    1345             :     }
    1346             : 
    1347           3 :     return status;
    1348             : }
    1349             : 
    1350             : /*
    1351             :  * \gset [prefix] -- send query and store result into variables
    1352             :  */
    1353             : static backslashResult
    1354          20 : exec_command_gset(PsqlScanState scan_state, bool active_branch)
    1355             : {
    1356          20 :     backslashResult status = PSQL_CMD_SKIP_LINE;
    1357             : 
    1358          20 :     if (active_branch)
    1359             :     {
    1360          20 :         char       *prefix = psql_scan_slash_option(scan_state,
    1361             :                                                     OT_NORMAL, NULL, false);
    1362             : 
    1363          20 :         if (prefix)
    1364           7 :             pset.gset_prefix = prefix;
    1365             :         else
    1366             :         {
    1367             :             /* we must set a non-NULL prefix to trigger storing */
    1368          13 :             pset.gset_prefix = pg_strdup("");
    1369             :         }
    1370             :         /* gset_prefix is freed later */
    1371          20 :         status = PSQL_CMD_SEND;
    1372             :     }
    1373             :     else
    1374           0 :         ignore_slash_options(scan_state);
    1375             : 
    1376          20 :     return status;
    1377             : }
    1378             : 
    1379             : /*
    1380             :  * \help [topic] -- print help about SQL commands
    1381             :  */
    1382             : static backslashResult
    1383           1 : exec_command_help(PsqlScanState scan_state, bool active_branch)
    1384             : {
    1385           1 :     if (active_branch)
    1386             :     {
    1387           0 :         char       *opt = psql_scan_slash_option(scan_state,
    1388             :                                                  OT_WHOLE_LINE, NULL, false);
    1389             :         size_t      len;
    1390             : 
    1391             :         /* strip any trailing spaces and semicolons */
    1392           0 :         if (opt)
    1393             :         {
    1394           0 :             len = strlen(opt);
    1395           0 :             while (len > 0 &&
    1396           0 :                    (isspace((unsigned char) opt[len - 1])
    1397           0 :                     || opt[len - 1] == ';'))
    1398           0 :                 opt[--len] = '\0';
    1399             :         }
    1400             : 
    1401           0 :         helpSQL(opt, pset.popt.topt.pager);
    1402           0 :         free(opt);
    1403             :     }
    1404             :     else
    1405           1 :         ignore_slash_whole_line(scan_state);
    1406             : 
    1407           1 :     return PSQL_CMD_SKIP_LINE;
    1408             : }
    1409             : 
    1410             : /*
    1411             :  * \H and \html -- toggle HTML formatting
    1412             :  */
    1413             : static backslashResult
    1414           0 : exec_command_html(PsqlScanState scan_state, bool active_branch)
    1415             : {
    1416           0 :     bool        success = true;
    1417             : 
    1418           0 :     if (active_branch)
    1419             :     {
    1420           0 :         if (pset.popt.topt.format != PRINT_HTML)
    1421           0 :             success = do_pset("format", "html", &pset.popt, pset.quiet);
    1422             :         else
    1423           0 :             success = do_pset("format", "aligned", &pset.popt, pset.quiet);
    1424             :     }
    1425             : 
    1426           0 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1427             : }
    1428             : 
    1429             : /*
    1430             :  * \i and \ir -- include a file
    1431             :  */
    1432             : static backslashResult
    1433           0 : exec_command_include(PsqlScanState scan_state, bool active_branch, const char *cmd)
    1434             : {
    1435           0 :     bool        success = true;
    1436             : 
    1437           0 :     if (active_branch)
    1438             :     {
    1439           0 :         char       *fname = psql_scan_slash_option(scan_state,
    1440             :                                                    OT_NORMAL, NULL, true);
    1441             : 
    1442           0 :         if (!fname)
    1443             :         {
    1444           0 :             psql_error("\\%s: missing required argument\n", cmd);
    1445           0 :             success = false;
    1446             :         }
    1447             :         else
    1448             :         {
    1449             :             bool        include_relative;
    1450             : 
    1451           0 :             include_relative = (strcmp(cmd, "ir") == 0
    1452           0 :                                 || strcmp(cmd, "include_relative") == 0);
    1453           0 :             expand_tilde(&fname);
    1454           0 :             success = (process_file(fname, include_relative) == EXIT_SUCCESS);
    1455           0 :             free(fname);
    1456             :         }
    1457             :     }
    1458             :     else
    1459           0 :         ignore_slash_options(scan_state);
    1460             : 
    1461           0 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1462             : }
    1463             : 
    1464             : /*
    1465             :  * \if <expr> -- beginning of an \if..\endif block
    1466             :  *
    1467             :  * <expr> is parsed as a boolean expression.  Invalid expressions will emit a
    1468             :  * warning and be treated as false.  Statements that follow a false expression
    1469             :  * will be parsed but ignored.  Note that in the case where an \if statement
    1470             :  * is itself within an inactive section of a block, then the entire inner
    1471             :  * \if..\endif block will be parsed but ignored.
    1472             :  */
    1473             : static backslashResult
    1474          16 : exec_command_if(PsqlScanState scan_state, ConditionalStack cstack,
    1475             :                 PQExpBuffer query_buf)
    1476             : {
    1477          16 :     if (conditional_active(cstack))
    1478             :     {
    1479             :         /*
    1480             :          * First, push a new active stack entry; this ensures that the lexer
    1481             :          * will perform variable substitution and backtick evaluation while
    1482             :          * scanning the expression.  (That should happen anyway, since we know
    1483             :          * we're in an active outer branch, but let's be sure.)
    1484             :          */
    1485          15 :         conditional_stack_push(cstack, IFSTATE_TRUE);
    1486             : 
    1487             :         /* Remember current query state in case we need to restore later */
    1488          15 :         save_query_text_state(scan_state, cstack, query_buf);
    1489             : 
    1490             :         /*
    1491             :          * Evaluate the expression; if it's false, change to inactive state.
    1492             :          */
    1493          15 :         if (!is_true_boolean_expression(scan_state, "\\if expression"))
    1494           7 :             conditional_stack_poke(cstack, IFSTATE_FALSE);
    1495             :     }
    1496             :     else
    1497             :     {
    1498             :         /*
    1499             :          * We're within an inactive outer branch, so this entire \if block
    1500             :          * will be ignored.  We don't want to evaluate the expression, so push
    1501             :          * the "ignored" stack state before scanning it.
    1502             :          */
    1503           1 :         conditional_stack_push(cstack, IFSTATE_IGNORED);
    1504             : 
    1505             :         /* Remember current query state in case we need to restore later */
    1506           1 :         save_query_text_state(scan_state, cstack, query_buf);
    1507             : 
    1508           1 :         ignore_boolean_expression(scan_state);
    1509             :     }
    1510             : 
    1511          16 :     return PSQL_CMD_SKIP_LINE;
    1512             : }
    1513             : 
    1514             : /*
    1515             :  * \elif <expr> -- alternative branch in an \if..\endif block
    1516             :  *
    1517             :  * <expr> is evaluated the same as in \if <expr>.
    1518             :  */
    1519             : static backslashResult
    1520           6 : exec_command_elif(PsqlScanState scan_state, ConditionalStack cstack,
    1521             :                   PQExpBuffer query_buf)
    1522             : {
    1523           6 :     bool        success = true;
    1524             : 
    1525           6 :     switch (conditional_stack_peek(cstack))
    1526             :     {
    1527             :         case IFSTATE_TRUE:
    1528             : 
    1529             :             /*
    1530             :              * Just finished active branch of this \if block.  Update saved
    1531             :              * state so we will keep whatever data was put in query_buf by the
    1532             :              * active branch.
    1533             :              */
    1534           0 :             save_query_text_state(scan_state, cstack, query_buf);
    1535             : 
    1536             :             /*
    1537             :              * Discard \elif expression and ignore the rest until \endif.
    1538             :              * Switch state before reading expression to ensure proper lexer
    1539             :              * behavior.
    1540             :              */
    1541           0 :             conditional_stack_poke(cstack, IFSTATE_IGNORED);
    1542           0 :             ignore_boolean_expression(scan_state);
    1543           0 :             break;
    1544             :         case IFSTATE_FALSE:
    1545             : 
    1546             :             /*
    1547             :              * Discard any query text added by the just-skipped branch.
    1548             :              */
    1549           4 :             discard_query_text(scan_state, cstack, query_buf);
    1550             : 
    1551             :             /*
    1552             :              * Have not yet found a true expression in this \if block, so this
    1553             :              * might be the first.  We have to change state before examining
    1554             :              * the expression, or the lexer won't do the right thing.
    1555             :              */
    1556           4 :             conditional_stack_poke(cstack, IFSTATE_TRUE);
    1557           4 :             if (!is_true_boolean_expression(scan_state, "\\elif expression"))
    1558           3 :                 conditional_stack_poke(cstack, IFSTATE_FALSE);
    1559           4 :             break;
    1560             :         case IFSTATE_IGNORED:
    1561             : 
    1562             :             /*
    1563             :              * Discard any query text added by the just-skipped branch.
    1564             :              */
    1565           0 :             discard_query_text(scan_state, cstack, query_buf);
    1566             : 
    1567             :             /*
    1568             :              * Skip expression and move on.  Either the \if block already had
    1569             :              * an active section, or whole block is being skipped.
    1570             :              */
    1571           0 :             ignore_boolean_expression(scan_state);
    1572           0 :             break;
    1573             :         case IFSTATE_ELSE_TRUE:
    1574             :         case IFSTATE_ELSE_FALSE:
    1575           1 :             psql_error("\\elif: cannot occur after \\else\n");
    1576           1 :             success = false;
    1577           1 :             break;
    1578             :         case IFSTATE_NONE:
    1579             :             /* no \if to elif from */
    1580           1 :             psql_error("\\elif: no matching \\if\n");
    1581           1 :             success = false;
    1582           1 :             break;
    1583             :     }
    1584             : 
    1585           6 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1586             : }
    1587             : 
    1588             : /*
    1589             :  * \else -- final alternative in an \if..\endif block
    1590             :  *
    1591             :  * Statements within an \else branch will only be executed if
    1592             :  * all previous \if and \elif expressions evaluated to false
    1593             :  * and the block was not itself being ignored.
    1594             :  */
    1595             : static backslashResult
    1596          18 : exec_command_else(PsqlScanState scan_state, ConditionalStack cstack,
    1597             :                   PQExpBuffer query_buf)
    1598             : {
    1599          18 :     bool        success = true;
    1600             : 
    1601          18 :     switch (conditional_stack_peek(cstack))
    1602             :     {
    1603             :         case IFSTATE_TRUE:
    1604             : 
    1605             :             /*
    1606             :              * Just finished active branch of this \if block.  Update saved
    1607             :              * state so we will keep whatever data was put in query_buf by the
    1608             :              * active branch.
    1609             :              */
    1610           9 :             save_query_text_state(scan_state, cstack, query_buf);
    1611             : 
    1612             :             /* Now skip the \else branch */
    1613           9 :             conditional_stack_poke(cstack, IFSTATE_ELSE_FALSE);
    1614           9 :             break;
    1615             :         case IFSTATE_FALSE:
    1616             : 
    1617             :             /*
    1618             :              * Discard any query text added by the just-skipped branch.
    1619             :              */
    1620           6 :             discard_query_text(scan_state, cstack, query_buf);
    1621             : 
    1622             :             /*
    1623             :              * We've not found any true \if or \elif expression, so execute
    1624             :              * the \else branch.
    1625             :              */
    1626           6 :             conditional_stack_poke(cstack, IFSTATE_ELSE_TRUE);
    1627           6 :             break;
    1628             :         case IFSTATE_IGNORED:
    1629             : 
    1630             :             /*
    1631             :              * Discard any query text added by the just-skipped branch.
    1632             :              */
    1633           1 :             discard_query_text(scan_state, cstack, query_buf);
    1634             : 
    1635             :             /*
    1636             :              * Either we previously processed the active branch of this \if,
    1637             :              * or the whole \if block is being skipped.  Either way, skip the
    1638             :              * \else branch.
    1639             :              */
    1640           1 :             conditional_stack_poke(cstack, IFSTATE_ELSE_FALSE);
    1641           1 :             break;
    1642             :         case IFSTATE_ELSE_TRUE:
    1643             :         case IFSTATE_ELSE_FALSE:
    1644           1 :             psql_error("\\else: cannot occur after \\else\n");
    1645           1 :             success = false;
    1646           1 :             break;
    1647             :         case IFSTATE_NONE:
    1648             :             /* no \if to else from */
    1649           1 :             psql_error("\\else: no matching \\if\n");
    1650           1 :             success = false;
    1651           1 :             break;
    1652             :     }
    1653             : 
    1654          18 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1655             : }
    1656             : 
    1657             : /*
    1658             :  * \endif -- ends an \if...\endif block
    1659             :  */
    1660             : static backslashResult
    1661          17 : exec_command_endif(PsqlScanState scan_state, ConditionalStack cstack,
    1662             :                    PQExpBuffer query_buf)
    1663             : {
    1664          17 :     bool        success = true;
    1665             : 
    1666          17 :     switch (conditional_stack_peek(cstack))
    1667             :     {
    1668             :         case IFSTATE_TRUE:
    1669             :         case IFSTATE_ELSE_TRUE:
    1670             :             /* Close the \if block, keeping the query text */
    1671           6 :             success = conditional_stack_pop(cstack);
    1672           6 :             Assert(success);
    1673           6 :             break;
    1674             :         case IFSTATE_FALSE:
    1675             :         case IFSTATE_IGNORED:
    1676             :         case IFSTATE_ELSE_FALSE:
    1677             : 
    1678             :             /*
    1679             :              * Discard any query text added by the just-skipped branch.
    1680             :              */
    1681          10 :             discard_query_text(scan_state, cstack, query_buf);
    1682             : 
    1683             :             /* Close the \if block */
    1684          10 :             success = conditional_stack_pop(cstack);
    1685          10 :             Assert(success);
    1686          10 :             break;
    1687             :         case IFSTATE_NONE:
    1688             :             /* no \if to end */
    1689           1 :             psql_error("\\endif: no matching \\if\n");
    1690           1 :             success = false;
    1691           1 :             break;
    1692             :     }
    1693             : 
    1694          17 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1695             : }
    1696             : 
    1697             : /*
    1698             :  * \l -- list databases
    1699             :  */
    1700             : static backslashResult
    1701           0 : exec_command_list(PsqlScanState scan_state, bool active_branch, const char *cmd)
    1702             : {
    1703           0 :     bool        success = true;
    1704             : 
    1705           0 :     if (active_branch)
    1706             :     {
    1707             :         char       *pattern;
    1708             :         bool        show_verbose;
    1709             : 
    1710           0 :         pattern = psql_scan_slash_option(scan_state,
    1711             :                                          OT_NORMAL, NULL, true);
    1712             : 
    1713           0 :         show_verbose = strchr(cmd, '+') ? true : false;
    1714             : 
    1715           0 :         success = listAllDbs(pattern, show_verbose);
    1716             : 
    1717           0 :         if (pattern)
    1718           0 :             free(pattern);
    1719             :     }
    1720             :     else
    1721           0 :         ignore_slash_options(scan_state);
    1722             : 
    1723           0 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1724             : }
    1725             : 
    1726             : /*
    1727             :  * \lo_* -- large object operations
    1728             :  */
    1729             : static backslashResult
    1730           6 : exec_command_lo(PsqlScanState scan_state, bool active_branch, const char *cmd)
    1731             : {
    1732           6 :     backslashResult status = PSQL_CMD_SKIP_LINE;
    1733           6 :     bool        success = true;
    1734             : 
    1735           6 :     if (active_branch)
    1736             :     {
    1737             :         char       *opt1,
    1738             :                    *opt2;
    1739             : 
    1740           6 :         opt1 = psql_scan_slash_option(scan_state,
    1741             :                                       OT_NORMAL, NULL, true);
    1742           6 :         opt2 = psql_scan_slash_option(scan_state,
    1743             :                                       OT_NORMAL, NULL, true);
    1744             : 
    1745           6 :         if (strcmp(cmd + 3, "export") == 0)
    1746             :         {
    1747           1 :             if (!opt2)
    1748             :             {
    1749           0 :                 psql_error("\\%s: missing required argument\n", cmd);
    1750           0 :                 success = false;
    1751             :             }
    1752             :             else
    1753             :             {
    1754           1 :                 expand_tilde(&opt2);
    1755           1 :                 success = do_lo_export(opt1, opt2);
    1756             :             }
    1757             :         }
    1758             : 
    1759           5 :         else if (strcmp(cmd + 3, "import") == 0)
    1760             :         {
    1761           2 :             if (!opt1)
    1762             :             {
    1763           0 :                 psql_error("\\%s: missing required argument\n", cmd);
    1764           0 :                 success = false;
    1765             :             }
    1766             :             else
    1767             :             {
    1768           2 :                 expand_tilde(&opt1);
    1769           2 :                 success = do_lo_import(opt1, opt2);
    1770             :             }
    1771             :         }
    1772             : 
    1773           3 :         else if (strcmp(cmd + 3, "list") == 0)
    1774           0 :             success = do_lo_list();
    1775             : 
    1776           3 :         else if (strcmp(cmd + 3, "unlink") == 0)
    1777             :         {
    1778           3 :             if (!opt1)
    1779             :             {
    1780           0 :                 psql_error("\\%s: missing required argument\n", cmd);
    1781           0 :                 success = false;
    1782             :             }
    1783             :             else
    1784           3 :                 success = do_lo_unlink(opt1);
    1785             :         }
    1786             : 
    1787             :         else
    1788           0 :             status = PSQL_CMD_UNKNOWN;
    1789             : 
    1790           6 :         free(opt1);
    1791           6 :         free(opt2);
    1792             :     }
    1793             :     else
    1794           0 :         ignore_slash_options(scan_state);
    1795             : 
    1796           6 :     if (!success)
    1797           0 :         status = PSQL_CMD_ERROR;
    1798             : 
    1799           6 :     return status;
    1800             : }
    1801             : 
    1802             : /*
    1803             :  * \o -- set query output
    1804             :  */
    1805             : static backslashResult
    1806           1 : exec_command_out(PsqlScanState scan_state, bool active_branch)
    1807             : {
    1808           1 :     bool        success = true;
    1809             : 
    1810           1 :     if (active_branch)
    1811             :     {
    1812           0 :         char       *fname = psql_scan_slash_option(scan_state,
    1813             :                                                    OT_FILEPIPE, NULL, true);
    1814             : 
    1815           0 :         expand_tilde(&fname);
    1816           0 :         success = setQFout(fname);
    1817           0 :         free(fname);
    1818             :     }
    1819             :     else
    1820           1 :         ignore_slash_filepipe(scan_state);
    1821             : 
    1822           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1823             : }
    1824             : 
    1825             : /*
    1826             :  * \p -- print the current query buffer
    1827             :  */
    1828             : static backslashResult
    1829           7 : exec_command_print(PsqlScanState scan_state, bool active_branch,
    1830             :                    PQExpBuffer query_buf, PQExpBuffer previous_buf)
    1831             : {
    1832           7 :     if (active_branch)
    1833             :     {
    1834             :         /*
    1835             :          * We want to print the same thing \g would execute, but not to change
    1836             :          * the query buffer state; so we can't use copy_previous_query().
    1837             :          * Also, beware of possibility that buffer pointers are NULL.
    1838             :          */
    1839           6 :         if (query_buf && query_buf->len > 0)
    1840           3 :             puts(query_buf->data);
    1841           3 :         else if (previous_buf && previous_buf->len > 0)
    1842           3 :             puts(previous_buf->data);
    1843           0 :         else if (!pset.quiet)
    1844           0 :             puts(_("Query buffer is empty."));
    1845           6 :         fflush(stdout);
    1846             :     }
    1847             : 
    1848           7 :     return PSQL_CMD_SKIP_LINE;
    1849             : }
    1850             : 
    1851             : /*
    1852             :  * \password -- set user password
    1853             :  */
    1854             : static backslashResult
    1855           1 : exec_command_password(PsqlScanState scan_state, bool active_branch)
    1856             : {
    1857           1 :     bool        success = true;
    1858             : 
    1859           1 :     if (active_branch)
    1860             :     {
    1861           0 :         char       *opt0 = psql_scan_slash_option(scan_state,
    1862             :                                                   OT_SQLID, NULL, true);
    1863             :         char        pw1[100];
    1864             :         char        pw2[100];
    1865             : 
    1866           0 :         simple_prompt("Enter new password: ", pw1, sizeof(pw1), false);
    1867           0 :         simple_prompt("Enter it again: ", pw2, sizeof(pw2), false);
    1868             : 
    1869           0 :         if (strcmp(pw1, pw2) != 0)
    1870             :         {
    1871           0 :             psql_error("Passwords didn't match.\n");
    1872           0 :             success = false;
    1873             :         }
    1874             :         else
    1875             :         {
    1876             :             char       *user;
    1877             :             char       *encrypted_password;
    1878             : 
    1879           0 :             if (opt0)
    1880           0 :                 user = opt0;
    1881             :             else
    1882           0 :                 user = PQuser(pset.db);
    1883             : 
    1884           0 :             encrypted_password = PQencryptPasswordConn(pset.db, pw1, user, NULL);
    1885             : 
    1886           0 :             if (!encrypted_password)
    1887             :             {
    1888           0 :                 psql_error("%s", PQerrorMessage(pset.db));
    1889           0 :                 success = false;
    1890             :             }
    1891             :             else
    1892             :             {
    1893             :                 PQExpBufferData buf;
    1894             :                 PGresult   *res;
    1895             : 
    1896           0 :                 initPQExpBuffer(&buf);
    1897           0 :                 printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ",
    1898             :                                   fmtId(user));
    1899           0 :                 appendStringLiteralConn(&buf, encrypted_password, pset.db);
    1900           0 :                 res = PSQLexec(buf.data);
    1901           0 :                 termPQExpBuffer(&buf);
    1902           0 :                 if (!res)
    1903           0 :                     success = false;
    1904             :                 else
    1905           0 :                     PQclear(res);
    1906           0 :                 PQfreemem(encrypted_password);
    1907             :             }
    1908             :         }
    1909             : 
    1910           0 :         if (opt0)
    1911           0 :             free(opt0);
    1912             :     }
    1913             :     else
    1914           1 :         ignore_slash_options(scan_state);
    1915             : 
    1916           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1917             : }
    1918             : 
    1919             : /*
    1920             :  * \prompt -- prompt and set variable
    1921             :  */
    1922             : static backslashResult
    1923           1 : exec_command_prompt(PsqlScanState scan_state, bool active_branch,
    1924             :                     const char *cmd)
    1925             : {
    1926           1 :     bool        success = true;
    1927             : 
    1928           1 :     if (active_branch)
    1929             :     {
    1930             :         char       *opt,
    1931           0 :                    *prompt_text = NULL;
    1932             :         char       *arg1,
    1933             :                    *arg2;
    1934             : 
    1935           0 :         arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
    1936           0 :         arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
    1937             : 
    1938           0 :         if (!arg1)
    1939             :         {
    1940           0 :             psql_error("\\%s: missing required argument\n", cmd);
    1941           0 :             success = false;
    1942             :         }
    1943             :         else
    1944             :         {
    1945             :             char       *result;
    1946             : 
    1947           0 :             if (arg2)
    1948             :             {
    1949           0 :                 prompt_text = arg1;
    1950           0 :                 opt = arg2;
    1951             :             }
    1952             :             else
    1953           0 :                 opt = arg1;
    1954             : 
    1955           0 :             if (!pset.inputfile)
    1956             :             {
    1957           0 :                 result = (char *) pg_malloc(4096);
    1958           0 :                 simple_prompt(prompt_text, result, 4096, true);
    1959             :             }
    1960             :             else
    1961             :             {
    1962           0 :                 if (prompt_text)
    1963             :                 {
    1964           0 :                     fputs(prompt_text, stdout);
    1965           0 :                     fflush(stdout);
    1966             :                 }
    1967           0 :                 result = gets_fromFile(stdin);
    1968           0 :                 if (!result)
    1969             :                 {
    1970           0 :                     psql_error("\\%s: could not read value for variable\n",
    1971             :                                cmd);
    1972           0 :                     success = false;
    1973             :                 }
    1974             :             }
    1975             : 
    1976           0 :             if (result &&
    1977           0 :                 !SetVariable(pset.vars, opt, result))
    1978           0 :                 success = false;
    1979             : 
    1980           0 :             if (result)
    1981           0 :                 free(result);
    1982           0 :             if (prompt_text)
    1983           0 :                 free(prompt_text);
    1984           0 :             free(opt);
    1985             :         }
    1986             :     }
    1987             :     else
    1988           1 :         ignore_slash_options(scan_state);
    1989             : 
    1990           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    1991             : }
    1992             : 
    1993             : /*
    1994             :  * \pset -- set printing parameters
    1995             :  */
    1996             : static backslashResult
    1997         152 : exec_command_pset(PsqlScanState scan_state, bool active_branch)
    1998             : {
    1999         152 :     bool        success = true;
    2000             : 
    2001         152 :     if (active_branch)
    2002             :     {
    2003         150 :         char       *opt0 = psql_scan_slash_option(scan_state,
    2004             :                                                   OT_NORMAL, NULL, false);
    2005         150 :         char       *opt1 = psql_scan_slash_option(scan_state,
    2006             :                                                   OT_NORMAL, NULL, false);
    2007             : 
    2008         150 :         if (!opt0)
    2009             :         {
    2010             :             /* list all variables */
    2011             : 
    2012             :             int         i;
    2013             :             static const char *const my_list[] = {
    2014             :                 "border", "columns", "expanded", "fieldsep", "fieldsep_zero",
    2015             :                 "footer", "format", "linestyle", "null",
    2016             :                 "numericlocale", "pager", "pager_min_lines",
    2017             :                 "recordsep", "recordsep_zero",
    2018             :                 "tableattr", "title", "tuples_only",
    2019             :                 "unicode_border_linestyle",
    2020             :                 "unicode_column_linestyle",
    2021             :                 "unicode_header_linestyle",
    2022             :                 NULL
    2023             :             };
    2024             : 
    2025          21 :             for (i = 0; my_list[i] != NULL; i++)
    2026             :             {
    2027          20 :                 char       *val = pset_value_string(my_list[i], &pset.popt);
    2028             : 
    2029          20 :                 printf("%-24s %s\n", my_list[i], val);
    2030          20 :                 free(val);
    2031             :             }
    2032             : 
    2033           1 :             success = true;
    2034             :         }
    2035             :         else
    2036         149 :             success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
    2037             : 
    2038         150 :         free(opt0);
    2039         150 :         free(opt1);
    2040             :     }
    2041             :     else
    2042           2 :         ignore_slash_options(scan_state);
    2043             : 
    2044         152 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2045             : }
    2046             : 
    2047             : /*
    2048             :  * \q or \quit -- exit psql
    2049             :  */
    2050             : static backslashResult
    2051           1 : exec_command_quit(PsqlScanState scan_state, bool active_branch)
    2052             : {
    2053           1 :     backslashResult status = PSQL_CMD_SKIP_LINE;
    2054             : 
    2055           1 :     if (active_branch)
    2056           0 :         status = PSQL_CMD_TERMINATE;
    2057             : 
    2058           1 :     return status;
    2059             : }
    2060             : 
    2061             : /*
    2062             :  * \r -- reset (clear) the query buffer
    2063             :  */
    2064             : static backslashResult
    2065           4 : exec_command_reset(PsqlScanState scan_state, bool active_branch,
    2066             :                    PQExpBuffer query_buf)
    2067             : {
    2068           4 :     if (active_branch)
    2069             :     {
    2070           3 :         resetPQExpBuffer(query_buf);
    2071           3 :         psql_scan_reset(scan_state);
    2072           3 :         if (!pset.quiet)
    2073           0 :             puts(_("Query buffer reset (cleared)."));
    2074             :     }
    2075             : 
    2076           4 :     return PSQL_CMD_SKIP_LINE;
    2077             : }
    2078             : 
    2079             : /*
    2080             :  * \s -- save history in a file or show it on the screen
    2081             :  */
    2082             : static backslashResult
    2083           1 : exec_command_s(PsqlScanState scan_state, bool active_branch)
    2084             : {
    2085           1 :     bool        success = true;
    2086             : 
    2087           1 :     if (active_branch)
    2088             :     {
    2089           0 :         char       *fname = psql_scan_slash_option(scan_state,
    2090             :                                                    OT_NORMAL, NULL, true);
    2091             : 
    2092           0 :         expand_tilde(&fname);
    2093           0 :         success = printHistory(fname, pset.popt.topt.pager);
    2094           0 :         if (success && !pset.quiet && fname)
    2095           0 :             printf(_("Wrote history to file \"%s\".\n"), fname);
    2096           0 :         if (!fname)
    2097           0 :             putchar('\n');
    2098           0 :         free(fname);
    2099             :     }
    2100             :     else
    2101           1 :         ignore_slash_options(scan_state);
    2102             : 
    2103           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2104             : }
    2105             : 
    2106             : /*
    2107             :  * \set -- set variable
    2108             :  */
    2109             : static backslashResult
    2110          64 : exec_command_set(PsqlScanState scan_state, bool active_branch)
    2111             : {
    2112          64 :     bool        success = true;
    2113             : 
    2114          64 :     if (active_branch)
    2115             :     {
    2116          63 :         char       *opt0 = psql_scan_slash_option(scan_state,
    2117             :                                                   OT_NORMAL, NULL, false);
    2118             : 
    2119          63 :         if (!opt0)
    2120             :         {
    2121             :             /* list all variables */
    2122           0 :             PrintVariables(pset.vars);
    2123           0 :             success = true;
    2124             :         }
    2125             :         else
    2126             :         {
    2127             :             /*
    2128             :              * Set variable to the concatenation of the arguments.
    2129             :              */
    2130             :             char       *newval;
    2131             :             char       *opt;
    2132             : 
    2133          63 :             opt = psql_scan_slash_option(scan_state,
    2134             :                                          OT_NORMAL, NULL, false);
    2135          63 :             newval = pg_strdup(opt ? opt : "");
    2136          63 :             free(opt);
    2137             : 
    2138         126 :             while ((opt = psql_scan_slash_option(scan_state,
    2139             :                                                  OT_NORMAL, NULL, false)))
    2140             :             {
    2141           0 :                 newval = pg_realloc(newval, strlen(newval) + strlen(opt) + 1);
    2142           0 :                 strcat(newval, opt);
    2143           0 :                 free(opt);
    2144             :             }
    2145             : 
    2146          63 :             if (!SetVariable(pset.vars, opt0, newval))
    2147           4 :                 success = false;
    2148             : 
    2149          63 :             free(newval);
    2150             :         }
    2151          63 :         free(opt0);
    2152             :     }
    2153             :     else
    2154           1 :         ignore_slash_options(scan_state);
    2155             : 
    2156          64 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2157             : }
    2158             : 
    2159             : /*
    2160             :  * \setenv -- set environment variable
    2161             :  */
    2162             : static backslashResult
    2163           1 : exec_command_setenv(PsqlScanState scan_state, bool active_branch,
    2164             :                     const char *cmd)
    2165             : {
    2166           1 :     bool        success = true;
    2167             : 
    2168           1 :     if (active_branch)
    2169             :     {
    2170           0 :         char       *envvar = psql_scan_slash_option(scan_state,
    2171             :                                                     OT_NORMAL, NULL, false);
    2172           0 :         char       *envval = psql_scan_slash_option(scan_state,
    2173             :                                                     OT_NORMAL, NULL, false);
    2174             : 
    2175           0 :         if (!envvar)
    2176             :         {
    2177           0 :             psql_error("\\%s: missing required argument\n", cmd);
    2178           0 :             success = false;
    2179             :         }
    2180           0 :         else if (strchr(envvar, '=') != NULL)
    2181             :         {
    2182           0 :             psql_error("\\%s: environment variable name must not contain \"=\"\n",
    2183             :                        cmd);
    2184           0 :             success = false;
    2185             :         }
    2186           0 :         else if (!envval)
    2187             :         {
    2188             :             /* No argument - unset the environment variable */
    2189           0 :             unsetenv(envvar);
    2190           0 :             success = true;
    2191             :         }
    2192             :         else
    2193             :         {
    2194             :             /* Set variable to the value of the next argument */
    2195             :             char       *newval;
    2196             : 
    2197           0 :             newval = psprintf("%s=%s", envvar, envval);
    2198           0 :             putenv(newval);
    2199           0 :             success = true;
    2200             : 
    2201             :             /*
    2202             :              * Do not free newval here, it will screw up the environment if
    2203             :              * you do. See putenv man page for details. That means we leak a
    2204             :              * bit of memory here, but not enough to worry about.
    2205             :              */
    2206             :         }
    2207           0 :         free(envvar);
    2208           0 :         free(envval);
    2209             :     }
    2210             :     else
    2211           1 :         ignore_slash_options(scan_state);
    2212             : 
    2213           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2214             : }
    2215             : 
    2216             : /*
    2217             :  * \sf -- show a function's source code
    2218             :  */
    2219             : static backslashResult
    2220           1 : exec_command_sf(PsqlScanState scan_state, bool active_branch, const char *cmd)
    2221             : {
    2222           1 :     backslashResult status = PSQL_CMD_SKIP_LINE;
    2223             : 
    2224           1 :     if (active_branch)
    2225             :     {
    2226           0 :         bool        show_linenumbers = (strcmp(cmd, "sf+") == 0);
    2227             :         PQExpBuffer func_buf;
    2228             :         char       *func;
    2229           0 :         Oid         foid = InvalidOid;
    2230             : 
    2231           0 :         func_buf = createPQExpBuffer();
    2232           0 :         func = psql_scan_slash_option(scan_state,
    2233             :                                       OT_WHOLE_LINE, NULL, true);
    2234           0 :         if (pset.sversion < 80400)
    2235             :         {
    2236             :             char        sverbuf[32];
    2237             : 
    2238           0 :             psql_error("The server (version %s) does not support showing function source.\n",
    2239             :                        formatPGVersionNumber(pset.sversion, false,
    2240             :                                              sverbuf, sizeof(sverbuf)));
    2241           0 :             status = PSQL_CMD_ERROR;
    2242             :         }
    2243           0 :         else if (!func)
    2244             :         {
    2245           0 :             psql_error("function name is required\n");
    2246           0 :             status = PSQL_CMD_ERROR;
    2247             :         }
    2248           0 :         else if (!lookup_object_oid(EditableFunction, func, &foid))
    2249             :         {
    2250             :             /* error already reported */
    2251           0 :             status = PSQL_CMD_ERROR;
    2252             :         }
    2253           0 :         else if (!get_create_object_cmd(EditableFunction, foid, func_buf))
    2254             :         {
    2255             :             /* error already reported */
    2256           0 :             status = PSQL_CMD_ERROR;
    2257             :         }
    2258             :         else
    2259             :         {
    2260             :             FILE       *output;
    2261             :             bool        is_pager;
    2262             : 
    2263             :             /* Select output stream: stdout, pager, or file */
    2264           0 :             if (pset.queryFout == stdout)
    2265             :             {
    2266             :                 /* count lines in function to see if pager is needed */
    2267           0 :                 int         lineno = count_lines_in_buf(func_buf);
    2268             : 
    2269           0 :                 output = PageOutput(lineno, &(pset.popt.topt));
    2270           0 :                 is_pager = true;
    2271             :             }
    2272             :             else
    2273             :             {
    2274             :                 /* use previously set output file, without pager */
    2275           0 :                 output = pset.queryFout;
    2276           0 :                 is_pager = false;
    2277             :             }
    2278             : 
    2279           0 :             if (show_linenumbers)
    2280             :             {
    2281             :                 /*
    2282             :                  * lineno "1" should correspond to the first line of the
    2283             :                  * function body.  We expect that pg_get_functiondef() will
    2284             :                  * emit that on a line beginning with "AS ", and that there
    2285             :                  * can be no such line before the real start of the function
    2286             :                  * body.
    2287             :                  */
    2288           0 :                 print_with_linenumbers(output, func_buf->data, "AS ");
    2289             :             }
    2290             :             else
    2291             :             {
    2292             :                 /* just send the function definition to output */
    2293           0 :                 fputs(func_buf->data, output);
    2294             :             }
    2295             : 
    2296           0 :             if (is_pager)
    2297           0 :                 ClosePager(output);
    2298             :         }
    2299             : 
    2300           0 :         if (func)
    2301           0 :             free(func);
    2302           0 :         destroyPQExpBuffer(func_buf);
    2303             :     }
    2304             :     else
    2305           1 :         ignore_slash_whole_line(scan_state);
    2306             : 
    2307           1 :     return status;
    2308             : }
    2309             : 
    2310             : /*
    2311             :  * \sv -- show a view's source code
    2312             :  */
    2313             : static backslashResult
    2314           2 : exec_command_sv(PsqlScanState scan_state, bool active_branch, const char *cmd)
    2315             : {
    2316           2 :     backslashResult status = PSQL_CMD_SKIP_LINE;
    2317             : 
    2318           2 :     if (active_branch)
    2319             :     {
    2320           1 :         bool        show_linenumbers = (strcmp(cmd, "sv+") == 0);
    2321             :         PQExpBuffer view_buf;
    2322             :         char       *view;
    2323           1 :         Oid         view_oid = InvalidOid;
    2324             : 
    2325           1 :         view_buf = createPQExpBuffer();
    2326           1 :         view = psql_scan_slash_option(scan_state,
    2327             :                                       OT_WHOLE_LINE, NULL, true);
    2328           1 :         if (pset.sversion < 70400)
    2329             :         {
    2330             :             char        sverbuf[32];
    2331             : 
    2332           0 :             psql_error("The server (version %s) does not support showing view definitions.\n",
    2333             :                        formatPGVersionNumber(pset.sversion, false,
    2334             :                                              sverbuf, sizeof(sverbuf)));
    2335           0 :             status = PSQL_CMD_ERROR;
    2336             :         }
    2337           1 :         else if (!view)
    2338             :         {
    2339           0 :             psql_error("view name is required\n");
    2340           0 :             status = PSQL_CMD_ERROR;
    2341             :         }
    2342           1 :         else if (!lookup_object_oid(EditableView, view, &view_oid))
    2343             :         {
    2344             :             /* error already reported */
    2345           0 :             status = PSQL_CMD_ERROR;
    2346             :         }
    2347           1 :         else if (!get_create_object_cmd(EditableView, view_oid, view_buf))
    2348             :         {
    2349             :             /* error already reported */
    2350           0 :             status = PSQL_CMD_ERROR;
    2351             :         }
    2352             :         else
    2353             :         {
    2354             :             FILE       *output;
    2355             :             bool        is_pager;
    2356             : 
    2357             :             /* Select output stream: stdout, pager, or file */
    2358           1 :             if (pset.queryFout == stdout)
    2359             :             {
    2360             :                 /* count lines in view to see if pager is needed */
    2361           1 :                 int         lineno = count_lines_in_buf(view_buf);
    2362             : 
    2363           1 :                 output = PageOutput(lineno, &(pset.popt.topt));
    2364           1 :                 is_pager = true;
    2365             :             }
    2366             :             else
    2367             :             {
    2368             :                 /* use previously set output file, without pager */
    2369           0 :                 output = pset.queryFout;
    2370           0 :                 is_pager = false;
    2371             :             }
    2372             : 
    2373           1 :             if (show_linenumbers)
    2374             :             {
    2375             :                 /* add line numbers, numbering all lines */
    2376           0 :                 print_with_linenumbers(output, view_buf->data, NULL);
    2377             :             }
    2378             :             else
    2379             :             {
    2380             :                 /* just send the view definition to output */
    2381           1 :                 fputs(view_buf->data, output);
    2382             :             }
    2383             : 
    2384           1 :             if (is_pager)
    2385           1 :                 ClosePager(output);
    2386             :         }
    2387             : 
    2388           1 :         if (view)
    2389           1 :             free(view);
    2390           1 :         destroyPQExpBuffer(view_buf);
    2391             :     }
    2392             :     else
    2393           1 :         ignore_slash_whole_line(scan_state);
    2394             : 
    2395           2 :     return status;
    2396             : }
    2397             : 
    2398             : /*
    2399             :  * \t -- turn off table headers and row count
    2400             :  */
    2401             : static backslashResult
    2402           7 : exec_command_t(PsqlScanState scan_state, bool active_branch)
    2403             : {
    2404           7 :     bool        success = true;
    2405             : 
    2406           7 :     if (active_branch)
    2407             :     {
    2408           6 :         char       *opt = psql_scan_slash_option(scan_state,
    2409             :                                                  OT_NORMAL, NULL, true);
    2410             : 
    2411           6 :         success = do_pset("tuples_only", opt, &pset.popt, pset.quiet);
    2412           6 :         free(opt);
    2413             :     }
    2414             :     else
    2415           1 :         ignore_slash_options(scan_state);
    2416             : 
    2417           7 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2418             : }
    2419             : 
    2420             : /*
    2421             :  * \T -- define html <table ...> attributes
    2422             :  */
    2423             : static backslashResult
    2424           1 : exec_command_T(PsqlScanState scan_state, bool active_branch)
    2425             : {
    2426           1 :     bool        success = true;
    2427             : 
    2428           1 :     if (active_branch)
    2429             :     {
    2430           0 :         char       *value = psql_scan_slash_option(scan_state,
    2431             :                                                    OT_NORMAL, NULL, false);
    2432             : 
    2433           0 :         success = do_pset("tableattr", value, &pset.popt, pset.quiet);
    2434           0 :         free(value);
    2435             :     }
    2436             :     else
    2437           1 :         ignore_slash_options(scan_state);
    2438             : 
    2439           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2440             : }
    2441             : 
    2442             : /*
    2443             :  * \timing -- enable/disable timing of queries
    2444             :  */
    2445             : static backslashResult
    2446           1 : exec_command_timing(PsqlScanState scan_state, bool active_branch)
    2447             : {
    2448           1 :     bool        success = true;
    2449             : 
    2450           1 :     if (active_branch)
    2451             :     {
    2452           0 :         char       *opt = psql_scan_slash_option(scan_state,
    2453             :                                                  OT_NORMAL, NULL, false);
    2454             : 
    2455           0 :         if (opt)
    2456           0 :             success = ParseVariableBool(opt, "\\timing", &pset.timing);
    2457             :         else
    2458           0 :             pset.timing = !pset.timing;
    2459           0 :         if (!pset.quiet)
    2460             :         {
    2461           0 :             if (pset.timing)
    2462           0 :                 puts(_("Timing is on."));
    2463             :             else
    2464           0 :                 puts(_("Timing is off."));
    2465             :         }
    2466           0 :         free(opt);
    2467             :     }
    2468             :     else
    2469           1 :         ignore_slash_options(scan_state);
    2470             : 
    2471           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2472             : }
    2473             : 
    2474             : /*
    2475             :  * \unset -- unset variable
    2476             :  */
    2477             : static backslashResult
    2478           5 : exec_command_unset(PsqlScanState scan_state, bool active_branch,
    2479             :                    const char *cmd)
    2480             : {
    2481           5 :     bool        success = true;
    2482             : 
    2483           5 :     if (active_branch)
    2484             :     {
    2485           4 :         char       *opt = psql_scan_slash_option(scan_state,
    2486             :                                                  OT_NORMAL, NULL, false);
    2487             : 
    2488           4 :         if (!opt)
    2489             :         {
    2490           0 :             psql_error("\\%s: missing required argument\n", cmd);
    2491           0 :             success = false;
    2492             :         }
    2493           4 :         else if (!SetVariable(pset.vars, opt, NULL))
    2494           0 :             success = false;
    2495             : 
    2496           4 :         free(opt);
    2497             :     }
    2498             :     else
    2499           1 :         ignore_slash_options(scan_state);
    2500             : 
    2501           5 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2502             : }
    2503             : 
    2504             : /*
    2505             :  * \w -- write query buffer to file
    2506             :  */
    2507             : static backslashResult
    2508           2 : exec_command_write(PsqlScanState scan_state, bool active_branch,
    2509             :                    const char *cmd,
    2510             :                    PQExpBuffer query_buf, PQExpBuffer previous_buf)
    2511             : {
    2512           2 :     backslashResult status = PSQL_CMD_SKIP_LINE;
    2513             : 
    2514           2 :     if (active_branch)
    2515             :     {
    2516           0 :         char       *fname = psql_scan_slash_option(scan_state,
    2517             :                                                    OT_FILEPIPE, NULL, true);
    2518           0 :         FILE       *fd = NULL;
    2519           0 :         bool        is_pipe = false;
    2520             : 
    2521           0 :         if (!query_buf)
    2522             :         {
    2523           0 :             psql_error("no query buffer\n");
    2524           0 :             status = PSQL_CMD_ERROR;
    2525             :         }
    2526             :         else
    2527             :         {
    2528           0 :             if (!fname)
    2529             :             {
    2530           0 :                 psql_error("\\%s: missing required argument\n", cmd);
    2531           0 :                 status = PSQL_CMD_ERROR;
    2532             :             }
    2533             :             else
    2534             :             {
    2535           0 :                 expand_tilde(&fname);
    2536           0 :                 if (fname[0] == '|')
    2537             :                 {
    2538           0 :                     is_pipe = true;
    2539           0 :                     disable_sigpipe_trap();
    2540           0 :                     fd = popen(&fname[1], "w");
    2541             :                 }
    2542             :                 else
    2543             :                 {
    2544           0 :                     canonicalize_path(fname);
    2545           0 :                     fd = fopen(fname, "w");
    2546             :                 }
    2547           0 :                 if (!fd)
    2548             :                 {
    2549           0 :                     psql_error("%s: %s\n", fname, strerror(errno));
    2550           0 :                     status = PSQL_CMD_ERROR;
    2551             :                 }
    2552             :             }
    2553             :         }
    2554             : 
    2555           0 :         if (fd)
    2556             :         {
    2557             :             int         result;
    2558             : 
    2559             :             /*
    2560             :              * We want to print the same thing \g would execute, but not to
    2561             :              * change the query buffer state; so we can't use
    2562             :              * copy_previous_query().  Also, beware of possibility that buffer
    2563             :              * pointers are NULL.
    2564             :              */
    2565           0 :             if (query_buf && query_buf->len > 0)
    2566           0 :                 fprintf(fd, "%s\n", query_buf->data);
    2567           0 :             else if (previous_buf && previous_buf->len > 0)
    2568           0 :                 fprintf(fd, "%s\n", previous_buf->data);
    2569             : 
    2570           0 :             if (is_pipe)
    2571           0 :                 result = pclose(fd);
    2572             :             else
    2573           0 :                 result = fclose(fd);
    2574             : 
    2575           0 :             if (result == EOF)
    2576             :             {
    2577           0 :                 psql_error("%s: %s\n", fname, strerror(errno));
    2578           0 :                 status = PSQL_CMD_ERROR;
    2579             :             }
    2580             :         }
    2581             : 
    2582           0 :         if (is_pipe)
    2583           0 :             restore_sigpipe_trap();
    2584             : 
    2585           0 :         free(fname);
    2586             :     }
    2587             :     else
    2588           2 :         ignore_slash_filepipe(scan_state);
    2589             : 
    2590           2 :     return status;
    2591             : }
    2592             : 
    2593             : /*
    2594             :  * \watch -- execute a query every N seconds
    2595             :  */
    2596             : static backslashResult
    2597           1 : exec_command_watch(PsqlScanState scan_state, bool active_branch,
    2598             :                    PQExpBuffer query_buf, PQExpBuffer previous_buf)
    2599             : {
    2600           1 :     bool        success = true;
    2601             : 
    2602           1 :     if (active_branch)
    2603             :     {
    2604           0 :         char       *opt = psql_scan_slash_option(scan_state,
    2605             :                                                  OT_NORMAL, NULL, true);
    2606           0 :         double      sleep = 2;
    2607             : 
    2608             :         /* Convert optional sleep-length argument */
    2609           0 :         if (opt)
    2610             :         {
    2611           0 :             sleep = strtod(opt, NULL);
    2612           0 :             if (sleep <= 0)
    2613           0 :                 sleep = 1;
    2614           0 :             free(opt);
    2615             :         }
    2616             : 
    2617             :         /* If query_buf is empty, recall and execute previous query */
    2618           0 :         copy_previous_query(query_buf, previous_buf);
    2619             : 
    2620           0 :         success = do_watch(query_buf, sleep);
    2621             : 
    2622             :         /* Reset the query buffer as though for \r */
    2623           0 :         resetPQExpBuffer(query_buf);
    2624           0 :         psql_scan_reset(scan_state);
    2625             :     }
    2626             :     else
    2627           1 :         ignore_slash_options(scan_state);
    2628             : 
    2629           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2630             : }
    2631             : 
    2632             : /*
    2633             :  * \x -- set or toggle expanded table representation
    2634             :  */
    2635             : static backslashResult
    2636           1 : exec_command_x(PsqlScanState scan_state, bool active_branch)
    2637             : {
    2638           1 :     bool        success = true;
    2639             : 
    2640           1 :     if (active_branch)
    2641             :     {
    2642           0 :         char       *opt = psql_scan_slash_option(scan_state,
    2643             :                                                  OT_NORMAL, NULL, true);
    2644             : 
    2645           0 :         success = do_pset("expanded", opt, &pset.popt, pset.quiet);
    2646           0 :         free(opt);
    2647             :     }
    2648             :     else
    2649           1 :         ignore_slash_options(scan_state);
    2650             : 
    2651           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2652             : }
    2653             : 
    2654             : /*
    2655             :  * \z -- list table privileges (equivalent to \dp)
    2656             :  */
    2657             : static backslashResult
    2658           2 : exec_command_z(PsqlScanState scan_state, bool active_branch)
    2659             : {
    2660           2 :     bool        success = true;
    2661             : 
    2662           2 :     if (active_branch)
    2663             :     {
    2664           2 :         char       *pattern = psql_scan_slash_option(scan_state,
    2665             :                                                      OT_NORMAL, NULL, true);
    2666             : 
    2667           2 :         success = permissionsList(pattern);
    2668           2 :         if (pattern)
    2669           2 :             free(pattern);
    2670             :     }
    2671             :     else
    2672           0 :         ignore_slash_options(scan_state);
    2673             : 
    2674           2 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2675             : }
    2676             : 
    2677             : /*
    2678             :  * \! -- execute shell command
    2679             :  */
    2680             : static backslashResult
    2681           1 : exec_command_shell_escape(PsqlScanState scan_state, bool active_branch)
    2682             : {
    2683           1 :     bool        success = true;
    2684             : 
    2685           1 :     if (active_branch)
    2686             :     {
    2687           0 :         char       *opt = psql_scan_slash_option(scan_state,
    2688             :                                                  OT_WHOLE_LINE, NULL, false);
    2689             : 
    2690           0 :         success = do_shell(opt);
    2691           0 :         free(opt);
    2692             :     }
    2693             :     else
    2694           1 :         ignore_slash_whole_line(scan_state);
    2695             : 
    2696           1 :     return success ? PSQL_CMD_SKIP_LINE : PSQL_CMD_ERROR;
    2697             : }
    2698             : 
    2699             : /*
    2700             :  * \? -- print help about backslash commands
    2701             :  */
    2702             : static backslashResult
    2703           0 : exec_command_slash_command_help(PsqlScanState scan_state, bool active_branch)
    2704             : {
    2705           0 :     if (active_branch)
    2706             :     {
    2707           0 :         char       *opt0 = psql_scan_slash_option(scan_state,
    2708             :                                                   OT_NORMAL, NULL, false);
    2709             : 
    2710           0 :         if (!opt0 || strcmp(opt0, "commands") == 0)
    2711           0 :             slashUsage(pset.popt.topt.pager);
    2712           0 :         else if (strcmp(opt0, "options") == 0)
    2713           0 :             usage(pset.popt.topt.pager);
    2714           0 :         else if (strcmp(opt0, "variables") == 0)
    2715           0 :             helpVariables(pset.popt.topt.pager);
    2716             :         else
    2717           0 :             slashUsage(pset.popt.topt.pager);
    2718             : 
    2719           0 :         if (opt0)
    2720           0 :             free(opt0);
    2721             :     }
    2722             :     else
    2723           0 :         ignore_slash_options(scan_state);
    2724             : 
    2725           0 :     return PSQL_CMD_SKIP_LINE;
    2726             : }
    2727             : 
    2728             : 
    2729             : /*
    2730             :  * Read and interpret an argument to the \connect slash command.
    2731             :  *
    2732             :  * Returns a malloc'd string, or NULL if no/empty argument.
    2733             :  */
    2734             : static char *
    2735         132 : read_connect_arg(PsqlScanState scan_state)
    2736             : {
    2737             :     char       *result;
    2738             :     char        quote;
    2739             : 
    2740             :     /*
    2741             :      * Ideally we should treat the arguments as SQL identifiers.  But for
    2742             :      * backwards compatibility with 7.2 and older pg_dump files, we have to
    2743             :      * take unquoted arguments verbatim (don't downcase them). For now,
    2744             :      * double-quoted arguments may be stripped of double quotes (as if SQL
    2745             :      * identifiers).  By 7.4 or so, pg_dump files can be expected to
    2746             :      * double-quote all mixed-case \connect arguments, and then we can get rid
    2747             :      * of OT_SQLIDHACK.
    2748             :      */
    2749         132 :     result = psql_scan_slash_option(scan_state, OT_SQLIDHACK, &quote, true);
    2750             : 
    2751         132 :     if (!result)
    2752         108 :         return NULL;
    2753             : 
    2754          24 :     if (quote)
    2755           0 :         return result;
    2756             : 
    2757          24 :     if (*result == '\0' || strcmp(result, "-") == 0)
    2758             :     {
    2759          24 :         free(result);
    2760          24 :         return NULL;
    2761             :     }
    2762             : 
    2763           0 :     return result;
    2764             : }
    2765             : 
    2766             : /*
    2767             :  * Read a boolean expression, return it as a PQExpBuffer string.
    2768             :  *
    2769             :  * Note: anything more or less than one token will certainly fail to be
    2770             :  * parsed by ParseVariableBool, so we don't worry about complaining here.
    2771             :  * This routine's return data structure will need to be rethought anyway
    2772             :  * to support likely future extensions such as "\if defined VARNAME".
    2773             :  */
    2774             : static PQExpBuffer
    2775          20 : gather_boolean_expression(PsqlScanState scan_state)
    2776             : {
    2777          20 :     PQExpBuffer exp_buf = createPQExpBuffer();
    2778          20 :     int         num_options = 0;
    2779             :     char       *value;
    2780             : 
    2781             :     /* collect all arguments for the conditional command into exp_buf */
    2782          62 :     while ((value = psql_scan_slash_option(scan_state,
    2783             :                                            OT_NORMAL, NULL, false)) != NULL)
    2784             :     {
    2785             :         /* add spaces between tokens */
    2786          22 :         if (num_options > 0)
    2787           2 :             appendPQExpBufferChar(exp_buf, ' ');
    2788          22 :         appendPQExpBufferStr(exp_buf, value);
    2789          22 :         num_options++;
    2790          22 :         free(value);
    2791             :     }
    2792             : 
    2793          20 :     return exp_buf;
    2794             : }
    2795             : 
    2796             : /*
    2797             :  * Read a boolean expression, return true if the expression
    2798             :  * was a valid boolean expression that evaluated to true.
    2799             :  * Otherwise return false.
    2800             :  *
    2801             :  * Note: conditional stack's top state must be active, else lexer will
    2802             :  * fail to expand variables and backticks.
    2803             :  */
    2804             : static bool
    2805          19 : is_true_boolean_expression(PsqlScanState scan_state, const char *name)
    2806             : {
    2807          19 :     PQExpBuffer buf = gather_boolean_expression(scan_state);
    2808          19 :     bool        value = false;
    2809          19 :     bool        success = ParseVariableBool(buf->data, name, &value);
    2810             : 
    2811          19 :     destroyPQExpBuffer(buf);
    2812          19 :     return success && value;
    2813             : }
    2814             : 
    2815             : /*
    2816             :  * Read a boolean expression, but do nothing with it.
    2817             :  *
    2818             :  * Note: conditional stack's top state must be INACTIVE, else lexer will
    2819             :  * expand variables and backticks, which we do not want here.
    2820             :  */
    2821             : static void
    2822           1 : ignore_boolean_expression(PsqlScanState scan_state)
    2823             : {
    2824           1 :     PQExpBuffer buf = gather_boolean_expression(scan_state);
    2825             : 
    2826           1 :     destroyPQExpBuffer(buf);
    2827           1 : }
    2828             : 
    2829             : /*
    2830             :  * Read and discard "normal" slash command options.
    2831             :  *
    2832             :  * This should be used for inactive-branch processing of any slash command
    2833             :  * that eats one or more OT_NORMAL, OT_SQLID, or OT_SQLIDHACK parameters.
    2834             :  * We don't need to worry about exactly how many it would eat, since the
    2835             :  * cleanup logic in HandleSlashCmds would silently discard any extras anyway.
    2836             :  */
    2837             : static void
    2838          37 : ignore_slash_options(PsqlScanState scan_state)
    2839             : {
    2840             :     char       *arg;
    2841             : 
    2842         136 :     while ((arg = psql_scan_slash_option(scan_state,
    2843             :                                          OT_NORMAL, NULL, false)) != NULL)
    2844          62 :         free(arg);
    2845          37 : }
    2846             : 
    2847             : /*
    2848             :  * Read and discard FILEPIPE slash command argument.
    2849             :  *
    2850             :  * This *MUST* be used for inactive-branch processing of any slash command
    2851             :  * that takes an OT_FILEPIPE option.  Otherwise we might consume a different
    2852             :  * amount of option text in active and inactive cases.
    2853             :  */
    2854             : static void
    2855           5 : ignore_slash_filepipe(PsqlScanState scan_state)
    2856             : {
    2857           5 :     char       *arg = psql_scan_slash_option(scan_state,
    2858             :                                              OT_FILEPIPE, NULL, false);
    2859             : 
    2860           5 :     if (arg)
    2861           5 :         free(arg);
    2862           5 : }
    2863             : 
    2864             : /*
    2865             :  * Read and discard whole-line slash command argument.
    2866             :  *
    2867             :  * This *MUST* be used for inactive-branch processing of any slash command
    2868             :  * that takes an OT_WHOLE_LINE option.  Otherwise we might consume a different
    2869             :  * amount of option text in active and inactive cases.
    2870             :  */
    2871             : static void
    2872           7 : ignore_slash_whole_line(PsqlScanState scan_state)
    2873             : {
    2874           7 :     char       *arg = psql_scan_slash_option(scan_state,
    2875             :                                              OT_WHOLE_LINE, NULL, false);
    2876             : 
    2877           7 :     if (arg)
    2878           7 :         free(arg);
    2879           7 : }
    2880             : 
    2881             : /*
    2882             :  * Return true if the command given is a branching command.
    2883             :  */
    2884             : static bool
    2885           0 : is_branching_command(const char *cmd)
    2886             : {
    2887           0 :     return (strcmp(cmd, "if") == 0 ||
    2888           0 :             strcmp(cmd, "elif") == 0 ||
    2889           0 :             strcmp(cmd, "else") == 0 ||
    2890           0 :             strcmp(cmd, "endif") == 0);
    2891             : }
    2892             : 
    2893             : /*
    2894             :  * Prepare to possibly restore query buffer to its current state
    2895             :  * (cf. discard_query_text).
    2896             :  *
    2897             :  * We need to remember the length of the query buffer, and the lexer's
    2898             :  * notion of the parenthesis nesting depth.
    2899             :  */
    2900             : static void
    2901          25 : save_query_text_state(PsqlScanState scan_state, ConditionalStack cstack,
    2902             :                       PQExpBuffer query_buf)
    2903             : {
    2904          25 :     if (query_buf)
    2905          25 :         conditional_stack_set_query_len(cstack, query_buf->len);
    2906          25 :     conditional_stack_set_paren_depth(cstack,
    2907             :                                       psql_scan_get_paren_depth(scan_state));
    2908          25 : }
    2909             : 
    2910             : /*
    2911             :  * Discard any query text absorbed during an inactive conditional branch.
    2912             :  *
    2913             :  * We must discard data that was appended to query_buf during an inactive
    2914             :  * \if branch.  We don't have to do anything there if there's no query_buf.
    2915             :  *
    2916             :  * Also, reset the lexer state to the same paren depth there was before.
    2917             :  * (The rest of its state doesn't need attention, since we could not be
    2918             :  * inside a comment or literal or partial token.)
    2919             :  */
    2920             : static void
    2921          21 : discard_query_text(PsqlScanState scan_state, ConditionalStack cstack,
    2922             :                    PQExpBuffer query_buf)
    2923             : {
    2924          21 :     if (query_buf)
    2925             :     {
    2926          21 :         int         new_len = conditional_stack_get_query_len(cstack);
    2927             : 
    2928          21 :         Assert(new_len >= 0 && new_len <= query_buf->len);
    2929          21 :         query_buf->len = new_len;
    2930          21 :         query_buf->data[new_len] = '\0';
    2931             :     }
    2932          21 :     psql_scan_set_paren_depth(scan_state,
    2933             :                               conditional_stack_get_paren_depth(cstack));
    2934          21 : }
    2935             : 
    2936             : /*
    2937             :  * If query_buf is empty, copy previous_buf into it.
    2938             :  *
    2939             :  * This is used by various slash commands for which re-execution of a
    2940             :  * previous query is a common usage.  For convenience, we allow the
    2941             :  * case of query_buf == NULL (and do nothing).
    2942             :  */
    2943             : static void
    2944          56 : copy_previous_query(PQExpBuffer query_buf, PQExpBuffer previous_buf)
    2945             : {
    2946          56 :     if (query_buf && query_buf->len == 0)
    2947           8 :         appendPQExpBufferStr(query_buf, previous_buf->data);
    2948          56 : }
    2949             : 
    2950             : /*
    2951             :  * Ask the user for a password; 'username' is the username the
    2952             :  * password is for, if one has been explicitly specified. Returns a
    2953             :  * malloc'd string.
    2954             :  */
    2955             : static char *
    2956           0 : prompt_for_password(const char *username)
    2957             : {
    2958             :     char        buf[100];
    2959             : 
    2960           0 :     if (username == NULL)
    2961           0 :         simple_prompt("Password: ", buf, sizeof(buf), false);
    2962             :     else
    2963             :     {
    2964             :         char       *prompt_text;
    2965             : 
    2966           0 :         prompt_text = psprintf(_("Password for user %s: "), username);
    2967           0 :         simple_prompt(prompt_text, buf, sizeof(buf), false);
    2968           0 :         free(prompt_text);
    2969             :     }
    2970           0 :     return pg_strdup(buf);
    2971             : }
    2972             : 
    2973             : static bool
    2974           0 : param_is_newly_set(const char *old_val, const char *new_val)
    2975             : {
    2976           0 :     if (new_val == NULL)
    2977           0 :         return false;
    2978             : 
    2979           0 :     if (old_val == NULL || strcmp(old_val, new_val) != 0)
    2980           0 :         return true;
    2981             : 
    2982           0 :     return false;
    2983             : }
    2984             : 
    2985             : /*
    2986             :  * do_connect -- handler for \connect
    2987             :  *
    2988             :  * Connects to a database with given parameters. Absent an established
    2989             :  * connection, all parameters are required. Given -reuse-previous=off or a
    2990             :  * connection string without -reuse-previous=on, NULL values will pass through
    2991             :  * to PQconnectdbParams(), so the libpq defaults will be used. Otherwise, NULL
    2992             :  * values will be replaced with the ones in the current connection.
    2993             :  *
    2994             :  * In interactive mode, if connection fails with the given parameters,
    2995             :  * the old connection will be kept.
    2996             :  */
    2997             : static bool
    2998          33 : do_connect(enum trivalue reuse_previous_specification,
    2999             :            char *dbname, char *user, char *host, char *port)
    3000             : {
    3001          33 :     PGconn     *o_conn = pset.db,
    3002             :                *n_conn;
    3003          33 :     char       *password = NULL;
    3004             :     bool        keep_password;
    3005             :     bool        has_connection_string;
    3006             :     bool        reuse_previous;
    3007             :     PQExpBufferData connstr;
    3008             : 
    3009          33 :     if (!o_conn && (!dbname || !user || !host || !port))
    3010             :     {
    3011             :         /*
    3012             :          * We don't know the supplied connection parameters and don't want to
    3013             :          * connect to the wrong database by using defaults, so require all
    3014             :          * parameters to be specified.
    3015             :          */
    3016           0 :         psql_error("All connection parameters must be supplied because no "
    3017             :                    "database connection exists\n");
    3018           0 :         return false;
    3019             :     }
    3020             : 
    3021          33 :     has_connection_string = dbname ?
    3022             :         recognized_connection_string(dbname) : false;
    3023          33 :     switch (reuse_previous_specification)
    3024             :     {
    3025             :         case TRI_YES:
    3026           0 :             reuse_previous = true;
    3027           0 :             break;
    3028             :         case TRI_NO:
    3029           0 :             reuse_previous = false;
    3030           0 :             break;
    3031             :         default:
    3032          33 :             reuse_previous = !has_connection_string;
    3033          33 :             break;
    3034             :     }
    3035             :     /* Silently ignore arguments subsequent to a connection string. */
    3036          33 :     if (has_connection_string)
    3037             :     {
    3038           0 :         user = NULL;
    3039           0 :         host = NULL;
    3040           0 :         port = NULL;
    3041             :     }
    3042             : 
    3043             :     /* grab missing values from the old connection */
    3044          33 :     if (!user && reuse_previous)
    3045          33 :         user = PQuser(o_conn);
    3046          33 :     if (!host && reuse_previous)
    3047          33 :         host = PQhost(o_conn);
    3048          33 :     if (!port && reuse_previous)
    3049          33 :         port = PQport(o_conn);
    3050             : 
    3051             :     /*
    3052             :      * Any change in the parameters read above makes us discard the password.
    3053             :      * We also discard it if we're to use a conninfo rather than the
    3054             :      * positional syntax.
    3055             :      */
    3056          33 :     if (has_connection_string)
    3057           0 :         keep_password = false;
    3058             :     else
    3059          33 :         keep_password =
    3060          33 :             (user && PQuser(o_conn) && strcmp(user, PQuser(o_conn)) == 0) &&
    3061          99 :             (host && PQhost(o_conn) && strcmp(host, PQhost(o_conn)) == 0) &&
    3062          33 :             (port && PQport(o_conn) && strcmp(port, PQport(o_conn)) == 0);
    3063             : 
    3064             :     /*
    3065             :      * Grab missing dbname from old connection.  No password discard if this
    3066             :      * changes: passwords aren't (usually) database-specific.
    3067             :      */
    3068          33 :     if (!dbname && reuse_previous)
    3069             :     {
    3070          33 :         initPQExpBuffer(&connstr);
    3071          33 :         appendPQExpBuffer(&connstr, "dbname=");
    3072          33 :         appendConnStrVal(&connstr, PQdb(o_conn));
    3073          33 :         dbname = connstr.data;
    3074             :         /* has_connection_string=true would be a dead store */
    3075             :     }
    3076             :     else
    3077           0 :         connstr.data = NULL;
    3078             : 
    3079             :     /*
    3080             :      * If the user asked to be prompted for a password, ask for one now. If
    3081             :      * not, use the password from the old connection, provided the username
    3082             :      * etc have not changed. Otherwise, try to connect without a password
    3083             :      * first, and then ask for a password if needed.
    3084             :      *
    3085             :      * XXX: this behavior leads to spurious connection attempts recorded in
    3086             :      * the postmaster's log.  But libpq offers no API that would let us obtain
    3087             :      * a password and then continue with the first connection attempt.
    3088             :      */
    3089          33 :     if (pset.getPassword == TRI_YES)
    3090             :     {
    3091           0 :         password = prompt_for_password(user);
    3092             :     }
    3093          33 :     else if (o_conn && keep_password)
    3094             :     {
    3095          33 :         password = PQpass(o_conn);
    3096          33 :         if (password && *password)
    3097           0 :             password = pg_strdup(password);
    3098             :         else
    3099          33 :             password = NULL;
    3100             :     }
    3101             : 
    3102             :     while (true)
    3103             :     {
    3104             : #define PARAMS_ARRAY_SIZE   8
    3105          33 :         const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
    3106          33 :         const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
    3107          33 :         int         paramnum = -1;
    3108             : 
    3109          33 :         keywords[++paramnum] = "host";
    3110          33 :         values[paramnum] = host;
    3111          33 :         keywords[++paramnum] = "port";
    3112          33 :         values[paramnum] = port;
    3113          33 :         keywords[++paramnum] = "user";
    3114          33 :         values[paramnum] = user;
    3115             : 
    3116             :         /*
    3117             :          * Position in the array matters when the dbname is a connection
    3118             :          * string, because settings in a connection string override earlier
    3119             :          * array entries only.  Thus, user= in the connection string always
    3120             :          * takes effect, but client_encoding= often will not.
    3121             :          *
    3122             :          * If you change this code, also change the initial-connection code in
    3123             :          * main().  For no good reason, a connection string password= takes
    3124             :          * precedence in main() but not here.
    3125             :          */
    3126          33 :         keywords[++paramnum] = "dbname";
    3127          33 :         values[paramnum] = dbname;
    3128          33 :         keywords[++paramnum] = "password";
    3129          33 :         values[paramnum] = password;
    3130          33 :         keywords[++paramnum] = "fallback_application_name";
    3131          33 :         values[paramnum] = pset.progname;
    3132          33 :         keywords[++paramnum] = "client_encoding";
    3133          33 :         values[paramnum] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
    3134             : 
    3135             :         /* add array terminator */
    3136          33 :         keywords[++paramnum] = NULL;
    3137          33 :         values[paramnum] = NULL;
    3138             : 
    3139          33 :         n_conn = PQconnectdbParams(keywords, values, true);
    3140             : 
    3141          33 :         pg_free(keywords);
    3142          33 :         pg_free(values);
    3143             : 
    3144             :         /* We can immediately discard the password -- no longer needed */
    3145          33 :         if (password)
    3146           0 :             pg_free(password);
    3147             : 
    3148          33 :         if (PQstatus(n_conn) == CONNECTION_OK)
    3149          33 :             break;
    3150             : 
    3151             :         /*
    3152             :          * Connection attempt failed; either retry the connection attempt with
    3153             :          * a new password, or give up.
    3154             :          */
    3155           0 :         if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
    3156             :         {
    3157           0 :             PQfinish(n_conn);
    3158           0 :             password = prompt_for_password(user);
    3159           0 :             continue;
    3160             :         }
    3161             : 
    3162             :         /*
    3163             :          * Failed to connect to the database. In interactive mode, keep the
    3164             :          * previous connection to the DB; in scripting mode, close our
    3165             :          * previous connection as well.
    3166             :          */
    3167           0 :         if (pset.cur_cmd_interactive)
    3168             :         {
    3169           0 :             psql_error("%s", PQerrorMessage(n_conn));
    3170             : 
    3171             :             /* pset.db is left unmodified */
    3172           0 :             if (o_conn)
    3173           0 :                 psql_error("Previous connection kept\n");
    3174             :         }
    3175             :         else
    3176             :         {
    3177           0 :             psql_error("\\connect: %s", PQerrorMessage(n_conn));
    3178           0 :             if (o_conn)
    3179             :             {
    3180           0 :                 PQfinish(o_conn);
    3181           0 :                 pset.db = NULL;
    3182             :             }
    3183             :         }
    3184             : 
    3185           0 :         PQfinish(n_conn);
    3186           0 :         if (connstr.data)
    3187           0 :             termPQExpBuffer(&connstr);
    3188           0 :         return false;
    3189           0 :     }
    3190          33 :     if (connstr.data)
    3191          33 :         termPQExpBuffer(&connstr);
    3192             : 
    3193             :     /*
    3194             :      * Replace the old connection with the new one, and update
    3195             :      * connection-dependent variables.
    3196             :      */
    3197          33 :     PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
    3198          33 :     pset.db = n_conn;
    3199          33 :     SyncVariables();
    3200          33 :     connection_warnings(false); /* Must be after SyncVariables */
    3201             : 
    3202             :     /* Tell the user about the new connection */
    3203          33 :     if (!pset.quiet)
    3204             :     {
    3205           0 :         if (!o_conn ||
    3206           0 :             param_is_newly_set(PQhost(o_conn), PQhost(pset.db)) ||
    3207           0 :             param_is_newly_set(PQport(o_conn), PQport(pset.db)))
    3208           0 :         {
    3209           0 :             char       *host = PQhost(pset.db);
    3210             : 
    3211             :             /* If the host is an absolute path, the connection is via socket */
    3212           0 :             if (is_absolute_path(host))
    3213           0 :                 printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
    3214           0 :                        PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
    3215             :             else
    3216           0 :                 printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
    3217           0 :                        PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
    3218             :         }
    3219             :         else
    3220           0 :             printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
    3221           0 :                    PQdb(pset.db), PQuser(pset.db));
    3222             :     }
    3223             : 
    3224          33 :     if (o_conn)
    3225          33 :         PQfinish(o_conn);
    3226          33 :     return true;
    3227             : }
    3228             : 
    3229             : 
    3230             : void
    3231          33 : connection_warnings(bool in_startup)
    3232             : {
    3233          33 :     if (!pset.quiet && !pset.notty)
    3234             :     {
    3235           0 :         int         client_ver = PG_VERSION_NUM;
    3236             :         char        cverbuf[32];
    3237             :         char        sverbuf[32];
    3238             : 
    3239           0 :         if (pset.sversion != client_ver)
    3240             :         {
    3241             :             const char *server_version;
    3242             : 
    3243             :             /* Try to get full text form, might include "devel" etc */
    3244           0 :             server_version = PQparameterStatus(pset.db, "server_version");
    3245             :             /* Otherwise fall back on pset.sversion */
    3246           0 :             if (!server_version)
    3247             :             {
    3248           0 :                 formatPGVersionNumber(pset.sversion, true,
    3249             :                                       sverbuf, sizeof(sverbuf));
    3250           0 :                 server_version = sverbuf;
    3251             :             }
    3252             : 
    3253           0 :             printf(_("%s (%s, server %s)\n"),
    3254             :                    pset.progname, PG_VERSION, server_version);
    3255             :         }
    3256             :         /* For version match, only print psql banner on startup. */
    3257           0 :         else if (in_startup)
    3258           0 :             printf("%s (%s)\n", pset.progname, PG_VERSION);
    3259             : 
    3260           0 :         if (pset.sversion / 100 > client_ver / 100)
    3261           0 :             printf(_("WARNING: %s major version %s, server major version %s.\n"
    3262             :                      "         Some psql features might not work.\n"),
    3263             :                    pset.progname,
    3264             :                    formatPGVersionNumber(client_ver, false,
    3265             :                                          cverbuf, sizeof(cverbuf)),
    3266             :                    formatPGVersionNumber(pset.sversion, false,
    3267             :                                          sverbuf, sizeof(sverbuf)));
    3268             : 
    3269             : #ifdef WIN32
    3270             :         checkWin32Codepage();
    3271             : #endif
    3272           0 :         printSSLInfo();
    3273             :     }
    3274          33 : }
    3275             : 
    3276             : 
    3277             : /*
    3278             :  * printSSLInfo
    3279             :  *
    3280             :  * Prints information about the current SSL connection, if SSL is in use
    3281             :  */
    3282             : static void
    3283           0 : printSSLInfo(void)
    3284             : {
    3285             :     const char *protocol;
    3286             :     const char *cipher;
    3287             :     const char *bits;
    3288             :     const char *compression;
    3289             : 
    3290           0 :     if (!PQsslInUse(pset.db))
    3291           0 :         return;                 /* no SSL */
    3292             : 
    3293           0 :     protocol = PQsslAttribute(pset.db, "protocol");
    3294           0 :     cipher = PQsslAttribute(pset.db, "cipher");
    3295           0 :     bits = PQsslAttribute(pset.db, "key_bits");
    3296           0 :     compression = PQsslAttribute(pset.db, "compression");
    3297             : 
    3298           0 :     printf(_("SSL connection (protocol: %s, cipher: %s, bits: %s, compression: %s)\n"),
    3299             :            protocol ? protocol : _("unknown"),
    3300             :            cipher ? cipher : _("unknown"),
    3301             :            bits ? bits : _("unknown"),
    3302           0 :            (compression && strcmp(compression, "off") != 0) ? _("on") : _("off"));
    3303             : }
    3304             : 
    3305             : 
    3306             : /*
    3307             :  * checkWin32Codepage
    3308             :  *
    3309             :  * Prints a warning when win32 console codepage differs from Windows codepage
    3310             :  */
    3311             : #ifdef WIN32
    3312             : static void
    3313             : checkWin32Codepage(void)
    3314             : {
    3315             :     unsigned int wincp,
    3316             :                 concp;
    3317             : 
    3318             :     wincp = GetACP();
    3319             :     concp = GetConsoleCP();
    3320             :     if (wincp != concp)
    3321             :     {
    3322             :         printf(_("WARNING: Console code page (%u) differs from Windows code page (%u)\n"
    3323             :                  "         8-bit characters might not work correctly. See psql reference\n"
    3324             :                  "         page \"Notes for Windows users\" for details.\n"),
    3325             :                concp, wincp);
    3326             :     }
    3327             : }
    3328             : #endif
    3329             : 
    3330             : 
    3331             : /*
    3332             :  * SyncVariables
    3333             :  *
    3334             :  * Make psql's internal variables agree with connection state upon
    3335             :  * establishing a new connection.
    3336             :  */
    3337             : void
    3338         215 : SyncVariables(void)
    3339             : {
    3340             :     /* get stuff from connection */
    3341         215 :     pset.encoding = PQclientEncoding(pset.db);
    3342         215 :     pset.popt.topt.encoding = pset.encoding;
    3343         215 :     pset.sversion = PQserverVersion(pset.db);
    3344             : 
    3345         215 :     SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
    3346         215 :     SetVariable(pset.vars, "USER", PQuser(pset.db));
    3347         215 :     SetVariable(pset.vars, "HOST", PQhost(pset.db));
    3348         215 :     SetVariable(pset.vars, "PORT", PQport(pset.db));
    3349         215 :     SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
    3350             : 
    3351             :     /* send stuff to it, too */
    3352         215 :     PQsetErrorVerbosity(pset.db, pset.verbosity);
    3353         215 :     PQsetErrorContextVisibility(pset.db, pset.show_context);
    3354         215 : }
    3355             : 
    3356             : /*
    3357             :  * UnsyncVariables
    3358             :  *
    3359             :  * Clear variables that should be not be set when there is no connection.
    3360             :  */
    3361             : void
    3362           0 : UnsyncVariables(void)
    3363             : {
    3364           0 :     SetVariable(pset.vars, "DBNAME", NULL);
    3365           0 :     SetVariable(pset.vars, "USER", NULL);
    3366           0 :     SetVariable(pset.vars, "HOST", NULL);
    3367           0 :     SetVariable(pset.vars, "PORT", NULL);
    3368           0 :     SetVariable(pset.vars, "ENCODING", NULL);
    3369           0 : }
    3370             : 
    3371             : 
    3372             : /*
    3373             :  * do_edit -- handler for \e
    3374             :  *
    3375             :  * If you do not specify a filename, the current query buffer will be copied
    3376             :  * into a temporary one.
    3377             :  */
    3378             : static bool
    3379           0 : editFile(const char *fname, int lineno)
    3380             : {
    3381             :     const char *editorName;
    3382           0 :     const char *editor_lineno_arg = NULL;
    3383             :     char       *sys;
    3384             :     int         result;
    3385             : 
    3386           0 :     Assert(fname != NULL);
    3387             : 
    3388             :     /* Find an editor to use */
    3389           0 :     editorName = getenv("PSQL_EDITOR");
    3390           0 :     if (!editorName)
    3391           0 :         editorName = getenv("EDITOR");
    3392           0 :     if (!editorName)
    3393           0 :         editorName = getenv("VISUAL");
    3394           0 :     if (!editorName)
    3395           0 :         editorName = DEFAULT_EDITOR;
    3396             : 
    3397             :     /* Get line number argument, if we need it. */
    3398           0 :     if (lineno > 0)
    3399             :     {
    3400           0 :         editor_lineno_arg = getenv("PSQL_EDITOR_LINENUMBER_ARG");
    3401             : #ifdef DEFAULT_EDITOR_LINENUMBER_ARG
    3402           0 :         if (!editor_lineno_arg)
    3403           0 :             editor_lineno_arg = DEFAULT_EDITOR_LINENUMBER_ARG;
    3404             : #endif
    3405           0 :         if (!editor_lineno_arg)
    3406             :         {
    3407           0 :             psql_error("environment variable PSQL_EDITOR_LINENUMBER_ARG must be set to specify a line number\n");
    3408           0 :             return false;
    3409             :         }
    3410             :     }
    3411             : 
    3412             :     /*
    3413             :      * On Unix the EDITOR value should *not* be quoted, since it might include
    3414             :      * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
    3415             :      * if necessary.  But this policy is not very workable on Windows, due to
    3416             :      * severe brain damage in their command shell plus the fact that standard
    3417             :      * program paths include spaces.
    3418             :      */
    3419             : #ifndef WIN32
    3420           0 :     if (lineno > 0)
    3421           0 :         sys = psprintf("exec %s %s%d '%s'",
    3422             :                        editorName, editor_lineno_arg, lineno, fname);
    3423             :     else
    3424           0 :         sys = psprintf("exec %s '%s'",
    3425             :                        editorName, fname);
    3426             : #else
    3427             :     if (lineno > 0)
    3428             :         sys = psprintf("\"%s\" %s%d \"%s\"",
    3429             :                        editorName, editor_lineno_arg, lineno, fname);
    3430             :     else
    3431             :         sys = psprintf("\"%s\" \"%s\"",
    3432             :                        editorName, fname);
    3433             : #endif
    3434           0 :     result = system(sys);
    3435           0 :     if (result == -1)
    3436           0 :         psql_error("could not start editor \"%s\"\n", editorName);
    3437           0 :     else if (result == 127)
    3438           0 :         psql_error("could not start /bin/sh\n");
    3439           0 :     free(sys);
    3440             : 
    3441           0 :     return result == 0;
    3442             : }
    3443             : 
    3444             : 
    3445             : /* call this one */
    3446             : static bool
    3447           0 : do_edit(const char *filename_arg, PQExpBuffer query_buf,
    3448             :         int lineno, bool *edited)
    3449             : {
    3450             :     char        fnametmp[MAXPGPATH];
    3451           0 :     FILE       *stream = NULL;
    3452             :     const char *fname;
    3453           0 :     bool        error = false;
    3454             :     int         fd;
    3455             : 
    3456             :     struct stat before,
    3457             :                 after;
    3458             : 
    3459           0 :     if (filename_arg)
    3460           0 :         fname = filename_arg;
    3461             :     else
    3462             :     {
    3463             :         /* make a temp file to edit */
    3464             : #ifndef WIN32
    3465           0 :         const char *tmpdir = getenv("TMPDIR");
    3466             : 
    3467           0 :         if (!tmpdir)
    3468           0 :             tmpdir = "/tmp";
    3469             : #else
    3470             :         char        tmpdir[MAXPGPATH];
    3471             :         int         ret;
    3472             : 
    3473             :         ret = GetTempPath(MAXPGPATH, tmpdir);
    3474             :         if (ret == 0 || ret > MAXPGPATH)
    3475             :         {
    3476             :             psql_error("could not locate temporary directory: %s\n",
    3477             :                        !ret ? strerror(errno) : "");
    3478             :             return false;
    3479             :         }
    3480             : 
    3481             :         /*
    3482             :          * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
    3483             :          * current directory to the supplied path unless we use only
    3484             :          * backslashes, so we do that.
    3485             :          */
    3486             : #endif
    3487             : #ifndef WIN32
    3488           0 :         snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
    3489             :                  "/", (int) getpid());
    3490             : #else
    3491             :         snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
    3492             :                  "" /* trailing separator already present */ , (int) getpid());
    3493             : #endif
    3494             : 
    3495           0 :         fname = (const char *) fnametmp;
    3496             : 
    3497           0 :         fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
    3498           0 :         if (fd != -1)
    3499           0 :             stream = fdopen(fd, "w");
    3500             : 
    3501           0 :         if (fd == -1 || !stream)
    3502             :         {
    3503           0 :             psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
    3504           0 :             error = true;
    3505             :         }
    3506             :         else
    3507             :         {
    3508           0 :             unsigned int ql = query_buf->len;
    3509             : 
    3510           0 :             if (ql == 0 || query_buf->data[ql - 1] != '\n')
    3511             :             {
    3512           0 :                 appendPQExpBufferChar(query_buf, '\n');
    3513           0 :                 ql++;
    3514             :             }
    3515             : 
    3516           0 :             if (fwrite(query_buf->data, 1, ql, stream) != ql)
    3517             :             {
    3518           0 :                 psql_error("%s: %s\n", fname, strerror(errno));
    3519             : 
    3520           0 :                 if (fclose(stream) != 0)
    3521           0 :                     psql_error("%s: %s\n", fname, strerror(errno));
    3522             : 
    3523           0 :                 if (remove(fname) != 0)
    3524           0 :                     psql_error("%s: %s\n", fname, strerror(errno));
    3525             : 
    3526           0 :                 error = true;
    3527             :             }
    3528           0 :             else if (fclose(stream) != 0)
    3529             :             {
    3530           0 :                 psql_error("%s: %s\n", fname, strerror(errno));
    3531           0 :                 if (remove(fname) != 0)
    3532           0 :                     psql_error("%s: %s\n", fname, strerror(errno));
    3533           0 :                 error = true;
    3534             :             }
    3535             :         }
    3536             :     }
    3537             : 
    3538           0 :     if (!error && stat(fname, &before) != 0)
    3539             :     {
    3540           0 :         psql_error("%s: %s\n", fname, strerror(errno));
    3541           0 :         error = true;
    3542             :     }
    3543             : 
    3544             :     /* call editor */
    3545           0 :     if (!error)
    3546           0 :         error = !editFile(fname, lineno);
    3547             : 
    3548           0 :     if (!error && stat(fname, &after) != 0)
    3549             :     {
    3550           0 :         psql_error("%s: %s\n", fname, strerror(errno));
    3551           0 :         error = true;
    3552             :     }
    3553             : 
    3554           0 :     if (!error && before.st_mtime != after.st_mtime)
    3555             :     {
    3556           0 :         stream = fopen(fname, PG_BINARY_R);
    3557           0 :         if (!stream)
    3558             :         {
    3559           0 :             psql_error("%s: %s\n", fname, strerror(errno));
    3560           0 :             error = true;
    3561             :         }
    3562             :         else
    3563             :         {
    3564             :             /* read file back into query_buf */
    3565             :             char        line[1024];
    3566             : 
    3567           0 :             resetPQExpBuffer(query_buf);
    3568           0 :             while (fgets(line, sizeof(line), stream) != NULL)
    3569           0 :                 appendPQExpBufferStr(query_buf, line);
    3570             : 
    3571           0 :             if (ferror(stream))
    3572             :             {
    3573           0 :                 psql_error("%s: %s\n", fname, strerror(errno));
    3574           0 :                 error = true;
    3575             :             }
    3576           0 :             else if (edited)
    3577             :             {
    3578           0 :                 *edited = true;
    3579             :             }
    3580             : 
    3581           0 :             fclose(stream);
    3582             :         }
    3583             :     }
    3584             : 
    3585             :     /* remove temp file */
    3586           0 :     if (!filename_arg)
    3587             :     {
    3588           0 :         if (remove(fname) == -1)
    3589             :         {
    3590           0 :             psql_error("%s: %s\n", fname, strerror(errno));
    3591           0 :             error = true;
    3592             :         }
    3593             :     }
    3594             : 
    3595           0 :     return !error;
    3596             : }
    3597             : 
    3598             : 
    3599             : 
    3600             : /*
    3601             :  * process_file
    3602             :  *
    3603             :  * Reads commands from filename and passes them to the main processing loop.
    3604             :  * Handler for \i and \ir, but can be used for other things as well.  Returns
    3605             :  * MainLoop() error code.
    3606             :  *
    3607             :  * If use_relative_path is true and filename is not an absolute path, then open
    3608             :  * the file from where the currently processed file (if any) is located.
    3609             :  */
    3610             : int
    3611         180 : process_file(char *filename, bool use_relative_path)
    3612             : {
    3613             :     FILE       *fd;
    3614             :     int         result;
    3615             :     char       *oldfilename;
    3616             :     char        relpath[MAXPGPATH];
    3617             : 
    3618         180 :     if (!filename)
    3619             :     {
    3620         180 :         fd = stdin;
    3621         180 :         filename = NULL;
    3622             :     }
    3623           0 :     else if (strcmp(filename, "-") != 0)
    3624             :     {
    3625           0 :         canonicalize_path(filename);
    3626             : 
    3627             :         /*
    3628             :          * If we were asked to resolve the pathname relative to the location
    3629             :          * of the currently executing script, and there is one, and this is a
    3630             :          * relative pathname, then prepend all but the last pathname component
    3631             :          * of the current script to this pathname.
    3632             :          */
    3633           0 :         if (use_relative_path && pset.inputfile &&
    3634           0 :             !is_absolute_path(filename) && !has_drive_prefix(filename))
    3635             :         {
    3636           0 :             strlcpy(relpath, pset.inputfile, sizeof(relpath));
    3637           0 :             get_parent_directory(relpath);
    3638           0 :             join_path_components(relpath, relpath, filename);
    3639           0 :             canonicalize_path(relpath);
    3640             : 
    3641           0 :             filename = relpath;
    3642             :         }
    3643             : 
    3644           0 :         fd = fopen(filename, PG_BINARY_R);
    3645             : 
    3646           0 :         if (!fd)
    3647             :         {
    3648           0 :             psql_error("%s: %s\n", filename, strerror(errno));
    3649           0 :             return EXIT_FAILURE;
    3650             :         }
    3651             :     }
    3652             :     else
    3653             :     {
    3654           0 :         fd = stdin;
    3655           0 :         filename = "<stdin>";   /* for future error messages */
    3656             :     }
    3657             : 
    3658         180 :     oldfilename = pset.inputfile;
    3659         180 :     pset.inputfile = filename;
    3660             : 
    3661         180 :     result = MainLoop(fd);
    3662             : 
    3663         180 :     if (fd != stdin)
    3664           0 :         fclose(fd);
    3665             : 
    3666         180 :     pset.inputfile = oldfilename;
    3667         180 :     return result;
    3668             : }
    3669             : 
    3670             : 
    3671             : 
    3672             : static const char *
    3673           1 : _align2string(enum printFormat in)
    3674             : {
    3675           1 :     switch (in)
    3676             :     {
    3677             :         case PRINT_NOTHING:
    3678           0 :             return "nothing";
    3679             :             break;
    3680             :         case PRINT_UNALIGNED:
    3681           0 :             return "unaligned";
    3682             :             break;
    3683             :         case PRINT_ALIGNED:
    3684           1 :             return "aligned";
    3685             :             break;
    3686             :         case PRINT_WRAPPED:
    3687           0 :             return "wrapped";
    3688             :             break;
    3689             :         case PRINT_HTML:
    3690           0 :             return "html";
    3691             :             break;
    3692             :         case PRINT_ASCIIDOC:
    3693           0 :             return "asciidoc";
    3694             :             break;
    3695             :         case PRINT_LATEX:
    3696           0 :             return "latex";
    3697             :             break;
    3698             :         case PRINT_LATEX_LONGTABLE:
    3699           0 :             return "latex-longtable";
    3700             :             break;
    3701             :         case PRINT_TROFF_MS:
    3702           0 :             return "troff-ms";
    3703             :             break;
    3704             :     }
    3705           0 :     return "unknown";
    3706             : }
    3707             : 
    3708             : /*
    3709             :  * Parse entered Unicode linestyle.  If ok, update *linestyle and return
    3710             :  * true, else return false.
    3711             :  */
    3712             : static bool
    3713           0 : set_unicode_line_style(const char *value, size_t vallen,
    3714             :                        unicode_linestyle *linestyle)
    3715             : {
    3716           0 :     if (pg_strncasecmp("single", value, vallen) == 0)
    3717           0 :         *linestyle = UNICODE_LINESTYLE_SINGLE;
    3718           0 :     else if (pg_strncasecmp("double", value, vallen) == 0)
    3719           0 :         *linestyle = UNICODE_LINESTYLE_DOUBLE;
    3720             :     else
    3721           0 :         return false;
    3722           0 :     return true;
    3723             : }
    3724             : 
    3725             : static const char *
    3726           3 : _unicode_linestyle2string(int linestyle)
    3727             : {
    3728           3 :     switch (linestyle)
    3729             :     {
    3730             :         case UNICODE_LINESTYLE_SINGLE:
    3731           3 :             return "single";
    3732             :             break;
    3733             :         case UNICODE_LINESTYLE_DOUBLE:
    3734           0 :             return "double";
    3735             :             break;
    3736             :     }
    3737           0 :     return "unknown";
    3738             : }
    3739             : 
    3740             : /*
    3741             :  * do_pset
    3742             :  *
    3743             :  */
    3744             : bool
    3745         161 : do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
    3746             : {
    3747         161 :     size_t      vallen = 0;
    3748             : 
    3749         161 :     Assert(param != NULL);
    3750             : 
    3751         161 :     if (value)
    3752         155 :         vallen = strlen(value);
    3753             : 
    3754             :     /* set format */
    3755         161 :     if (strcmp(param, "format") == 0)
    3756             :     {
    3757          89 :         if (!value)
    3758             :             ;
    3759          89 :         else if (pg_strncasecmp("unaligned", value, vallen) == 0)
    3760          30 :             popt->topt.format = PRINT_UNALIGNED;
    3761          59 :         else if (pg_strncasecmp("aligned", value, vallen) == 0)
    3762          31 :             popt->topt.format = PRINT_ALIGNED;
    3763          28 :         else if (pg_strncasecmp("wrapped", value, vallen) == 0)
    3764          27 :             popt->topt.format = PRINT_WRAPPED;
    3765           1 :         else if (pg_strncasecmp("html", value, vallen) == 0)
    3766           0 :             popt->topt.format = PRINT_HTML;
    3767           1 :         else if (pg_strncasecmp("asciidoc", value, vallen) == 0)
    3768           1 :             popt->topt.format = PRINT_ASCIIDOC;
    3769           0 :         else if (pg_strncasecmp("latex", value, vallen) == 0)
    3770           0 :             popt->topt.format = PRINT_LATEX;
    3771           0 :         else if (pg_strncasecmp("latex-longtable", value, vallen) == 0)
    3772           0 :             popt->topt.format = PRINT_LATEX_LONGTABLE;
    3773           0 :         else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
    3774           0 :             popt->topt.format = PRINT_TROFF_MS;
    3775             :         else
    3776             :         {
    3777           0 :             psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, asciidoc, latex, latex-longtable, troff-ms\n");
    3778           0 :             return false;
    3779             :         }
    3780             :     }
    3781             : 
    3782             :     /* set table line style */
    3783          72 :     else if (strcmp(param, "linestyle") == 0)
    3784             :     {
    3785           5 :         if (!value)
    3786             :             ;
    3787           5 :         else if (pg_strncasecmp("ascii", value, vallen) == 0)
    3788           3 :             popt->topt.line_style = &pg_asciiformat;
    3789           2 :         else if (pg_strncasecmp("old-ascii", value, vallen) == 0)
    3790           2 :             popt->topt.line_style = &pg_asciiformat_old;
    3791           0 :         else if (pg_strncasecmp("unicode", value, vallen) == 0)
    3792           0 :             popt->topt.line_style = &pg_utf8format;
    3793             :         else
    3794             :         {
    3795           0 :             psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode\n");
    3796           0 :             return false;
    3797             :         }
    3798             :     }
    3799             : 
    3800             :     /* set unicode border line style */
    3801          67 :     else if (strcmp(param, "unicode_border_linestyle") == 0)
    3802             :     {
    3803           0 :         if (!value)
    3804             :             ;
    3805           0 :         else if (set_unicode_line_style(value, vallen,
    3806             :                                         &popt->topt.unicode_border_linestyle))
    3807           0 :             refresh_utf8format(&(popt->topt));
    3808             :         else
    3809             :         {
    3810           0 :             psql_error("\\pset: allowed Unicode border line styles are single, double\n");
    3811           0 :             return false;
    3812             :         }
    3813             :     }
    3814             : 
    3815             :     /* set unicode column line style */
    3816          67 :     else if (strcmp(param, "unicode_column_linestyle") == 0)
    3817             :     {
    3818           0 :         if (!value)
    3819             :             ;
    3820           0 :         else if (set_unicode_line_style(value, vallen,
    3821             :                                         &popt->topt.unicode_column_linestyle))
    3822           0 :             refresh_utf8format(&(popt->topt));
    3823             :         else
    3824             :         {
    3825           0 :             psql_error("\\pset: allowed Unicode column line styles are single, double\n");
    3826           0 :             return false;
    3827             :         }
    3828             :     }
    3829             : 
    3830             :     /* set unicode header line style */
    3831          67 :     else if (strcmp(param, "unicode_header_linestyle") == 0)
    3832             :     {
    3833           0 :         if (!value)
    3834             :             ;
    3835           0 :         else if (set_unicode_line_style(value, vallen,
    3836             :                                         &popt->topt.unicode_header_linestyle))
    3837           0 :             refresh_utf8format(&(popt->topt));
    3838             :         else
    3839             :         {
    3840           0 :             psql_error("\\pset: allowed Unicode header line styles are single, double\n");
    3841           0 :             return false;
    3842             :         }
    3843             :     }
    3844             : 
    3845             :     /* set border style/width */
    3846          67 :     else if (strcmp(param, "border") == 0)
    3847             :     {
    3848          34 :         if (value)
    3849          34 :             popt->topt.border = atoi(value);
    3850             :     }
    3851             : 
    3852             :     /* set expanded/vertical mode */
    3853          66 :     else if (strcmp(param, "x") == 0 ||
    3854          54 :              strcmp(param, "expanded") == 0 ||
    3855          21 :              strcmp(param, "vertical") == 0)
    3856             :     {
    3857          24 :         if (value && pg_strcasecmp(value, "auto") == 0)
    3858           0 :             popt->topt.expanded = 2;
    3859          12 :         else if (value)
    3860             :         {
    3861             :             bool        on_off;
    3862             : 
    3863          12 :             if (ParseVariableBool(value, NULL, &on_off))
    3864          12 :                 popt->topt.expanded = on_off ? 1 : 0;
    3865             :             else
    3866             :             {
    3867           0 :                 PsqlVarEnumError(param, value, "on, off, auto");
    3868           0 :                 return false;
    3869             :             }
    3870             :         }
    3871             :         else
    3872           0 :             popt->topt.expanded = !popt->topt.expanded;
    3873             :     }
    3874             : 
    3875             :     /* locale-aware numeric output */
    3876          21 :     else if (strcmp(param, "numericlocale") == 0)
    3877             :     {
    3878           0 :         if (value)
    3879           0 :             return ParseVariableBool(value, param, &popt->topt.numericLocale);
    3880             :         else
    3881           0 :             popt->topt.numericLocale = !popt->topt.numericLocale;
    3882             :     }
    3883             : 
    3884             :     /* null display */
    3885          21 :     else if (strcmp(param, "null") == 0)
    3886             :     {
    3887           6 :         if (value)
    3888             :         {
    3889           6 :             free(popt->nullPrint);
    3890           6 :             popt->nullPrint = pg_strdup(value);
    3891             :         }
    3892             :     }
    3893             : 
    3894             :     /* field separator for unaligned text */
    3895          15 :     else if (strcmp(param, "fieldsep") == 0)
    3896             :     {
    3897           1 :         if (value)
    3898             :         {
    3899           1 :             free(popt->topt.fieldSep.separator);
    3900           1 :             popt->topt.fieldSep.separator = pg_strdup(value);
    3901           1 :             popt->topt.fieldSep.separator_zero = false;
    3902             :         }
    3903             :     }
    3904             : 
    3905          14 :     else if (strcmp(param, "fieldsep_zero") == 0)
    3906             :     {
    3907           0 :         free(popt->topt.fieldSep.separator);
    3908           0 :         popt->topt.fieldSep.separator = NULL;
    3909           0 :         popt->topt.fieldSep.separator_zero = true;
    3910             :     }
    3911             : 
    3912             :     /* record separator for unaligned text */
    3913          14 :     else if (strcmp(param, "recordsep") == 0)
    3914             :     {
    3915           0 :         if (value)
    3916             :         {
    3917           0 :             free(popt->topt.recordSep.separator);
    3918           0 :             popt->topt.recordSep.separator = pg_strdup(value);
    3919           0 :             popt->topt.recordSep.separator_zero = false;
    3920             :         }
    3921             :     }
    3922             : 
    3923          14 :     else if (strcmp(param, "recordsep_zero") == 0)
    3924             :     {
    3925           0 :         free(popt->topt.recordSep.separator);
    3926           0 :         popt->topt.recordSep.separator = NULL;
    3927           0 :         popt->topt.recordSep.separator_zero = true;
    3928             :     }
    3929             : 
    3930             :     /* toggle between full and tuples-only format */
    3931          14 :     else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
    3932             :     {
    3933          12 :         if (value)
    3934           0 :             return ParseVariableBool(value, param, &popt->topt.tuples_only);
    3935             :         else
    3936           6 :             popt->topt.tuples_only = !popt->topt.tuples_only;
    3937             :     }
    3938             : 
    3939             :     /* set title override */
    3940           8 :     else if (strcmp(param, "C") == 0 || strcmp(param, "title") == 0)
    3941             :     {
    3942           0 :         free(popt->title);
    3943           0 :         if (!value)
    3944           0 :             popt->title = NULL;
    3945             :         else
    3946           0 :             popt->title = pg_strdup(value);
    3947             :     }
    3948             : 
    3949             :     /* set HTML table tag options */
    3950           8 :     else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
    3951             :     {
    3952           0 :         free(popt->topt.tableAttr);
    3953           0 :         if (!value)
    3954           0 :             popt->topt.tableAttr = NULL;
    3955             :         else
    3956           0 :             popt->topt.tableAttr = pg_strdup(value);
    3957             :     }
    3958             : 
    3959             :     /* toggle use of pager */
    3960           8 :     else if (strcmp(param, "pager") == 0)
    3961             :     {
    3962           0 :         if (value && pg_strcasecmp(value, "always") == 0)
    3963           0 :             popt->topt.pager = 2;
    3964           0 :         else if (value)
    3965             :         {
    3966             :             bool        on_off;
    3967             : 
    3968           0 :             if (!ParseVariableBool(value, NULL, &on_off))
    3969             :             {
    3970           0 :                 PsqlVarEnumError(param, value, "on, off, always");
    3971           0 :                 return false;
    3972             :             }
    3973           0 :             popt->topt.pager = on_off ? 1 : 0;
    3974             :         }
    3975           0 :         else if (popt->topt.pager == 1)
    3976           0 :             popt->topt.pager = 0;
    3977             :         else
    3978           0 :             popt->topt.pager = 1;
    3979             :     }
    3980             : 
    3981             :     /* set minimum lines for pager use */
    3982           8 :     else if (strcmp(param, "pager_min_lines") == 0)
    3983             :     {
    3984           0 :         if (value)
    3985           0 :             popt->topt.pager_min_lines = atoi(value);
    3986             :     }
    3987             : 
    3988             :     /* disable "(x rows)" footer */
    3989           8 :     else if (strcmp(param, "footer") == 0)
    3990             :     {
    3991           0 :         if (value)
    3992           0 :             return ParseVariableBool(value, param, &popt->topt.default_footer);
    3993             :         else
    3994           0 :             popt->topt.default_footer = !popt->topt.default_footer;
    3995             :     }
    3996             : 
    3997             :     /* set border style/width */
    3998           8 :     else if (strcmp(param, "columns") == 0)
    3999             :     {
    4000           8 :         if (value)
    4001           8 :             popt->topt.columns = atoi(value);
    4002             :     }
    4003             :     else
    4004             :     {
    4005           0 :         psql_error("\\pset: unknown option: %s\n", param);
    4006           0 :         return false;
    4007             :     }
    4008             : 
    4009         161 :     if (!quiet)
    4010           0 :         printPsetInfo(param, &pset.popt);
    4011             : 
    4012         161 :     return true;
    4013             : }
    4014             : 
    4015             : 
    4016             : static bool
    4017           0 : printPsetInfo(const char *param, struct printQueryOpt *popt)
    4018             : {
    4019           0 :     Assert(param != NULL);
    4020             : 
    4021             :     /* show border style/width */
    4022           0 :     if (strcmp(param, "border") == 0)
    4023           0 :         printf(_("Border style is %d.\n"), popt->topt.border);
    4024             : 
    4025             :     /* show the target width for the wrapped format */
    4026           0 :     else if (strcmp(param, "columns") == 0)
    4027             :     {
    4028           0 :         if (!popt->topt.columns)
    4029           0 :             printf(_("Target width is unset.\n"));
    4030             :         else
    4031           0 :             printf(_("Target width is %d.\n"), popt->topt.columns);
    4032             :     }
    4033             : 
    4034             :     /* show expanded/vertical mode */
    4035           0 :     else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
    4036             :     {
    4037           0 :         if (popt->topt.expanded == 1)
    4038           0 :             printf(_("Expanded display is on.\n"));
    4039           0 :         else if (popt->topt.expanded == 2)
    4040           0 :             printf(_("Expanded display is used automatically.\n"));
    4041             :         else
    4042           0 :             printf(_("Expanded display is off.\n"));
    4043             :     }
    4044             : 
    4045             :     /* show field separator for unaligned text */
    4046           0 :     else if (strcmp(param, "fieldsep") == 0)
    4047             :     {
    4048           0 :         if (popt->topt.fieldSep.separator_zero)
    4049           0 :             printf(_("Field separator is zero byte.\n"));
    4050             :         else
    4051           0 :             printf(_("Field separator is \"%s\".\n"),
    4052             :                    popt->topt.fieldSep.separator);
    4053             :     }
    4054             : 
    4055           0 :     else if (strcmp(param, "fieldsep_zero") == 0)
    4056             :     {
    4057           0 :         printf(_("Field separator is zero byte.\n"));
    4058             :     }
    4059             : 
    4060             :     /* show disable "(x rows)" footer */
    4061           0 :     else if (strcmp(param, "footer") == 0)
    4062             :     {
    4063           0 :         if (popt->topt.default_footer)
    4064           0 :             printf(_("Default footer is on.\n"));
    4065             :         else
    4066           0 :             printf(_("Default footer is off.\n"));
    4067             :     }
    4068             : 
    4069             :     /* show format */
    4070           0 :     else if (strcmp(param, "format") == 0)
    4071             :     {
    4072           0 :         printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
    4073             :     }
    4074             : 
    4075             :     /* show table line style */
    4076           0 :     else if (strcmp(param, "linestyle") == 0)
    4077             :     {
    4078           0 :         printf(_("Line style is %s.\n"),
    4079           0 :                get_line_style(&popt->topt)->name);
    4080             :     }
    4081             : 
    4082             :     /* show null display */
    4083           0 :     else if (strcmp(param, "null") == 0)
    4084             :     {
    4085           0 :         printf(_("Null display is \"%s\".\n"),
    4086           0 :                popt->nullPrint ? popt->nullPrint : "");
    4087             :     }
    4088             : 
    4089             :     /* show locale-aware numeric output */
    4090           0 :     else if (strcmp(param, "numericlocale") == 0)
    4091             :     {
    4092           0 :         if (popt->topt.numericLocale)
    4093           0 :             printf(_("Locale-adjusted numeric output is on.\n"));
    4094             :         else
    4095           0 :             printf(_("Locale-adjusted numeric output is off.\n"));
    4096             :     }
    4097             : 
    4098             :     /* show toggle use of pager */
    4099           0 :     else if (strcmp(param, "pager") == 0)
    4100             :     {
    4101           0 :         if (popt->topt.pager == 1)
    4102           0 :             printf(_("Pager is used for long output.\n"));
    4103           0 :         else if (popt->topt.pager == 2)
    4104           0 :             printf(_("Pager is always used.\n"));
    4105             :         else
    4106           0 :             printf(_("Pager usage is off.\n"));
    4107             :     }
    4108             : 
    4109             :     /* show minimum lines for pager use */
    4110           0 :     else if (strcmp(param, "pager_min_lines") == 0)
    4111             :     {
    4112           0 :         printf(ngettext("Pager won't be used for less than %d line.\n",
    4113             :                         "Pager won't be used for less than %d lines.\n",
    4114             :                         popt->topt.pager_min_lines),
    4115             :                popt->topt.pager_min_lines);
    4116             :     }
    4117             : 
    4118             :     /* show record separator for unaligned text */
    4119           0 :     else if (strcmp(param, "recordsep") == 0)
    4120             :     {
    4121           0 :         if (popt->topt.recordSep.separator_zero)
    4122           0 :             printf(_("Record separator is zero byte.\n"));
    4123           0 :         else if (strcmp(popt->topt.recordSep.separator, "\n") == 0)
    4124           0 :             printf(_("Record separator is <newline>.\n"));
    4125             :         else
    4126           0 :             printf(_("Record separator is \"%s\".\n"),
    4127             :                    popt->topt.recordSep.separator);
    4128             :     }
    4129             : 
    4130           0 :     else if (strcmp(param, "recordsep_zero") == 0)
    4131             :     {
    4132           0 :         printf(_("Record separator is zero byte.\n"));
    4133             :     }
    4134             : 
    4135             :     /* show HTML table tag options */
    4136           0 :     else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
    4137             :     {
    4138           0 :         if (popt->topt.tableAttr)
    4139           0 :             printf(_("Table attributes are \"%s\".\n"),
    4140             :                    popt->topt.tableAttr);
    4141             :         else
    4142           0 :             printf(_("Table attributes unset.\n"));
    4143             :     }
    4144             : 
    4145             :     /* show title override */
    4146           0 :     else if (strcmp(param, "C") == 0 || strcmp(param, "title") == 0)
    4147             :     {
    4148           0 :         if (popt->title)
    4149           0 :             printf(_("Title is \"%s\".\n"), popt->title);
    4150             :         else
    4151           0 :             printf(_("Title is unset.\n"));
    4152             :     }
    4153             : 
    4154             :     /* show toggle between full and tuples-only format */
    4155           0 :     else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
    4156             :     {
    4157           0 :         if (popt->topt.tuples_only)
    4158           0 :             printf(_("Tuples only is on.\n"));
    4159             :         else
    4160           0 :             printf(_("Tuples only is off.\n"));
    4161             :     }
    4162             : 
    4163             :     /* Unicode style formatting */
    4164           0 :     else if (strcmp(param, "unicode_border_linestyle") == 0)
    4165             :     {
    4166           0 :         printf(_("Unicode border line style is \"%s\".\n"),
    4167           0 :                _unicode_linestyle2string(popt->topt.unicode_border_linestyle));
    4168             :     }
    4169             : 
    4170           0 :     else if (strcmp(param, "unicode_column_linestyle") == 0)
    4171             :     {
    4172           0 :         printf(_("Unicode column line style is \"%s\".\n"),
    4173           0 :                _unicode_linestyle2string(popt->topt.unicode_column_linestyle));
    4174             :     }
    4175             : 
    4176           0 :     else if (strcmp(param, "unicode_header_linestyle") == 0)
    4177             :     {
    4178           0 :         printf(_("Unicode header line style is \"%s\".\n"),
    4179           0 :                _unicode_linestyle2string(popt->topt.unicode_header_linestyle));
    4180             :     }
    4181             : 
    4182             :     else
    4183             :     {
    4184           0 :         psql_error("\\pset: unknown option: %s\n", param);
    4185           0 :         return false;
    4186             :     }
    4187             : 
    4188           0 :     return true;
    4189             : }
    4190             : 
    4191             : 
    4192             : static const char *
    4193           6 : pset_bool_string(bool val)
    4194             : {
    4195           6 :     return val ? "on" : "off";
    4196             : }
    4197             : 
    4198             : 
    4199             : static char *
    4200           3 : pset_quoted_string(const char *str)
    4201             : {
    4202           3 :     char       *ret = pg_malloc(strlen(str) * 2 + 3);
    4203           3 :     char       *r = ret;
    4204             : 
    4205           3 :     *r++ = '\'';
    4206             : 
    4207           5 :     for (; *str; str++)
    4208             :     {
    4209           2 :         if (*str == '\n')
    4210             :         {
    4211           1 :             *r++ = '\\';
    4212           1 :             *r++ = 'n';
    4213             :         }
    4214           1 :         else if (*str == '\'')
    4215             :         {
    4216           0 :             *r++ = '\\';
    4217           0 :             *r++ = '\'';
    4218             :         }
    4219             :         else
    4220           1 :             *r++ = *str;
    4221             :     }
    4222             : 
    4223           3 :     *r++ = '\'';
    4224           3 :     *r = '\0';
    4225             : 
    4226           3 :     return ret;
    4227             : }
    4228             : 
    4229             : 
    4230             : /*
    4231             :  * Return a malloc'ed string for the \pset value.
    4232             :  *
    4233             :  * Note that for some string parameters, print.c distinguishes between unset
    4234             :  * and empty string, but for others it doesn't.  This function should produce
    4235             :  * output that produces the correct setting when fed back into \pset.
    4236             :  */
    4237             : static char *
    4238          20 : pset_value_string(const char *param, struct printQueryOpt *popt)
    4239             : {
    4240          20 :     Assert(param != NULL);
    4241             : 
    4242          20 :     if (strcmp(param, "border") == 0)
    4243           1 :         return psprintf("%d", popt->topt.border);
    4244          19 :     else if (strcmp(param, "columns") == 0)
    4245           1 :         return psprintf("%d", popt->topt.columns);
    4246          18 :     else if (strcmp(param, "expanded") == 0)
    4247           2 :         return pstrdup(popt->topt.expanded == 2
    4248             :                        ? "auto"
    4249           1 :                        : pset_bool_string(popt->topt.expanded));
    4250          17 :     else if (strcmp(param, "fieldsep") == 0)
    4251           1 :         return pset_quoted_string(popt->topt.fieldSep.separator
    4252             :                                   ? popt->topt.fieldSep.separator
    4253             :                                   : "");
    4254          16 :     else if (strcmp(param, "fieldsep_zero") == 0)
    4255           1 :         return pstrdup(pset_bool_string(popt->topt.fieldSep.separator_zero));
    4256          15 :     else if (strcmp(param, "footer") == 0)
    4257           1 :         return pstrdup(pset_bool_string(popt->topt.default_footer));
    4258          14 :     else if (strcmp(param, "format") == 0)
    4259           1 :         return psprintf("%s", _align2string(popt->topt.format));
    4260          13 :     else if (strcmp(param, "linestyle") == 0)
    4261           1 :         return psprintf("%s", get_line_style(&popt->topt)->name);
    4262          12 :     else if (strcmp(param, "null") == 0)
    4263           1 :         return pset_quoted_string(popt->nullPrint
    4264             :                                   ? popt->nullPrint
    4265             :                                   : "");
    4266          11 :     else if (strcmp(param, "numericlocale") == 0)
    4267           1 :         return pstrdup(pset_bool_string(popt->topt.numericLocale));
    4268          10 :     else if (strcmp(param, "pager") == 0)
    4269           1 :         return psprintf("%d", popt->topt.pager);
    4270           9 :     else if (strcmp(param, "pager_min_lines") == 0)
    4271           1 :         return psprintf("%d", popt->topt.pager_min_lines);
    4272           8 :     else if (strcmp(param, "recordsep") == 0)
    4273           1 :         return pset_quoted_string(popt->topt.recordSep.separator
    4274             :                                   ? popt->topt.recordSep.separator
    4275             :                                   : "");
    4276           7 :     else if (strcmp(param, "recordsep_zero") == 0)
    4277           1 :         return pstrdup(pset_bool_string(popt->topt.recordSep.separator_zero));
    4278           6 :     else if (strcmp(param, "tableattr") == 0)
    4279           1 :         return popt->topt.tableAttr ? pset_quoted_string(popt->topt.tableAttr) : pstrdup("");
    4280           5 :     else if (strcmp(param, "title") == 0)
    4281           1 :         return popt->title ? pset_quoted_string(popt->title) : pstrdup("");
    4282           4 :     else if (strcmp(param, "tuples_only") == 0)
    4283           1 :         return pstrdup(pset_bool_string(popt->topt.tuples_only));
    4284           3 :     else if (strcmp(param, "unicode_border_linestyle") == 0)
    4285           1 :         return pstrdup(_unicode_linestyle2string(popt->topt.unicode_border_linestyle));
    4286           2 :     else if (strcmp(param, "unicode_column_linestyle") == 0)
    4287           1 :         return pstrdup(_unicode_linestyle2string(popt->topt.unicode_column_linestyle));
    4288           1 :     else if (strcmp(param, "unicode_header_linestyle") == 0)
    4289           1 :         return pstrdup(_unicode_linestyle2string(popt->topt.unicode_header_linestyle));
    4290             :     else
    4291           0 :         return pstrdup("ERROR");
    4292             : }
    4293             : 
    4294             : 
    4295             : 
    4296             : #ifndef WIN32
    4297             : #define DEFAULT_SHELL "/bin/sh"
    4298             : #else
    4299             : /*
    4300             :  *  CMD.EXE is in different places in different Win32 releases so we
    4301             :  *  have to rely on the path to find it.
    4302             :  */
    4303             : #define DEFAULT_SHELL "cmd.exe"
    4304             : #endif
    4305             : 
    4306             : static bool
    4307           0 : do_shell(const char *command)
    4308             : {
    4309             :     int         result;
    4310             : 
    4311           0 :     if (!command)
    4312             :     {
    4313             :         char       *sys;
    4314             :         const char *shellName;
    4315             : 
    4316           0 :         shellName = getenv("SHELL");
    4317             : #ifdef WIN32
    4318             :         if (shellName == NULL)
    4319             :             shellName = getenv("COMSPEC");
    4320             : #endif
    4321           0 :         if (shellName == NULL)
    4322           0 :             shellName = DEFAULT_SHELL;
    4323             : 
    4324             :         /* See EDITOR handling comment for an explanation */
    4325             : #ifndef WIN32
    4326           0 :         sys = psprintf("exec %s", shellName);
    4327             : #else
    4328             :         sys = psprintf("\"%s\"", shellName);
    4329             : #endif
    4330           0 :         result = system(sys);
    4331           0 :         free(sys);
    4332             :     }
    4333             :     else
    4334           0 :         result = system(command);
    4335             : 
    4336           0 :     if (result == 127 || result == -1)
    4337             :     {
    4338           0 :         psql_error("\\!: failed\n");
    4339           0 :         return false;
    4340             :     }
    4341           0 :     return true;
    4342             : }
    4343             : 
    4344             : /*
    4345             :  * do_watch -- handler for \watch
    4346             :  *
    4347             :  * We break this out of exec_command to avoid having to plaster "volatile"
    4348             :  * onto a bunch of exec_command's variables to silence stupider compilers.
    4349             :  */
    4350             : static bool
    4351           0 : do_watch(PQExpBuffer query_buf, double sleep)
    4352             : {
    4353           0 :     long        sleep_ms = (long) (sleep * 1000);
    4354           0 :     printQueryOpt myopt = pset.popt;
    4355             :     const char *strftime_fmt;
    4356             :     const char *user_title;
    4357             :     char       *title;
    4358             :     int         title_len;
    4359           0 :     int         res = 0;
    4360             : 
    4361           0 :     if (!query_buf || query_buf->len <= 0)
    4362             :     {
    4363           0 :         psql_error(_("\\watch cannot be used with an empty query\n"));
    4364           0 :         return false;
    4365             :     }
    4366             : 
    4367             :     /*
    4368             :      * Choose format for timestamps.  We might eventually make this a \pset
    4369             :      * option.  In the meantime, using a variable for the format suppresses
    4370             :      * overly-anal-retentive gcc warnings about %c being Y2K sensitive.
    4371             :      */
    4372           0 :     strftime_fmt = "%c";
    4373             : 
    4374             :     /*
    4375             :      * Set up rendering options, in particular, disable the pager, because
    4376             :      * nobody wants to be prompted while watching the output of 'watch'.
    4377             :      */
    4378           0 :     myopt.topt.pager = 0;
    4379             : 
    4380             :     /*
    4381             :      * If there's a title in the user configuration, make sure we have room
    4382             :      * for it in the title buffer.  Allow 128 bytes for the timestamp plus 128
    4383             :      * bytes for the rest.
    4384             :      */
    4385           0 :     user_title = myopt.title;
    4386           0 :     title_len = (user_title ? strlen(user_title) : 0) + 256;
    4387           0 :     title = pg_malloc(title_len);
    4388             : 
    4389             :     for (;;)
    4390             :     {
    4391             :         time_t      timer;
    4392             :         char        timebuf[128];
    4393             :         long        i;
    4394             : 
    4395             :         /*
    4396             :          * Prepare title for output.  Note that we intentionally include a
    4397             :          * newline at the end of the title; this is somewhat historical but it
    4398             :          * makes for reasonably nicely formatted output in simple cases.
    4399             :          */
    4400           0 :         timer = time(NULL);
    4401           0 :         strftime(timebuf, sizeof(timebuf), strftime_fmt, localtime(&timer));
    4402             : 
    4403           0 :         if (user_title)
    4404           0 :             snprintf(title, title_len, _("%s\t%s (every %gs)\n"),
    4405             :                      user_title, timebuf, sleep);
    4406             :         else
    4407           0 :             snprintf(title, title_len, _("%s (every %gs)\n"),
    4408             :                      timebuf, sleep);
    4409           0 :         myopt.title = title;
    4410             : 
    4411             :         /* Run the query and print out the results */
    4412           0 :         res = PSQLexecWatch(query_buf->data, &myopt);
    4413             : 
    4414             :         /*
    4415             :          * PSQLexecWatch handles the case where we can no longer repeat the
    4416             :          * query, and returns 0 or -1.
    4417             :          */
    4418           0 :         if (res <= 0)
    4419           0 :             break;
    4420             : 
    4421             :         /*
    4422             :          * Set up cancellation of 'watch' via SIGINT.  We redo this each time
    4423             :          * through the loop since it's conceivable something inside
    4424             :          * PSQLexecWatch could change sigint_interrupt_jmp.
    4425             :          */
    4426           0 :         if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
    4427           0 :             break;
    4428             : 
    4429             :         /*
    4430             :          * Enable 'watch' cancellations and wait a while before running the
    4431             :          * query again.  Break the sleep into short intervals (at most 1s)
    4432             :          * since pg_usleep isn't interruptible on some platforms.
    4433             :          */
    4434           0 :         sigint_interrupt_enabled = true;
    4435           0 :         i = sleep_ms;
    4436           0 :         while (i > 0)
    4437             :         {
    4438           0 :             long        s = Min(i, 1000L);
    4439             : 
    4440           0 :             pg_usleep(s * 1000L);
    4441           0 :             if (cancel_pressed)
    4442           0 :                 break;
    4443           0 :             i -= s;
    4444             :         }
    4445           0 :         sigint_interrupt_enabled = false;
    4446           0 :     }
    4447             : 
    4448           0 :     pg_free(title);
    4449           0 :     return (res >= 0);
    4450             : }
    4451             : 
    4452             : /*
    4453             :  * a little code borrowed from PSQLexec() to manage ECHO_HIDDEN output.
    4454             :  * returns true unless we have ECHO_HIDDEN_NOEXEC.
    4455             :  */
    4456             : static bool
    4457           2 : echo_hidden_command(const char *query)
    4458             : {
    4459           2 :     if (pset.echo_hidden != PSQL_ECHO_HIDDEN_OFF)
    4460             :     {
    4461           0 :         printf(_("********* QUERY **********\n"
    4462             :                  "%s\n"
    4463             :                  "**************************\n\n"), query);
    4464           0 :         fflush(stdout);
    4465           0 :         if (pset.logfile)
    4466             :         {
    4467           0 :             fprintf(pset.logfile,
    4468             :                     _("********* QUERY **********\n"
    4469             :                       "%s\n"
    4470             :                       "**************************\n\n"), query);
    4471           0 :             fflush(pset.logfile);
    4472             :         }
    4473             : 
    4474           0 :         if (pset.echo_hidden == PSQL_ECHO_HIDDEN_NOEXEC)
    4475           0 :             return false;
    4476             :     }
    4477           2 :     return true;
    4478             : }
    4479             : 
    4480             : /*
    4481             :  * Look up the object identified by obj_type and desc.  If successful,
    4482             :  * store its OID in *obj_oid and return TRUE, else return FALSE.
    4483             :  *
    4484             :  * Note that we'll fail if the object doesn't exist OR if there are multiple
    4485             :  * matching candidates OR if there's something syntactically wrong with the
    4486             :  * object description; unfortunately it can be hard to tell the difference.
    4487             :  */
    4488             : static bool
    4489           1 : lookup_object_oid(EditableObjectType obj_type, const char *desc,
    4490             :                   Oid *obj_oid)
    4491             : {
    4492           1 :     bool        result = true;
    4493           1 :     PQExpBuffer query = createPQExpBuffer();
    4494             :     PGresult   *res;
    4495             : 
    4496           1 :     switch (obj_type)
    4497             :     {
    4498             :         case EditableFunction:
    4499             : 
    4500             :             /*
    4501             :              * We have a function description, e.g. "x" or "x(int)".  Issue a
    4502             :              * query to retrieve the function's OID using a cast to regproc or
    4503             :              * regprocedure (as appropriate).
    4504             :              */
    4505           0 :             appendPQExpBufferStr(query, "SELECT ");
    4506           0 :             appendStringLiteralConn(query, desc, pset.db);
    4507           0 :             appendPQExpBuffer(query, "::pg_catalog.%s::pg_catalog.oid",
    4508           0 :                               strchr(desc, '(') ? "regprocedure" : "regproc");
    4509           0 :             break;
    4510             : 
    4511             :         case EditableView:
    4512             : 
    4513             :             /*
    4514             :              * Convert view name (possibly schema-qualified) to OID.  Note:
    4515             :              * this code doesn't check if the relation is actually a view.
    4516             :              * We'll detect that in get_create_object_cmd().
    4517             :              */
    4518           1 :             appendPQExpBufferStr(query, "SELECT ");
    4519           1 :             appendStringLiteralConn(query, desc, pset.db);
    4520           1 :             appendPQExpBuffer(query, "::pg_catalog.regclass::pg_catalog.oid");
    4521           1 :             break;
    4522             :     }
    4523             : 
    4524           1 :     if (!echo_hidden_command(query->data))
    4525             :     {
    4526           0 :         destroyPQExpBuffer(query);
    4527           0 :         return false;
    4528             :     }
    4529           1 :     res = PQexec(pset.db, query->data);
    4530           1 :     if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
    4531           1 :         *obj_oid = atooid(PQgetvalue(res, 0, 0));
    4532             :     else
    4533             :     {
    4534           0 :         minimal_error_message(res);
    4535           0 :         result = false;
    4536             :     }
    4537             : 
    4538           1 :     PQclear(res);
    4539           1 :     destroyPQExpBuffer(query);
    4540             : 
    4541           1 :     return result;
    4542             : }
    4543             : 
    4544             : /*
    4545             :  * Construct a "CREATE OR REPLACE ..." command that describes the specified
    4546             :  * database object.  If successful, the result is stored in buf.
    4547             :  */
    4548             : static bool
    4549           1 : get_create_object_cmd(EditableObjectType obj_type, Oid oid,
    4550             :                       PQExpBuffer buf)
    4551             : {
    4552           1 :     bool        result = true;
    4553           1 :     PQExpBuffer query = createPQExpBuffer();
    4554             :     PGresult   *res;
    4555             : 
    4556           1 :     switch (obj_type)
    4557             :     {
    4558             :         case EditableFunction:
    4559           0 :             printfPQExpBuffer(query,
    4560             :                               "SELECT pg_catalog.pg_get_functiondef(%u)",
    4561             :                               oid);
    4562           0 :             break;
    4563             : 
    4564             :         case EditableView:
    4565             : 
    4566             :             /*
    4567             :              * pg_get_viewdef() just prints the query, so we must prepend
    4568             :              * CREATE for ourselves.  We must fully qualify the view name to
    4569             :              * ensure the right view gets replaced.  Also, check relation kind
    4570             :              * to be sure it's a view.
    4571             :              *
    4572             :              * Starting with 9.2, views may have reloptions (security_barrier)
    4573             :              * and from 9.4 onwards they may also have WITH [LOCAL|CASCADED]
    4574             :              * CHECK OPTION.  These are not part of the view definition
    4575             :              * returned by pg_get_viewdef() and so need to be retrieved
    4576             :              * separately.  Materialized views (introduced in 9.3) may have
    4577             :              * arbitrary storage parameter reloptions.
    4578             :              */
    4579           1 :             if (pset.sversion >= 90400)
    4580             :             {
    4581           1 :                 printfPQExpBuffer(query,
    4582             :                                   "SELECT nspname, relname, relkind, "
    4583             :                                   "pg_catalog.pg_get_viewdef(c.oid, true), "
    4584             :                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    4585             :                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    4586             :                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption "
    4587             :                                   "FROM pg_catalog.pg_class c "
    4588             :                                   "LEFT JOIN pg_catalog.pg_namespace n "
    4589             :                                   "ON c.relnamespace = n.oid WHERE c.oid = %u",
    4590             :                                   oid);
    4591             :             }
    4592           0 :             else if (pset.sversion >= 90200)
    4593             :             {
    4594           0 :                 printfPQExpBuffer(query,
    4595             :                                   "SELECT nspname, relname, relkind, "
    4596             :                                   "pg_catalog.pg_get_viewdef(c.oid, true), "
    4597             :                                   "c.reloptions AS reloptions, "
    4598             :                                   "NULL AS checkoption "
    4599             :                                   "FROM pg_catalog.pg_class c "
    4600             :                                   "LEFT JOIN pg_catalog.pg_namespace n "
    4601             :                                   "ON c.relnamespace = n.oid WHERE c.oid = %u",
    4602             :                                   oid);
    4603             :             }
    4604             :             else
    4605             :             {
    4606           0 :                 printfPQExpBuffer(query,
    4607             :                                   "SELECT nspname, relname, relkind, "
    4608             :                                   "pg_catalog.pg_get_viewdef(c.oid, true), "
    4609             :                                   "NULL AS reloptions, "
    4610             :                                   "NULL AS checkoption "
    4611             :                                   "FROM pg_catalog.pg_class c "
    4612             :                                   "LEFT JOIN pg_catalog.pg_namespace n "
    4613             :                                   "ON c.relnamespace = n.oid WHERE c.oid = %u",
    4614             :                                   oid);
    4615             :             }
    4616           1 :             break;
    4617             :     }
    4618             : 
    4619           1 :     if (!echo_hidden_command(query->data))
    4620             :     {
    4621           0 :         destroyPQExpBuffer(query);
    4622           0 :         return false;
    4623             :     }
    4624           1 :     res = PQexec(pset.db, query->data);
    4625           1 :     if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
    4626             :     {
    4627           1 :         resetPQExpBuffer(buf);
    4628           1 :         switch (obj_type)
    4629             :         {
    4630             :             case EditableFunction:
    4631           0 :                 appendPQExpBufferStr(buf, PQgetvalue(res, 0, 0));
    4632           0 :                 break;
    4633             : 
    4634             :             case EditableView:
    4635             :                 {
    4636           1 :                     char       *nspname = PQgetvalue(res, 0, 0);
    4637           1 :                     char       *relname = PQgetvalue(res, 0, 1);
    4638           1 :                     char       *relkind = PQgetvalue(res, 0, 2);
    4639           1 :                     char       *viewdef = PQgetvalue(res, 0, 3);
    4640           1 :                     char       *reloptions = PQgetvalue(res, 0, 4);
    4641           1 :                     char       *checkoption = PQgetvalue(res, 0, 5);
    4642             : 
    4643             :                     /*
    4644             :                      * If the backend ever supports CREATE OR REPLACE
    4645             :                      * MATERIALIZED VIEW, allow that here; but as of today it
    4646             :                      * does not, so editing a matview definition in this way
    4647             :                      * is impossible.
    4648             :                      */
    4649           1 :                     switch (relkind[0])
    4650             :                     {
    4651             : #ifdef NOT_USED
    4652             :                         case RELKIND_MATVIEW:
    4653             :                             appendPQExpBufferStr(buf, "CREATE OR REPLACE MATERIALIZED VIEW ");
    4654             :                             break;
    4655             : #endif
    4656             :                         case RELKIND_VIEW:
    4657           1 :                             appendPQExpBufferStr(buf, "CREATE OR REPLACE VIEW ");
    4658           1 :                             break;
    4659             :                         default:
    4660           0 :                             psql_error("\"%s.%s\" is not a view\n",
    4661             :                                        nspname, relname);
    4662           0 :                             result = false;
    4663           0 :                             break;
    4664             :                     }
    4665           1 :                     appendPQExpBuffer(buf, "%s.", fmtId(nspname));
    4666           1 :                     appendPQExpBufferStr(buf, fmtId(relname));
    4667             : 
    4668             :                     /* reloptions, if not an empty array "{}" */
    4669           1 :                     if (reloptions != NULL && strlen(reloptions) > 2)
    4670             :                     {
    4671           0 :                         appendPQExpBufferStr(buf, "\n WITH (");
    4672           0 :                         if (!appendReloptionsArray(buf, reloptions, "",
    4673             :                                                    pset.encoding,
    4674           0 :                                                    standard_strings()))
    4675             :                         {
    4676           0 :                             psql_error("could not parse reloptions array\n");
    4677           0 :                             result = false;
    4678             :                         }
    4679           0 :                         appendPQExpBufferChar(buf, ')');
    4680             :                     }
    4681             : 
    4682             :                     /* View definition from pg_get_viewdef (a SELECT query) */
    4683           1 :                     appendPQExpBuffer(buf, " AS\n%s", viewdef);
    4684             : 
    4685             :                     /* Get rid of the semicolon that pg_get_viewdef appends */
    4686           1 :                     if (buf->len > 0 && buf->data[buf->len - 1] == ';')
    4687           1 :                         buf->data[--(buf->len)] = '\0';
    4688             : 
    4689             :                     /* WITH [LOCAL|CASCADED] CHECK OPTION */
    4690           1 :                     if (checkoption && checkoption[0] != '\0')
    4691           0 :                         appendPQExpBuffer(buf, "\n WITH %s CHECK OPTION",
    4692             :                                           checkoption);
    4693             :                 }
    4694           1 :                 break;
    4695             :         }
    4696             :         /* Make sure result ends with a newline */
    4697           2 :         if (buf->len > 0 && buf->data[buf->len - 1] != '\n')
    4698           1 :             appendPQExpBufferChar(buf, '\n');
    4699             :     }
    4700             :     else
    4701             :     {
    4702           0 :         minimal_error_message(res);
    4703           0 :         result = false;
    4704             :     }
    4705             : 
    4706           1 :     PQclear(res);
    4707           1 :     destroyPQExpBuffer(query);
    4708             : 
    4709           1 :     return result;
    4710             : }
    4711             : 
    4712             : /*
    4713             :  * If the given argument of \ef or \ev ends with a line number, delete the line
    4714             :  * number from the argument string and return it as an integer.  (We need
    4715             :  * this kluge because we're too lazy to parse \ef's function or \ev's view
    4716             :  * argument carefully --- we just slop it up in OT_WHOLE_LINE mode.)
    4717             :  *
    4718             :  * Returns -1 if no line number is present, 0 on error, or a positive value
    4719             :  * on success.
    4720             :  */
    4721             : static int
    4722           0 : strip_lineno_from_objdesc(char *obj)
    4723             : {
    4724             :     char       *c;
    4725             :     int         lineno;
    4726             : 
    4727           0 :     if (!obj || obj[0] == '\0')
    4728           0 :         return -1;
    4729             : 
    4730           0 :     c = obj + strlen(obj) - 1;
    4731             : 
    4732             :     /*
    4733             :      * This business of parsing backwards is dangerous as can be in a
    4734             :      * multibyte environment: there is no reason to believe that we are
    4735             :      * looking at the first byte of a character, nor are we necessarily
    4736             :      * working in a "safe" encoding.  Fortunately the bitpatterns we are
    4737             :      * looking for are unlikely to occur as non-first bytes, but beware of
    4738             :      * trying to expand the set of cases that can be recognized.  We must
    4739             :      * guard the <ctype.h> macros by using isascii() first, too.
    4740             :      */
    4741             : 
    4742             :     /* skip trailing whitespace */
    4743           0 :     while (c > obj && isascii((unsigned char) *c) && isspace((unsigned char) *c))
    4744           0 :         c--;
    4745             : 
    4746             :     /* must have a digit as last non-space char */
    4747           0 :     if (c == obj || !isascii((unsigned char) *c) || !isdigit((unsigned char) *c))
    4748           0 :         return -1;
    4749             : 
    4750             :     /* find start of digit string */
    4751           0 :     while (c > obj && isascii((unsigned char) *c) && isdigit((unsigned char) *c))
    4752           0 :         c--;
    4753             : 
    4754             :     /* digits must be separated from object name by space or closing paren */
    4755             :     /* notice also that we are not allowing an empty object name ... */
    4756           0 :     if (c == obj || !isascii((unsigned char) *c) ||
    4757           0 :         !(isspace((unsigned char) *c) || *c == ')'))
    4758           0 :         return -1;
    4759             : 
    4760             :     /* parse digit string */
    4761           0 :     c++;
    4762           0 :     lineno = atoi(c);
    4763           0 :     if (lineno < 1)
    4764             :     {
    4765           0 :         psql_error("invalid line number: %s\n", c);
    4766           0 :         return 0;
    4767             :     }
    4768             : 
    4769             :     /* strip digit string from object name */
    4770           0 :     *c = '\0';
    4771             : 
    4772           0 :     return lineno;
    4773             : }
    4774             : 
    4775             : /*
    4776             :  * Count number of lines in the buffer.
    4777             :  * This is used to test if pager is needed or not.
    4778             :  */
    4779             : static int
    4780           1 : count_lines_in_buf(PQExpBuffer buf)
    4781             : {
    4782           1 :     int         lineno = 0;
    4783           1 :     const char *lines = buf->data;
    4784             : 
    4785          14 :     while (*lines != '\0')
    4786             :     {
    4787          12 :         lineno++;
    4788             :         /* find start of next line */
    4789          12 :         lines = strchr(lines, '\n');
    4790          12 :         if (!lines)
    4791           0 :             break;
    4792          12 :         lines++;
    4793             :     }
    4794             : 
    4795           1 :     return lineno;
    4796             : }
    4797             : 
    4798             : /*
    4799             :  * Write text at *lines to output with line numbers.
    4800             :  *
    4801             :  * If header_keyword isn't NULL, then line 1 should be the first line beginning
    4802             :  * with header_keyword; lines before that are unnumbered.
    4803             :  *
    4804             :  * Caution: this scribbles on *lines.
    4805             :  */
    4806             : static void
    4807           0 : print_with_linenumbers(FILE *output, char *lines,
    4808             :                        const char *header_keyword)
    4809             : {
    4810           0 :     bool        in_header = (header_keyword != NULL);
    4811           0 :     size_t      header_sz = in_header ? strlen(header_keyword) : 0;
    4812           0 :     int         lineno = 0;
    4813             : 
    4814           0 :     while (*lines != '\0')
    4815             :     {
    4816             :         char       *eol;
    4817             : 
    4818           0 :         if (in_header && strncmp(lines, header_keyword, header_sz) == 0)
    4819           0 :             in_header = false;
    4820             : 
    4821             :         /* increment lineno only for body's lines */
    4822           0 :         if (!in_header)
    4823           0 :             lineno++;
    4824             : 
    4825             :         /* find and mark end of current line */
    4826           0 :         eol = strchr(lines, '\n');
    4827           0 :         if (eol != NULL)
    4828           0 :             *eol = '\0';
    4829             : 
    4830             :         /* show current line as appropriate */
    4831           0 :         if (in_header)
    4832           0 :             fprintf(output, "        %s\n", lines);
    4833             :         else
    4834           0 :             fprintf(output, "%-7d %s\n", lineno, lines);
    4835             : 
    4836             :         /* advance to next line, if any */
    4837           0 :         if (eol == NULL)
    4838           0 :             break;
    4839           0 :         lines = ++eol;
    4840             :     }
    4841           0 : }
    4842             : 
    4843             : /*
    4844             :  * Report just the primary error; this is to avoid cluttering the output
    4845             :  * with, for instance, a redisplay of the internally generated query
    4846             :  */
    4847             : static void
    4848           0 : minimal_error_message(PGresult *res)
    4849             : {
    4850             :     PQExpBuffer msg;
    4851             :     const char *fld;
    4852             : 
    4853           0 :     msg = createPQExpBuffer();
    4854             : 
    4855           0 :     fld = PQresultErrorField(res, PG_DIAG_SEVERITY);
    4856           0 :     if (fld)
    4857           0 :         printfPQExpBuffer(msg, "%s:  ", fld);
    4858             :     else
    4859           0 :         printfPQExpBuffer(msg, "ERROR:  ");
    4860           0 :     fld = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
    4861           0 :     if (fld)
    4862           0 :         appendPQExpBufferStr(msg, fld);
    4863             :     else
    4864           0 :         appendPQExpBufferStr(msg, "(not available)");
    4865           0 :     appendPQExpBufferChar(msg, '\n');
    4866             : 
    4867           0 :     psql_error("%s", msg->data);
    4868             : 
    4869           0 :     destroyPQExpBuffer(msg);
    4870           0 : }

Generated by: LCOV version 1.11