LCOV - code coverage report
Current view: top level - src/bin/psql - startup.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 74.9 % 578 433
Test Date: 2026-04-20 15:16:29 Functions: 95.3 % 43 41
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * psql - the PostgreSQL interactive terminal
       3              :  *
       4              :  * Copyright (c) 2000-2026, PostgreSQL Global Development Group
       5              :  *
       6              :  * src/bin/psql/startup.c
       7              :  */
       8              : #include "postgres_fe.h"
       9              : 
      10              : #ifndef WIN32
      11              : #include <unistd.h>
      12              : #else                           /* WIN32 */
      13              : #include <io.h>
      14              : #include <win32.h>
      15              : #endif                          /* WIN32 */
      16              : 
      17              : #include "command.h"
      18              : #include "common.h"
      19              : #include "common/logging.h"
      20              : #include "common/string.h"
      21              : #include "describe.h"
      22              : #include "fe_utils/print.h"
      23              : #include "getopt_long.h"
      24              : #include "help.h"
      25              : #include "input.h"
      26              : #include "mainloop.h"
      27              : #include "portability/instr_time.h"
      28              : #include "settings.h"
      29              : 
      30              : /*
      31              :  * Global psql options
      32              :  */
      33              : PsqlSettings pset;
      34              : 
      35              : #ifndef WIN32
      36              : #define SYSPSQLRC   "psqlrc"
      37              : #define PSQLRC      ".psqlrc"
      38              : #else
      39              : #define SYSPSQLRC   "psqlrc"
      40              : #define PSQLRC      "psqlrc.conf"
      41              : #endif
      42              : 
      43              : /*
      44              :  * Structures to pass information between the option parsing routine
      45              :  * and the main function
      46              :  */
      47              : enum _actions
      48              : {
      49              :     ACT_SINGLE_QUERY,
      50              :     ACT_SINGLE_SLASH,
      51              :     ACT_FILE,
      52              : };
      53              : 
      54              : typedef struct SimpleActionListCell
      55              : {
      56              :     struct SimpleActionListCell *next;
      57              :     enum _actions action;
      58              :     char       *val;
      59              : } SimpleActionListCell;
      60              : 
      61              : typedef struct SimpleActionList
      62              : {
      63              :     SimpleActionListCell *head;
      64              :     SimpleActionListCell *tail;
      65              : } SimpleActionList;
      66              : 
      67              : struct adhoc_opts
      68              : {
      69              :     char       *dbname;
      70              :     char       *host;
      71              :     char       *port;
      72              :     char       *username;
      73              :     char       *logfilename;
      74              :     bool        no_readline;
      75              :     bool        no_psqlrc;
      76              :     bool        single_txn;
      77              :     bool        list_dbs;
      78              :     SimpleActionList actions;
      79              : };
      80              : 
      81              : static void parse_psql_options(int argc, char *argv[],
      82              :                                struct adhoc_opts *options);
      83              : static void simple_action_list_append(SimpleActionList *list,
      84              :                                       enum _actions action, const char *val);
      85              : static void process_psqlrc(char *argv0);
      86              : static void process_psqlrc_file(char *filename);
      87              : static void showVersion(void);
      88              : static void EstablishVariableSpace(void);
      89              : 
      90              : #define NOPAGER     0
      91              : 
      92              : static void
      93       216817 : log_pre_callback(void)
      94              : {
      95       216817 :     if (pset.queryFout && pset.queryFout != stdout)
      96            0 :         fflush(pset.queryFout);
      97       216817 : }
      98              : 
      99              : static void
     100       216817 : log_locus_callback(const char **filename, uint64 *lineno)
     101              : {
     102       216817 :     if (pset.inputfile)
     103              :     {
     104       169881 :         *filename = pset.inputfile;
     105       169881 :         *lineno = pset.lineno;
     106              :     }
     107              :     else
     108              :     {
     109        46936 :         *filename = NULL;
     110        46936 :         *lineno = 0;
     111              :     }
     112       216817 : }
     113              : 
     114              : #ifndef WIN32
     115              : static void
     116            7 : empty_signal_handler(SIGNAL_ARGS)
     117              : {
     118            7 : }
     119              : #endif
     120              : 
     121              : /*
     122              :  *
     123              :  * main
     124              :  *
     125              :  */
     126              : int
     127        10332 : main(int argc, char *argv[])
     128              : {
     129              :     struct adhoc_opts options;
     130              :     int         successResult;
     131        10332 :     char       *password = NULL;
     132              :     bool        new_pass;
     133              : 
     134        10332 :     pg_logging_init(argv[0]);
     135        10332 :     pg_logging_set_pre_callback(log_pre_callback);
     136        10332 :     pg_logging_set_locus_callback(log_locus_callback);
     137        10332 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
     138              : 
     139        10332 :     if (argc > 1)
     140              :     {
     141        10332 :         if ((strcmp(argv[1], "-?") == 0) || (argc == 2 && (strcmp(argv[1], "--help") == 0)))
     142              :         {
     143            1 :             usage(NOPAGER);
     144            1 :             exit(EXIT_SUCCESS);
     145              :         }
     146        10331 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     147              :         {
     148           20 :             showVersion();
     149           20 :             exit(EXIT_SUCCESS);
     150              :         }
     151              :     }
     152              : 
     153        10311 :     pset.progname = get_progname(argv[0]);
     154              : 
     155        10311 :     pset.db = NULL;
     156        10311 :     pset.dead_conn = NULL;
     157        10311 :     setDecimalLocale();
     158        10311 :     pset.encoding = PQenv2encoding();
     159        10311 :     pset.queryFout = stdout;
     160        10311 :     pset.queryFoutPipe = false;
     161        10311 :     pset.copyStream = NULL;
     162        10311 :     pset.last_error_result = NULL;
     163        10311 :     pset.cur_cmd_source = stdin;
     164        10311 :     pset.cur_cmd_interactive = false;
     165              : 
     166              :     /* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
     167        10311 :     pset.popt.topt.format = PRINT_ALIGNED;
     168        10311 :     pset.popt.topt.border = 1;
     169        10311 :     pset.popt.topt.pager = 1;
     170        10311 :     pset.popt.topt.pager_min_lines = 0;
     171        10311 :     pset.popt.topt.start_table = true;
     172        10311 :     pset.popt.topt.stop_table = true;
     173        10311 :     pset.popt.topt.default_footer = true;
     174              : 
     175        10311 :     pset.popt.topt.csvFieldSep[0] = DEFAULT_CSV_FIELD_SEP;
     176        10311 :     pset.popt.topt.csvFieldSep[1] = '\0';
     177              : 
     178        10311 :     pset.popt.topt.unicode_border_linestyle = UNICODE_LINESTYLE_SINGLE;
     179        10311 :     pset.popt.topt.unicode_column_linestyle = UNICODE_LINESTYLE_SINGLE;
     180        10311 :     pset.popt.topt.unicode_header_linestyle = UNICODE_LINESTYLE_SINGLE;
     181              : 
     182        10311 :     refresh_utf8format(&(pset.popt.topt));
     183              : 
     184              :     /* We must get COLUMNS here before readline() sets it */
     185        10311 :     pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;
     186              : 
     187        10311 :     pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
     188              : 
     189        10311 :     pset.getPassword = TRI_DEFAULT;
     190              : 
     191        10311 :     EstablishVariableSpace();
     192              : 
     193              :     /* Create variables showing psql version number */
     194        10311 :     SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
     195        10311 :     SetVariable(pset.vars, "VERSION_NAME", PG_VERSION);
     196        10311 :     SetVariable(pset.vars, "VERSION_NUM", CppAsString2(PG_VERSION_NUM));
     197              : 
     198              :     /* Initialize variables for last error */
     199        10311 :     SetVariable(pset.vars, "LAST_ERROR_MESSAGE", "");
     200        10311 :     SetVariable(pset.vars, "LAST_ERROR_SQLSTATE", "00000");
     201              : 
     202              :     /* Default values for variables (that don't match the result of \unset) */
     203        10311 :     SetVariableBool(pset.vars, "AUTOCOMMIT");
     204        10311 :     SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
     205        10311 :     SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
     206        10311 :     SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
     207        10311 :     SetVariableBool(pset.vars, "SHOW_ALL_RESULTS");
     208              : 
     209              :     /* Initialize pipeline variables */
     210        10311 :     SetVariable(pset.vars, "PIPELINE_SYNC_COUNT", "0");
     211        10311 :     SetVariable(pset.vars, "PIPELINE_COMMAND_COUNT", "0");
     212        10311 :     SetVariable(pset.vars, "PIPELINE_RESULT_COUNT", "0");
     213              : 
     214        10311 :     parse_psql_options(argc, argv, &options);
     215              : 
     216              :     /*
     217              :      * If no action was specified and we're in non-interactive mode, treat it
     218              :      * as if the user had specified "-f -".  This lets single-transaction mode
     219              :      * work in this case.
     220              :      */
     221        10308 :     if (options.actions.head == NULL && pset.notty)
     222         2453 :         simple_action_list_append(&options.actions, ACT_FILE, NULL);
     223              : 
     224              :     /* Bail out if -1 was specified but will be ignored. */
     225        10308 :     if (options.single_txn && options.actions.head == NULL)
     226            0 :         pg_fatal("-1 can only be used in non-interactive mode");
     227              : 
     228        10308 :     if (!pset.popt.topt.fieldSep.separator &&
     229        10306 :         !pset.popt.topt.fieldSep.separator_zero)
     230              :     {
     231        10306 :         pset.popt.topt.fieldSep.separator = pg_strdup(DEFAULT_FIELD_SEP);
     232        10306 :         pset.popt.topt.fieldSep.separator_zero = false;
     233              :     }
     234        10308 :     if (!pset.popt.topt.recordSep.separator &&
     235        10308 :         !pset.popt.topt.recordSep.separator_zero)
     236              :     {
     237        10308 :         pset.popt.topt.recordSep.separator = pg_strdup(DEFAULT_RECORD_SEP);
     238        10308 :         pset.popt.topt.recordSep.separator_zero = false;
     239              :     }
     240              : 
     241        10308 :     if (pset.getPassword == TRI_YES)
     242              :     {
     243              :         /*
     244              :          * We can't be sure yet of the username that will be used, so don't
     245              :          * offer a potentially wrong one.  Typical uses of this option are
     246              :          * noninteractive anyway.  (Note: since we've not yet set up our
     247              :          * cancel handler, there's no need to use simple_prompt_extended.)
     248              :          */
     249            0 :         password = simple_prompt("Password: ", false);
     250              :     }
     251              : 
     252              :     /* loop until we have a password if requested by backend */
     253              :     do
     254              :     {
     255              : #define PARAMS_ARRAY_SIZE   8
     256        10308 :         const char **keywords = pg_malloc_array(const char *, PARAMS_ARRAY_SIZE);
     257        10308 :         const char **values = pg_malloc_array(const char *, PARAMS_ARRAY_SIZE);
     258              : 
     259        10308 :         keywords[0] = "host";
     260        10308 :         values[0] = options.host;
     261        10308 :         keywords[1] = "port";
     262        10308 :         values[1] = options.port;
     263        10308 :         keywords[2] = "user";
     264        10308 :         values[2] = options.username;
     265        10308 :         keywords[3] = "password";
     266        10308 :         values[3] = password;
     267        10308 :         keywords[4] = "dbname"; /* see do_connect() */
     268            0 :         values[4] = (options.list_dbs && options.dbname == NULL) ?
     269        10308 :             "postgres" : options.dbname;
     270        10308 :         keywords[5] = "fallback_application_name";
     271        10308 :         values[5] = pset.progname;
     272        10308 :         keywords[6] = "client_encoding";
     273        10308 :         values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
     274        10308 :         keywords[7] = NULL;
     275        10308 :         values[7] = NULL;
     276              : 
     277        10308 :         new_pass = false;
     278        10308 :         pset.db = PQconnectdbParams(keywords, values, true);
     279        10308 :         free(keywords);
     280        10308 :         free(values);
     281              : 
     282        10508 :         if (PQstatus(pset.db) == CONNECTION_BAD &&
     283          201 :             PQconnectionNeedsPassword(pset.db) &&
     284            1 :             !password &&
     285            1 :             pset.getPassword != TRI_NO)
     286              :         {
     287              :             /*
     288              :              * Before closing the old PGconn, extract the user name that was
     289              :              * actually connected with --- it might've come out of a URI or
     290              :              * connstring "database name" rather than options.username.
     291              :              */
     292            0 :             const char *realusername = PQuser(pset.db);
     293              :             char       *password_prompt;
     294              : 
     295            0 :             if (realusername && realusername[0])
     296            0 :                 password_prompt = psprintf(_("Password for user %s: "),
     297              :                                            realusername);
     298              :             else
     299            0 :                 password_prompt = pg_strdup(_("Password: "));
     300            0 :             PQfinish(pset.db);
     301              : 
     302            0 :             password = simple_prompt(password_prompt, false);
     303            0 :             free(password_prompt);
     304            0 :             new_pass = true;
     305              :         }
     306        10308 :     } while (new_pass);
     307              : 
     308        10308 :     if (PQstatus(pset.db) == CONNECTION_BAD)
     309              :     {
     310          200 :         pg_log_error("%s", PQerrorMessage(pset.db));
     311          200 :         PQfinish(pset.db);
     312          200 :         exit(EXIT_BADCONN);
     313              :     }
     314              : 
     315        10108 :     psql_setup_cancel_handler();
     316              : 
     317              : #ifndef WIN32
     318              : 
     319              :     /*
     320              :      * do_watch() needs signal handlers installed (otherwise sigwait() will
     321              :      * filter them out on some platforms), but doesn't need them to do
     322              :      * anything, and they shouldn't ever run (unless perhaps a stray SIGALRM
     323              :      * arrives due to a race when do_watch() cancels an itimer).
     324              :      */
     325        10108 :     pqsignal(SIGCHLD, empty_signal_handler);
     326        10108 :     pqsignal(SIGALRM, empty_signal_handler);
     327              : #endif
     328              : 
     329        10108 :     PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
     330              : 
     331              :     /* initialize timing infrastructure (required for INSTR_* calls) */
     332        10108 :     pg_initialize_timing();
     333              : 
     334        10108 :     SyncVariables();
     335              : 
     336        10108 :     if (options.list_dbs)
     337              :     {
     338              :         int         success;
     339              : 
     340            0 :         if (!options.no_psqlrc)
     341            0 :             process_psqlrc(argv[0]);
     342              : 
     343            0 :         success = listAllDbs(NULL, false);
     344            0 :         PQfinish(pset.db);
     345            0 :         exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
     346              :     }
     347              : 
     348        10108 :     if (options.logfilename)
     349              :     {
     350            0 :         pset.logfile = fopen(options.logfilename, "a");
     351            0 :         if (!pset.logfile)
     352            0 :             pg_fatal("could not open log file \"%s\": %m",
     353              :                      options.logfilename);
     354              :     }
     355              : 
     356        10108 :     if (!options.no_psqlrc)
     357            0 :         process_psqlrc(argv[0]);
     358              : 
     359              :     /*
     360              :      * If any actions were given by user, process them in the order in which
     361              :      * they were specified.  Note single_txn is only effective in this mode.
     362              :      */
     363        10108 :     if (options.actions.head != NULL)
     364              :     {
     365              :         PGresult   *res;
     366              :         SimpleActionListCell *cell;
     367              : 
     368        10105 :         successResult = EXIT_SUCCESS;   /* silence compiler */
     369              : 
     370        10105 :         if (options.single_txn)
     371              :         {
     372            7 :             if ((res = PSQLexec("BEGIN")) == NULL)
     373              :             {
     374            0 :                 if (pset.on_error_stop)
     375              :                 {
     376            0 :                     successResult = EXIT_USER;
     377            0 :                     goto error;
     378              :                 }
     379              :             }
     380              :             else
     381            7 :                 PQclear(res);
     382              :         }
     383              : 
     384        20233 :         for (cell = options.actions.head; cell; cell = cell->next)
     385              :         {
     386        10273 :             if (cell->action == ACT_SINGLE_QUERY)
     387              :             {
     388          439 :                 pg_logging_config(PG_LOG_FLAG_TERSE);
     389              : 
     390          439 :                 if (pset.echo == PSQL_ECHO_ALL)
     391            0 :                     puts(cell->val);
     392              : 
     393          439 :                 successResult = SendQuery(cell->val)
     394          438 :                     ? EXIT_SUCCESS : EXIT_FAILURE;
     395              :             }
     396         9834 :             else if (cell->action == ACT_SINGLE_SLASH)
     397              :             {
     398              :                 PsqlScanState scan_state;
     399              :                 ConditionalStack cond_stack;
     400              : 
     401            2 :                 pg_logging_config(PG_LOG_FLAG_TERSE);
     402              : 
     403            2 :                 if (pset.echo == PSQL_ECHO_ALL)
     404            0 :                     puts(cell->val);
     405              : 
     406            2 :                 scan_state = psql_scan_create(&psqlscan_callbacks);
     407            2 :                 psql_scan_setup(scan_state,
     408            2 :                                 cell->val, strlen(cell->val),
     409            2 :                                 pset.encoding, standard_strings());
     410            2 :                 cond_stack = conditional_stack_create();
     411            2 :                 psql_scan_set_passthrough(scan_state, cond_stack);
     412              : 
     413            2 :                 successResult = HandleSlashCmds(scan_state,
     414              :                                                 cond_stack,
     415              :                                                 NULL,
     416              :                                                 NULL) != PSQL_CMD_ERROR
     417            2 :                     ? EXIT_SUCCESS : EXIT_FAILURE;
     418              : 
     419            2 :                 psql_scan_destroy(scan_state);
     420            2 :                 conditional_stack_destroy(cond_stack);
     421              :             }
     422         9832 :             else if (cell->action == ACT_FILE)
     423              :             {
     424         9832 :                 successResult = process_file(cell->val, false);
     425              :             }
     426              :             else
     427              :             {
     428              :                 /* should never come here */
     429              :                 Assert(false);
     430              :             }
     431              : 
     432        10257 :             if (successResult != EXIT_SUCCESS && pset.on_error_stop)
     433          129 :                 break;
     434              :         }
     435              : 
     436        10089 :         if (options.single_txn)
     437              :         {
     438              :             /*
     439              :              * Rollback the contents of the single transaction if the caller
     440              :              * has set ON_ERROR_STOP and one of the steps has failed.  This
     441              :              * check needs to match the one done a couple of lines above.
     442              :              */
     443            7 :             res = PSQLexec((successResult != EXIT_SUCCESS && pset.on_error_stop) ?
     444              :                            "ROLLBACK" : "COMMIT");
     445            7 :             if (res == NULL)
     446              :             {
     447            0 :                 if (pset.on_error_stop)
     448              :                 {
     449            0 :                     successResult = EXIT_USER;
     450            0 :                     goto error;
     451              :                 }
     452              :             }
     453              :             else
     454            7 :                 PQclear(res);
     455              :         }
     456              : 
     457        10089 : error:
     458              :         ;
     459              :     }
     460              : 
     461              :     /*
     462              :      * or otherwise enter interactive main loop
     463              :      */
     464              :     else
     465              :     {
     466            3 :         pg_logging_config(PG_LOG_FLAG_TERSE);
     467            3 :         connection_warnings(true);
     468            3 :         if (!pset.quiet)
     469            3 :             printf(_("Type \"help\" for help.\n\n"));
     470            3 :         initializeInput(options.no_readline ? 0 : 1);
     471            3 :         successResult = MainLoop(stdin);
     472              :     }
     473              : 
     474              :     /* clean up */
     475        10092 :     if (pset.logfile)
     476            0 :         fclose(pset.logfile);
     477        10092 :     if (pset.db)
     478        10092 :         PQfinish(pset.db);
     479        10092 :     if (pset.dead_conn)
     480            0 :         PQfinish(pset.dead_conn);
     481        10092 :     setQFout(NULL);
     482              : 
     483        10092 :     return successResult;
     484              : }
     485              : 
     486              : 
     487              : /*
     488              :  * Parse command line options
     489              :  */
     490              : 
     491              : static void
     492        10311 : parse_psql_options(int argc, char *argv[], struct adhoc_opts *options)
     493              : {
     494              :     static struct option long_options[] =
     495              :     {
     496              :         {"echo-all", no_argument, NULL, 'a'},
     497              :         {"no-align", no_argument, NULL, 'A'},
     498              :         {"command", required_argument, NULL, 'c'},
     499              :         {"dbname", required_argument, NULL, 'd'},
     500              :         {"echo-queries", no_argument, NULL, 'e'},
     501              :         {"echo-errors", no_argument, NULL, 'b'},
     502              :         {"echo-hidden", no_argument, NULL, 'E'},
     503              :         {"file", required_argument, NULL, 'f'},
     504              :         {"field-separator", required_argument, NULL, 'F'},
     505              :         {"field-separator-zero", no_argument, NULL, 'z'},
     506              :         {"host", required_argument, NULL, 'h'},
     507              :         {"html", no_argument, NULL, 'H'},
     508              :         {"list", no_argument, NULL, 'l'},
     509              :         {"log-file", required_argument, NULL, 'L'},
     510              :         {"no-readline", no_argument, NULL, 'n'},
     511              :         {"single-transaction", no_argument, NULL, '1'},
     512              :         {"output", required_argument, NULL, 'o'},
     513              :         {"port", required_argument, NULL, 'p'},
     514              :         {"pset", required_argument, NULL, 'P'},
     515              :         {"quiet", no_argument, NULL, 'q'},
     516              :         {"record-separator", required_argument, NULL, 'R'},
     517              :         {"record-separator-zero", no_argument, NULL, '0'},
     518              :         {"single-step", no_argument, NULL, 's'},
     519              :         {"single-line", no_argument, NULL, 'S'},
     520              :         {"tuples-only", no_argument, NULL, 't'},
     521              :         {"table-attr", required_argument, NULL, 'T'},
     522              :         {"username", required_argument, NULL, 'U'},
     523              :         {"set", required_argument, NULL, 'v'},
     524              :         {"variable", required_argument, NULL, 'v'},
     525              :         {"version", no_argument, NULL, 'V'},
     526              :         {"no-password", no_argument, NULL, 'w'},
     527              :         {"password", no_argument, NULL, 'W'},
     528              :         {"expanded", no_argument, NULL, 'x'},
     529              :         {"no-psqlrc", no_argument, NULL, 'X'},
     530              :         {"help", optional_argument, NULL, 1},
     531              :         {"csv", no_argument, NULL, 2},
     532              :         {NULL, 0, NULL, 0}
     533              :     };
     534              : 
     535              :     int         optindex;
     536              :     int         c;
     537              : 
     538        10311 :     memset(options, 0, sizeof *options);
     539              : 
     540        77080 :     while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01",
     541        77080 :                             long_options, &optindex)) != -1)
     542              :     {
     543        66772 :         switch (c)
     544              :         {
     545         1322 :             case 'a':
     546         1322 :                 SetVariable(pset.vars, "ECHO", "all");
     547         1322 :                 break;
     548         8714 :             case 'A':
     549         8714 :                 pset.popt.topt.format = PRINT_UNALIGNED;
     550         8714 :                 break;
     551            0 :             case 'b':
     552            0 :                 SetVariable(pset.vars, "ECHO", "errors");
     553            0 :                 break;
     554          478 :             case 'c':
     555          478 :                 if (optarg[0] == '\\')
     556            2 :                     simple_action_list_append(&options->actions,
     557              :                                               ACT_SINGLE_SLASH,
     558            2 :                                               optarg + 1);
     559              :                 else
     560          476 :                     simple_action_list_append(&options->actions,
     561              :                                               ACT_SINGLE_QUERY,
     562              :                                               optarg);
     563          478 :                 break;
     564        10201 :             case 'd':
     565        10201 :                 options->dbname = pg_strdup(optarg);
     566        10201 :                 break;
     567           10 :             case 'e':
     568           10 :                 SetVariable(pset.vars, "ECHO", "queries");
     569           10 :                 break;
     570            0 :             case 'E':
     571            0 :                 SetVariableBool(pset.vars, "ECHO_HIDDEN");
     572            0 :                 break;
     573         7579 :             case 'f':
     574         7579 :                 simple_action_list_append(&options->actions,
     575              :                                           ACT_FILE,
     576              :                                           optarg);
     577         7579 :                 break;
     578            2 :             case 'F':
     579            2 :                 pset.popt.topt.fieldSep.separator = pg_strdup(optarg);
     580            2 :                 pset.popt.topt.fieldSep.separator_zero = false;
     581            2 :                 break;
     582           10 :             case 'h':
     583           10 :                 options->host = pg_strdup(optarg);
     584           10 :                 break;
     585            0 :             case 'H':
     586            0 :                 pset.popt.topt.format = PRINT_HTML;
     587            0 :                 break;
     588            0 :             case 'l':
     589            0 :                 options->list_dbs = true;
     590            0 :                 break;
     591            0 :             case 'L':
     592            0 :                 options->logfilename = pg_strdup(optarg);
     593            0 :                 break;
     594            0 :             case 'n':
     595            0 :                 options->no_readline = true;
     596            0 :                 break;
     597            0 :             case 'o':
     598            0 :                 if (!setQFout(optarg))
     599            0 :                     exit(EXIT_FAILURE);
     600            0 :                 break;
     601           11 :             case 'p':
     602           11 :                 options->port = pg_strdup(optarg);
     603           11 :                 break;
     604            2 :             case 'P':
     605              :                 {
     606              :                     char       *value;
     607              :                     char       *equal_loc;
     608              :                     bool        result;
     609              : 
     610            2 :                     value = pg_strdup(optarg);
     611            2 :                     equal_loc = strchr(value, '=');
     612            2 :                     if (!equal_loc)
     613            0 :                         result = do_pset(value, NULL, &pset.popt, true);
     614              :                     else
     615              :                     {
     616            2 :                         *equal_loc = '\0';
     617            2 :                         result = do_pset(value, equal_loc + 1, &pset.popt, true);
     618              :                     }
     619              : 
     620            2 :                     if (!result)
     621            0 :                         pg_fatal("could not set printing parameter \"%s\"", value);
     622              : 
     623            2 :                     free(value);
     624            2 :                     break;
     625              :                 }
     626         9146 :             case 'q':
     627         9146 :                 SetVariableBool(pset.vars, "QUIET");
     628         9146 :                 break;
     629            0 :             case 'R':
     630            0 :                 pset.popt.topt.recordSep.separator = pg_strdup(optarg);
     631            0 :                 pset.popt.topt.recordSep.separator_zero = false;
     632            0 :                 break;
     633            0 :             case 's':
     634            0 :                 SetVariableBool(pset.vars, "SINGLESTEP");
     635            0 :                 break;
     636            0 :             case 'S':
     637            0 :                 SetVariableBool(pset.vars, "SINGLELINE");
     638            0 :                 break;
     639         8707 :             case 't':
     640         8707 :                 pset.popt.topt.tuples_only = true;
     641         8707 :                 break;
     642            0 :             case 'T':
     643            0 :                 pset.popt.topt.tableAttr = pg_strdup(optarg);
     644            0 :                 break;
     645           22 :             case 'U':
     646           22 :                 options->username = pg_strdup(optarg);
     647           22 :                 break;
     648         9805 :             case 'v':
     649              :                 {
     650              :                     char       *value;
     651              :                     char       *equal_loc;
     652              : 
     653         9805 :                     value = pg_strdup(optarg);
     654         9805 :                     equal_loc = strchr(value, '=');
     655         9805 :                     if (!equal_loc)
     656              :                     {
     657            0 :                         if (!DeleteVariable(pset.vars, value))
     658            0 :                             exit(EXIT_FAILURE); /* error already printed */
     659              :                     }
     660              :                     else
     661              :                     {
     662         9805 :                         *equal_loc = '\0';
     663         9805 :                         if (!SetVariable(pset.vars, value, equal_loc + 1))
     664            0 :                             exit(EXIT_FAILURE); /* error already printed */
     665              :                     }
     666              : 
     667         9805 :                     free(value);
     668         9805 :                     break;
     669              :                 }
     670            0 :             case 'V':
     671            0 :                 showVersion();
     672            0 :                 exit(EXIT_SUCCESS);
     673          445 :             case 'w':
     674          445 :                 pset.getPassword = TRI_NO;
     675          445 :                 break;
     676            0 :             case 'W':
     677            0 :                 pset.getPassword = TRI_YES;
     678            0 :                 break;
     679            0 :             case 'x':
     680            0 :                 pset.popt.topt.expanded = true;
     681            0 :                 break;
     682        10308 :             case 'X':
     683        10308 :                 options->no_psqlrc = true;
     684        10308 :                 break;
     685            0 :             case 'z':
     686            0 :                 pset.popt.topt.fieldSep.separator_zero = true;
     687            0 :                 break;
     688            0 :             case '0':
     689            0 :                 pset.popt.topt.recordSep.separator_zero = true;
     690            0 :                 break;
     691            7 :             case '1':
     692            7 :                 options->single_txn = true;
     693            7 :                 break;
     694            1 :             case '?':
     695            1 :                 if (optind <= argc &&
     696            1 :                     strcmp(argv[optind - 1], "-?") == 0)
     697              :                 {
     698              :                     /* actual help option given */
     699            0 :                     usage(NOPAGER);
     700            0 :                     exit(EXIT_SUCCESS);
     701              :                 }
     702              :                 else
     703              :                 {
     704              :                     /* getopt error (unknown option or missing argument) */
     705            1 :                     goto unknown_option;
     706              :                 }
     707              :                 break;
     708            2 :             case 1:
     709              :                 {
     710            2 :                     if (!optarg || strcmp(optarg, "options") == 0)
     711            0 :                         usage(NOPAGER);
     712            2 :                     else if (optarg && strcmp(optarg, "commands") == 0)
     713            1 :                         slashUsage(NOPAGER);
     714            1 :                     else if (optarg && strcmp(optarg, "variables") == 0)
     715            1 :                         helpVariables(NOPAGER);
     716              :                     else
     717            0 :                         goto unknown_option;
     718              : 
     719            2 :                     exit(EXIT_SUCCESS);
     720              :                 }
     721              :                 break;
     722            0 :             case 2:
     723            0 :                 pset.popt.topt.format = PRINT_CSV;
     724            0 :                 break;
     725              :             default:
     726            1 :         unknown_option:
     727              :                 /* getopt_long already emitted a complaint */
     728            1 :                 pg_log_error_hint("Try \"%s --help\" for more information.",
     729              :                                   pset.progname);
     730            1 :                 exit(EXIT_FAILURE);
     731              :         }
     732              :     }
     733              : 
     734              :     /*
     735              :      * if we still have arguments, use it as the database name and username
     736              :      */
     737        10433 :     while (argc - optind >= 1)
     738              :     {
     739          125 :         if (!options->dbname)
     740          125 :             options->dbname = argv[optind];
     741            0 :         else if (!options->username)
     742            0 :             options->username = argv[optind];
     743            0 :         else if (!pset.quiet)
     744            0 :             pg_log_warning("extra command-line argument \"%s\" ignored",
     745              :                            argv[optind]);
     746              : 
     747          125 :         optind++;
     748              :     }
     749        10308 : }
     750              : 
     751              : 
     752              : /*
     753              :  * Append a new item to the end of the SimpleActionList.
     754              :  * Note that "val" is copied if it's not NULL.
     755              :  */
     756              : static void
     757        10510 : simple_action_list_append(SimpleActionList *list,
     758              :                           enum _actions action, const char *val)
     759              : {
     760              :     SimpleActionListCell *cell;
     761              : 
     762        10510 :     cell = pg_malloc_object(SimpleActionListCell);
     763              : 
     764        10510 :     cell->next = NULL;
     765        10510 :     cell->action = action;
     766        10510 :     if (val)
     767         8057 :         cell->val = pg_strdup(val);
     768              :     else
     769         2453 :         cell->val = NULL;
     770              : 
     771        10510 :     if (list->tail)
     772          205 :         list->tail->next = cell;
     773              :     else
     774        10305 :         list->head = cell;
     775        10510 :     list->tail = cell;
     776        10510 : }
     777              : 
     778              : 
     779              : /*
     780              :  * Load .psqlrc file, if found.
     781              :  */
     782              : static void
     783            0 : process_psqlrc(char *argv0)
     784              : {
     785              :     char        home[MAXPGPATH];
     786              :     char        rc_file[MAXPGPATH];
     787              :     char        my_exec_path[MAXPGPATH];
     788              :     char        etc_path[MAXPGPATH];
     789            0 :     char       *envrc = getenv("PSQLRC");
     790              : 
     791            0 :     if (find_my_exec(argv0, my_exec_path) < 0)
     792            0 :         pg_fatal("could not find own program executable");
     793              : 
     794            0 :     get_etc_path(my_exec_path, etc_path);
     795              : 
     796            0 :     snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC);
     797            0 :     process_psqlrc_file(rc_file);
     798              : 
     799            0 :     if (envrc != NULL && strlen(envrc) > 0)
     800            0 :     {
     801              :         /* might need to free() this */
     802            0 :         char       *envrc_alloc = pstrdup(envrc);
     803              : 
     804            0 :         expand_tilde(&envrc_alloc);
     805            0 :         process_psqlrc_file(envrc_alloc);
     806              :     }
     807            0 :     else if (get_home_path(home))
     808              :     {
     809            0 :         snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC);
     810            0 :         process_psqlrc_file(rc_file);
     811              :     }
     812            0 : }
     813              : 
     814              : 
     815              : 
     816              : static void
     817            0 : process_psqlrc_file(char *filename)
     818              : {
     819              :     char       *psqlrc_minor,
     820              :                *psqlrc_major;
     821              : 
     822              : #if defined(WIN32) && (!defined(__MINGW32__))
     823              : #define R_OK 4
     824              : #endif
     825              : 
     826            0 :     psqlrc_minor = psprintf("%s-%s", filename, PG_VERSION);
     827            0 :     psqlrc_major = psprintf("%s-%s", filename, PG_MAJORVERSION);
     828              : 
     829              :     /* check for minor version first, then major, then no version */
     830            0 :     if (access(psqlrc_minor, R_OK) == 0)
     831            0 :         (void) process_file(psqlrc_minor, false);
     832            0 :     else if (access(psqlrc_major, R_OK) == 0)
     833            0 :         (void) process_file(psqlrc_major, false);
     834            0 :     else if (access(filename, R_OK) == 0)
     835            0 :         (void) process_file(filename, false);
     836              : 
     837            0 :     free(psqlrc_minor);
     838            0 :     free(psqlrc_major);
     839            0 : }
     840              : 
     841              : 
     842              : 
     843              : /* showVersion
     844              :  *
     845              :  * This output format is intended to match GNU standards.
     846              :  */
     847              : static void
     848           20 : showVersion(void)
     849              : {
     850           20 :     puts("psql (PostgreSQL) " PG_VERSION);
     851           20 : }
     852              : 
     853              : 
     854              : 
     855              : /*
     856              :  * Substitute hooks and assign hooks for psql variables.
     857              :  *
     858              :  * This isn't an amazingly good place for them, but neither is anywhere else.
     859              :  *
     860              :  * By policy, every special variable that controls any psql behavior should
     861              :  * have one or both hooks, even if they're just no-ops.  This ensures that
     862              :  * the variable will remain present in variables.c's list even when unset,
     863              :  * which ensures that it's known to tab completion.
     864              :  */
     865              : 
     866              : static char *
     867       142856 : bool_substitute_hook(char *newval)
     868              : {
     869       142856 :     if (newval == NULL)
     870              :     {
     871              :         /* "\unset FOO" becomes "\set FOO off" */
     872       103114 :         newval = pg_strdup("off");
     873              :     }
     874        39742 :     else if (newval[0] == '\0')
     875              :     {
     876              :         /* "\set FOO" becomes "\set FOO on" */
     877            4 :         pg_free(newval);
     878            4 :         newval = pg_strdup("on");
     879              :     }
     880       142856 :     return newval;
     881              : }
     882              : 
     883              : static bool
     884        20650 : autocommit_hook(const char *newval)
     885              : {
     886        20650 :     return ParseVariableBool(newval, "AUTOCOMMIT", &pset.autocommit);
     887              : }
     888              : 
     889              : static bool
     890        17472 : on_error_stop_hook(const char *newval)
     891              : {
     892        17472 :     return ParseVariableBool(newval, "ON_ERROR_STOP", &pset.on_error_stop);
     893              : }
     894              : 
     895              : static bool
     896        19529 : quiet_hook(const char *newval)
     897              : {
     898        19529 :     return ParseVariableBool(newval, "QUIET", &pset.quiet);
     899              : }
     900              : 
     901              : static bool
     902        10311 : singleline_hook(const char *newval)
     903              : {
     904        10311 :     return ParseVariableBool(newval, "SINGLELINE", &pset.singleline);
     905              : }
     906              : 
     907              : static bool
     908        10311 : singlestep_hook(const char *newval)
     909              : {
     910        10311 :     return ParseVariableBool(newval, "SINGLESTEP", &pset.singlestep);
     911              : }
     912              : 
     913              : static char *
     914        10364 : fetch_count_substitute_hook(char *newval)
     915              : {
     916        10364 :     if (newval == NULL)
     917        10335 :         newval = pg_strdup("0");
     918        10364 :     return newval;
     919              : }
     920              : 
     921              : static bool
     922        10364 : fetch_count_hook(const char *newval)
     923              : {
     924        10364 :     return ParseVariableNum(newval, "FETCH_COUNT", &pset.fetch_count);
     925              : }
     926              : 
     927              : static bool
     928        10311 : histfile_hook(const char *newval)
     929              : {
     930              :     /*
     931              :      * Someday we might try to validate the filename, but for now, this is
     932              :      * just a placeholder to ensure HISTFILE is known to tab completion.
     933              :      */
     934        10311 :     return true;
     935              : }
     936              : 
     937              : static char *
     938        10311 : histsize_substitute_hook(char *newval)
     939              : {
     940        10311 :     if (newval == NULL)
     941        10311 :         newval = pg_strdup("500");
     942        10311 :     return newval;
     943              : }
     944              : 
     945              : static bool
     946        10311 : histsize_hook(const char *newval)
     947              : {
     948        10311 :     return ParseVariableNum(newval, "HISTSIZE", &pset.histsize);
     949              : }
     950              : 
     951              : static char *
     952        10315 : watch_interval_substitute_hook(char *newval)
     953              : {
     954        10315 :     if (newval == NULL)
     955        10312 :         newval = pg_strdup(DEFAULT_WATCH_INTERVAL);
     956        10315 :     return newval;
     957              : }
     958              : 
     959              : static bool
     960        10315 : watch_interval_hook(const char *newval)
     961              : {
     962        10315 :     return ParseVariableDouble(newval, "WATCH_INTERVAL", &pset.watch_interval,
     963              :                                0, DEFAULT_WATCH_INTERVAL_MAX);
     964              : }
     965              : 
     966              : static char *
     967        10311 : ignoreeof_substitute_hook(char *newval)
     968              : {
     969              :     int         dummy;
     970              : 
     971              :     /*
     972              :      * This tries to mimic the behavior of bash, to wit "If set, the value is
     973              :      * the number of consecutive EOF characters which must be typed as the
     974              :      * first characters on an input line before bash exits.  If the variable
     975              :      * exists but does not have a numeric value, or has no value, the default
     976              :      * value is 10.  If it does not exist, EOF signifies the end of input to
     977              :      * the shell."  Unlike bash, however, we insist on the stored value
     978              :      * actually being a valid integer.
     979              :      */
     980        10311 :     if (newval == NULL)
     981        10311 :         newval = pg_strdup("0");
     982            0 :     else if (!ParseVariableNum(newval, NULL, &dummy))
     983            0 :         newval = pg_strdup("10");
     984        10311 :     return newval;
     985              : }
     986              : 
     987              : static bool
     988        10311 : ignoreeof_hook(const char *newval)
     989              : {
     990        10311 :     return ParseVariableNum(newval, "IGNOREEOF", &pset.ignoreeof);
     991              : }
     992              : 
     993              : static char *
     994        11669 : echo_substitute_hook(char *newval)
     995              : {
     996        11669 :     if (newval == NULL)
     997        10311 :         newval = pg_strdup("none");
     998        11669 :     return newval;
     999              : }
    1000              : 
    1001              : static bool
    1002        11669 : echo_hook(const char *newval)
    1003              : {
    1004              :     Assert(newval != NULL);     /* else substitute hook messed up */
    1005        11669 :     if (pg_strcasecmp(newval, "queries") == 0)
    1006           10 :         pset.echo = PSQL_ECHO_QUERIES;
    1007        11659 :     else if (pg_strcasecmp(newval, "errors") == 0)
    1008            4 :         pset.echo = PSQL_ECHO_ERRORS;
    1009        11655 :     else if (pg_strcasecmp(newval, "all") == 0)
    1010         1335 :         pset.echo = PSQL_ECHO_ALL;
    1011        10320 :     else if (pg_strcasecmp(newval, "none") == 0)
    1012        10320 :         pset.echo = PSQL_ECHO_NONE;
    1013              :     else
    1014              :     {
    1015            0 :         PsqlVarEnumError("ECHO", newval, "none, errors, queries, all");
    1016            0 :         return false;
    1017              :     }
    1018        11669 :     return true;
    1019              : }
    1020              : 
    1021              : static bool
    1022        10311 : echo_hidden_hook(const char *newval)
    1023              : {
    1024              :     Assert(newval != NULL);     /* else substitute hook messed up */
    1025        10311 :     if (pg_strcasecmp(newval, "noexec") == 0)
    1026            0 :         pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC;
    1027              :     else
    1028              :     {
    1029              :         bool        on_off;
    1030              : 
    1031        10311 :         if (ParseVariableBool(newval, NULL, &on_off))
    1032        10311 :             pset.echo_hidden = on_off ? PSQL_ECHO_HIDDEN_ON : PSQL_ECHO_HIDDEN_OFF;
    1033              :         else
    1034              :         {
    1035            0 :             PsqlVarEnumError("ECHO_HIDDEN", newval, "on, off, noexec");
    1036            0 :             return false;
    1037              :         }
    1038              :     }
    1039        10311 :     return true;
    1040              : }
    1041              : 
    1042              : static bool
    1043        10343 : on_error_rollback_hook(const char *newval)
    1044              : {
    1045              :     Assert(newval != NULL);     /* else substitute hook messed up */
    1046        10343 :     if (pg_strcasecmp(newval, "interactive") == 0)
    1047            0 :         pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE;
    1048              :     else
    1049              :     {
    1050              :         bool        on_off;
    1051              : 
    1052        10343 :         if (ParseVariableBool(newval, NULL, &on_off))
    1053        10339 :             pset.on_error_rollback = on_off ? PSQL_ERROR_ROLLBACK_ON : PSQL_ERROR_ROLLBACK_OFF;
    1054              :         else
    1055              :         {
    1056            4 :             PsqlVarEnumError("ON_ERROR_ROLLBACK", newval, "on, off, interactive");
    1057            4 :             return false;
    1058              :         }
    1059              :     }
    1060        10339 :     return true;
    1061              : }
    1062              : 
    1063              : static char *
    1064        10315 : comp_keyword_case_substitute_hook(char *newval)
    1065              : {
    1066        10315 :     if (newval == NULL)
    1067        10311 :         newval = pg_strdup("preserve-upper");
    1068        10315 :     return newval;
    1069              : }
    1070              : 
    1071              : static bool
    1072        10315 : comp_keyword_case_hook(const char *newval)
    1073              : {
    1074              :     Assert(newval != NULL);     /* else substitute hook messed up */
    1075        10315 :     if (pg_strcasecmp(newval, "preserve-upper") == 0)
    1076        10312 :         pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER;
    1077            3 :     else if (pg_strcasecmp(newval, "preserve-lower") == 0)
    1078            1 :         pset.comp_case = PSQL_COMP_CASE_PRESERVE_LOWER;
    1079            2 :     else if (pg_strcasecmp(newval, "upper") == 0)
    1080            1 :         pset.comp_case = PSQL_COMP_CASE_UPPER;
    1081            1 :     else if (pg_strcasecmp(newval, "lower") == 0)
    1082            1 :         pset.comp_case = PSQL_COMP_CASE_LOWER;
    1083              :     else
    1084              :     {
    1085            0 :         PsqlVarEnumError("COMP_KEYWORD_CASE", newval,
    1086              :                          "lower, upper, preserve-lower, preserve-upper");
    1087            0 :         return false;
    1088              :     }
    1089        10315 :     return true;
    1090              : }
    1091              : 
    1092              : static char *
    1093        10311 : histcontrol_substitute_hook(char *newval)
    1094              : {
    1095        10311 :     if (newval == NULL)
    1096        10311 :         newval = pg_strdup("none");
    1097        10311 :     return newval;
    1098              : }
    1099              : 
    1100              : static bool
    1101        10311 : histcontrol_hook(const char *newval)
    1102              : {
    1103              :     Assert(newval != NULL);     /* else substitute hook messed up */
    1104        10311 :     if (pg_strcasecmp(newval, "ignorespace") == 0)
    1105            0 :         pset.histcontrol = hctl_ignorespace;
    1106        10311 :     else if (pg_strcasecmp(newval, "ignoredups") == 0)
    1107            0 :         pset.histcontrol = hctl_ignoredups;
    1108        10311 :     else if (pg_strcasecmp(newval, "ignoreboth") == 0)
    1109            0 :         pset.histcontrol = hctl_ignoreboth;
    1110        10311 :     else if (pg_strcasecmp(newval, "none") == 0)
    1111        10311 :         pset.histcontrol = hctl_none;
    1112              :     else
    1113              :     {
    1114            0 :         PsqlVarEnumError("HISTCONTROL", newval,
    1115              :                          "none, ignorespace, ignoredups, ignoreboth");
    1116            0 :         return false;
    1117              :     }
    1118        10311 :     return true;
    1119              : }
    1120              : 
    1121              : static bool
    1122        20622 : prompt1_hook(const char *newval)
    1123              : {
    1124        20622 :     pset.prompt1 = newval ? newval : "";
    1125        20622 :     return true;
    1126              : }
    1127              : 
    1128              : static bool
    1129        20622 : prompt2_hook(const char *newval)
    1130              : {
    1131        20622 :     pset.prompt2 = newval ? newval : "";
    1132        20622 :     return true;
    1133              : }
    1134              : 
    1135              : static bool
    1136        20622 : prompt3_hook(const char *newval)
    1137              : {
    1138        20622 :     pset.prompt3 = newval ? newval : "";
    1139        20622 :     return true;
    1140              : }
    1141              : 
    1142              : static char *
    1143        10422 : verbosity_substitute_hook(char *newval)
    1144              : {
    1145        10422 :     if (newval == NULL)
    1146        10311 :         newval = pg_strdup("default");
    1147        10422 :     return newval;
    1148              : }
    1149              : 
    1150              : static bool
    1151        10422 : verbosity_hook(const char *newval)
    1152              : {
    1153              :     Assert(newval != NULL);     /* else substitute hook messed up */
    1154        10422 :     if (pg_strcasecmp(newval, "default") == 0)
    1155        10358 :         pset.verbosity = PQERRORS_DEFAULT;
    1156           64 :     else if (pg_strcasecmp(newval, "verbose") == 0)
    1157            0 :         pset.verbosity = PQERRORS_VERBOSE;
    1158           64 :     else if (pg_strcasecmp(newval, "terse") == 0)
    1159           38 :         pset.verbosity = PQERRORS_TERSE;
    1160           26 :     else if (pg_strcasecmp(newval, "sqlstate") == 0)
    1161           26 :         pset.verbosity = PQERRORS_SQLSTATE;
    1162              :     else
    1163              :     {
    1164            0 :         PsqlVarEnumError("VERBOSITY", newval, "default, verbose, terse, sqlstate");
    1165            0 :         return false;
    1166              :     }
    1167              : 
    1168        10422 :     if (pset.db)
    1169          111 :         PQsetErrorVerbosity(pset.db, pset.verbosity);
    1170        10422 :     return true;
    1171              : }
    1172              : 
    1173              : static bool
    1174        20631 : show_all_results_hook(const char *newval)
    1175              : {
    1176        20631 :     return ParseVariableBool(newval, "SHOW_ALL_RESULTS", &pset.show_all_results);
    1177              : }
    1178              : 
    1179              : static char *
    1180        10343 : show_context_substitute_hook(char *newval)
    1181              : {
    1182        10343 :     if (newval == NULL)
    1183        10312 :         newval = pg_strdup("errors");
    1184        10343 :     return newval;
    1185              : }
    1186              : 
    1187              : static bool
    1188        10343 : show_context_hook(const char *newval)
    1189              : {
    1190              :     Assert(newval != NULL);     /* else substitute hook messed up */
    1191        10343 :     if (pg_strcasecmp(newval, "never") == 0)
    1192            9 :         pset.show_context = PQSHOW_CONTEXT_NEVER;
    1193        10334 :     else if (pg_strcasecmp(newval, "errors") == 0)
    1194        10324 :         pset.show_context = PQSHOW_CONTEXT_ERRORS;
    1195           10 :     else if (pg_strcasecmp(newval, "always") == 0)
    1196           10 :         pset.show_context = PQSHOW_CONTEXT_ALWAYS;
    1197              :     else
    1198              :     {
    1199            0 :         PsqlVarEnumError("SHOW_CONTEXT", newval, "never, errors, always");
    1200            0 :         return false;
    1201              :     }
    1202              : 
    1203        10343 :     if (pset.db)
    1204           32 :         PQsetErrorContextVisibility(pset.db, pset.show_context);
    1205        10343 :     return true;
    1206              : }
    1207              : 
    1208              : static bool
    1209        11657 : hide_compression_hook(const char *newval)
    1210              : {
    1211        11657 :     return ParseVariableBool(newval, "HIDE_TOAST_COMPRESSION",
    1212              :                              &pset.hide_compression);
    1213              : }
    1214              : 
    1215              : static bool
    1216        11641 : hide_tableam_hook(const char *newval)
    1217              : {
    1218        11641 :     return ParseVariableBool(newval, "HIDE_TABLEAM", &pset.hide_tableam);
    1219              : }
    1220              : 
    1221              : static void
    1222        10311 : EstablishVariableSpace(void)
    1223              : {
    1224        10311 :     pset.vars = CreateVariableSpace();
    1225              : 
    1226        10311 :     SetVariableHooks(pset.vars, "AUTOCOMMIT",
    1227              :                      bool_substitute_hook,
    1228              :                      autocommit_hook);
    1229        10311 :     SetVariableHooks(pset.vars, "ON_ERROR_STOP",
    1230              :                      bool_substitute_hook,
    1231              :                      on_error_stop_hook);
    1232        10311 :     SetVariableHooks(pset.vars, "QUIET",
    1233              :                      bool_substitute_hook,
    1234              :                      quiet_hook);
    1235        10311 :     SetVariableHooks(pset.vars, "SINGLELINE",
    1236              :                      bool_substitute_hook,
    1237              :                      singleline_hook);
    1238        10311 :     SetVariableHooks(pset.vars, "SINGLESTEP",
    1239              :                      bool_substitute_hook,
    1240              :                      singlestep_hook);
    1241        10311 :     SetVariableHooks(pset.vars, "FETCH_COUNT",
    1242              :                      fetch_count_substitute_hook,
    1243              :                      fetch_count_hook);
    1244        10311 :     SetVariableHooks(pset.vars, "HISTFILE",
    1245              :                      NULL,
    1246              :                      histfile_hook);
    1247        10311 :     SetVariableHooks(pset.vars, "HISTSIZE",
    1248              :                      histsize_substitute_hook,
    1249              :                      histsize_hook);
    1250        10311 :     SetVariableHooks(pset.vars, "IGNOREEOF",
    1251              :                      ignoreeof_substitute_hook,
    1252              :                      ignoreeof_hook);
    1253        10311 :     SetVariableHooks(pset.vars, "ECHO",
    1254              :                      echo_substitute_hook,
    1255              :                      echo_hook);
    1256        10311 :     SetVariableHooks(pset.vars, "ECHO_HIDDEN",
    1257              :                      bool_substitute_hook,
    1258              :                      echo_hidden_hook);
    1259        10311 :     SetVariableHooks(pset.vars, "ON_ERROR_ROLLBACK",
    1260              :                      bool_substitute_hook,
    1261              :                      on_error_rollback_hook);
    1262        10311 :     SetVariableHooks(pset.vars, "COMP_KEYWORD_CASE",
    1263              :                      comp_keyword_case_substitute_hook,
    1264              :                      comp_keyword_case_hook);
    1265        10311 :     SetVariableHooks(pset.vars, "HISTCONTROL",
    1266              :                      histcontrol_substitute_hook,
    1267              :                      histcontrol_hook);
    1268        10311 :     SetVariableHooks(pset.vars, "PROMPT1",
    1269              :                      NULL,
    1270              :                      prompt1_hook);
    1271        10311 :     SetVariableHooks(pset.vars, "PROMPT2",
    1272              :                      NULL,
    1273              :                      prompt2_hook);
    1274        10311 :     SetVariableHooks(pset.vars, "PROMPT3",
    1275              :                      NULL,
    1276              :                      prompt3_hook);
    1277        10311 :     SetVariableHooks(pset.vars, "VERBOSITY",
    1278              :                      verbosity_substitute_hook,
    1279              :                      verbosity_hook);
    1280        10311 :     SetVariableHooks(pset.vars, "SHOW_ALL_RESULTS",
    1281              :                      bool_substitute_hook,
    1282              :                      show_all_results_hook);
    1283        10311 :     SetVariableHooks(pset.vars, "SHOW_CONTEXT",
    1284              :                      show_context_substitute_hook,
    1285              :                      show_context_hook);
    1286        10311 :     SetVariableHooks(pset.vars, "HIDE_TOAST_COMPRESSION",
    1287              :                      bool_substitute_hook,
    1288              :                      hide_compression_hook);
    1289        10311 :     SetVariableHooks(pset.vars, "HIDE_TABLEAM",
    1290              :                      bool_substitute_hook,
    1291              :                      hide_tableam_hook);
    1292        10311 :     SetVariableHooks(pset.vars, "WATCH_INTERVAL",
    1293              :                      watch_interval_substitute_hook,
    1294              :                      watch_interval_hook);
    1295        10311 : }
        

Generated by: LCOV version 2.0-1