LCOV - code coverage report
Current view: top level - src/bin/psql - input.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 74.6 % 126 94
Test Date: 2026-07-23 06:15:50 Functions: 100.0 % 4 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 48.0 % 102 49

             Branch data     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/input.c
       7                 :             :  */
       8                 :             : #include "postgres_fe.h"
       9                 :             : 
      10                 :             : #ifndef WIN32
      11                 :             : #include <unistd.h>
      12                 :             : #endif
      13                 :             : #include <fcntl.h>
      14                 :             : #include <limits.h>
      15                 :             : 
      16                 :             : #include "common.h"
      17                 :             : #include "common/logging.h"
      18                 :             : #include "input.h"
      19                 :             : #include "settings.h"
      20                 :             : #include "tab-complete.h"
      21                 :             : 
      22                 :             : #ifndef WIN32
      23                 :             : #define PSQLHISTORY ".psql_history"
      24                 :             : #else
      25                 :             : #define PSQLHISTORY "psql_history"
      26                 :             : #endif
      27                 :             : 
      28                 :             : /* Runtime options for turning off readline and history */
      29                 :             : /* (of course there is no runtime command for doing that :) */
      30                 :             : #ifdef USE_READLINE
      31                 :             : static bool useReadline;
      32                 :             : static bool useHistory;
      33                 :             : 
      34                 :             : static char *psql_history;
      35                 :             : 
      36                 :             : static int  history_lines_added;
      37                 :             : 
      38                 :             : 
      39                 :             : /*
      40                 :             :  *  Preserve newlines in saved queries by mapping '\n' to NL_IN_HISTORY
      41                 :             :  *
      42                 :             :  *  It is assumed NL_IN_HISTORY will never be entered by the user
      43                 :             :  *  nor appear inside a multi-byte string.  0x00 is not properly
      44                 :             :  *  handled by the readline routines so it can not be used
      45                 :             :  *  for this purpose.
      46                 :             :  */
      47                 :             : #define NL_IN_HISTORY   0x01
      48                 :             : #endif
      49                 :             : 
      50                 :             : static void finishInput(void);
      51                 :             : 
      52                 :             : 
      53                 :             : /*
      54                 :             :  * gets_interactive()
      55                 :             :  *
      56                 :             :  * Gets a line of interactive input, using readline if desired.
      57                 :             :  *
      58                 :             :  * prompt: the prompt string to be used
      59                 :             :  * query_buf: buffer containing lines already read in the current command
      60                 :             :  * (query_buf is not modified here, but may be consulted for tab completion)
      61                 :             :  *
      62                 :             :  * The result is a malloc'd string.
      63                 :             :  *
      64                 :             :  * Caller *must* have set up sigint_interrupt_jmp before calling.
      65                 :             :  */
      66                 :             : char *
      67                 :             : gets_interactive(const char *prompt, PQExpBuffer query_buf)
      68                 :             : {
      69                 :             : #ifdef USE_READLINE
      70         [ +  - ]:          72 :     if (useReadline)
      71                 :             :     {
      72                 :             :         char       *result;
      73                 :             : 
      74                 :             :         /*
      75                 :             :          * Some versions of readline don't notice SIGWINCH signals that arrive
      76                 :             :          * when not actively reading input.  The simplest fix is to always
      77                 :             :          * re-read the terminal size.  This leaves a window for SIGWINCH to be
      78                 :             :          * missed between here and where readline() enables libreadline's
      79                 :             :          * signal handler, but that's probably short enough to be ignored.
      80                 :             :          */
      81                 :             : #ifdef HAVE_RL_RESET_SCREEN_SIZE
      82                 :          72 :         rl_reset_screen_size();
      83                 :             : #endif
      84                 :             : 
      85                 :             :         /* Make current query_buf available to tab completion callback */
      86                 :          72 :         tab_completion_query_buf = query_buf;
      87                 :             : 
      88                 :             :         /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
      89                 :          72 :         sigint_interrupt_enabled = true;
      90                 :             : 
      91                 :          72 :         result = readline(prompt);
      92                 :             : 
      93                 :             :         /* Disable SIGINT again */
      94                 :          72 :         sigint_interrupt_enabled = false;
      95                 :             : 
      96                 :             :         /* Pure neatnik-ism */
      97                 :          72 :         tab_completion_query_buf = NULL;
      98                 :             : 
      99                 :          72 :         return result;
     100                 :             :     }
     101                 :             : #endif
     102                 :             : 
     103                 :           0 :     fputs(prompt, stdout);
     104                 :           0 :     fflush(stdout);
     105                 :           0 :     return gets_fromFile(stdin);
     106                 :             : }
     107                 :             : 
     108                 :             : 
     109                 :             : /*
     110                 :             :  * Append the line to the history buffer, making sure there is a trailing '\n'
     111                 :             :  */
     112                 :             : void
     113                 :             : pg_append_history(const char *s, PQExpBuffer history_buf)
     114                 :             : {
     115                 :             : #ifdef USE_READLINE
     116   [ +  -  +  - ]:          66 :     if (useHistory && s)
     117                 :             :     {
     118                 :          66 :         appendPQExpBufferStr(history_buf, s);
     119   [ +  -  +  - ]:          66 :         if (!s[0] || s[strlen(s) - 1] != '\n')
     120                 :          66 :             appendPQExpBufferChar(history_buf, '\n');
     121                 :             :     }
     122                 :             : #endif
     123                 :          66 : }
     124                 :             : 
     125                 :             : 
     126                 :             : /*
     127                 :             :  * Emit accumulated history entry to readline's history mechanism,
     128                 :             :  * then reset the buffer to empty.
     129                 :             :  *
     130                 :             :  * Note: we write nothing if history_buf is empty, so extra calls to this
     131                 :             :  * function don't hurt.  There must have been at least one line added by
     132                 :             :  * pg_append_history before we'll do anything.
     133                 :             :  */
     134                 :             : void
     135                 :             : pg_send_history(PQExpBuffer history_buf)
     136                 :             : {
     137                 :             : #ifdef USE_READLINE
     138                 :             :     static char *prev_hist = NULL;
     139                 :             : 
     140                 :         298 :     char       *s = history_buf->data;
     141                 :             :     int         i;
     142                 :             : 
     143                 :             :     /* Trim any trailing \n's (OK to scribble on history_buf) */
     144   [ +  +  +  + ]:         363 :     for (i = strlen(s) - 1; i >= 0 && s[i] == '\n'; i--)
     145                 :             :         ;
     146                 :         298 :     s[i + 1] = '\0';
     147                 :             : 
     148   [ +  +  +  + ]:         298 :     if (useHistory && s[0])
     149                 :             :     {
     150         [ -  + ]:          65 :         if (((pset.histcontrol & hctl_ignorespace) &&
     151         [ #  # ]:           0 :              s[0] == ' ') ||
     152   [ -  +  -  - ]:          65 :             ((pset.histcontrol & hctl_ignoredups) &&
     153         [ #  # ]:           0 :              prev_hist && strcmp(s, prev_hist) == 0))
     154                 :             :         {
     155                 :             :             /* Ignore this line as far as history is concerned */
     156                 :             :         }
     157                 :             :         else
     158                 :             :         {
     159                 :             :             /* Save each previous line for ignoredups processing */
     160                 :          65 :             pg_free(prev_hist);
     161                 :          65 :             prev_hist = pg_strdup(s);
     162                 :             :             /* And send it to readline */
     163                 :          65 :             add_history(s);
     164                 :             :             /* Count lines added to history for use later */
     165                 :          65 :             history_lines_added++;
     166                 :             :         }
     167                 :             :     }
     168                 :             : 
     169                 :         298 :     resetPQExpBuffer(history_buf);
     170                 :             : #endif
     171                 :         298 : }
     172                 :             : 
     173                 :             : 
     174                 :             : /*
     175                 :             :  * gets_fromFile
     176                 :             :  *
     177                 :             :  * Gets a line of noninteractive input from a file (which could be stdin).
     178                 :             :  * The result is a malloc'd string, or NULL on EOF or input error.
     179                 :             :  *
     180                 :             :  * Caller *must* have set up sigint_interrupt_jmp before calling.
     181                 :             :  *
     182                 :             :  * Note: we re-use a static PQExpBuffer for each call.  This is to avoid
     183                 :             :  * leaking memory if interrupted by SIGINT.
     184                 :             :  */
     185                 :             : char *
     186                 :             : gets_fromFile(FILE *source)
     187                 :             : {
     188                 :             :     static PQExpBuffer buffer = NULL;
     189                 :             : 
     190                 :             :     char        line[1024];
     191                 :             : 
     192         [ +  + ]:      638808 :     if (buffer == NULL)         /* first time through? */
     193                 :       10187 :         buffer = createPQExpBuffer();
     194                 :             :     else
     195                 :      628621 :         resetPQExpBuffer(buffer);
     196                 :             : 
     197                 :             :     for (;;)
     198                 :        8080 :     {
     199                 :             :         char       *result;
     200                 :             : 
     201                 :             :         /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
     202                 :      646888 :         sigint_interrupt_enabled = true;
     203                 :             : 
     204                 :             :         /* Get some data */
     205                 :      646888 :         result = fgets(line, sizeof(line), source);
     206                 :             : 
     207                 :             :         /* Disable SIGINT again */
     208                 :      646888 :         sigint_interrupt_enabled = false;
     209                 :             : 
     210                 :             :         /* EOF or error? */
     211         [ +  + ]:      646888 :         if (result == NULL)
     212                 :             :         {
     213         [ -  + ]:       17886 :             if (ferror(source))
     214                 :             :             {
     215                 :           0 :                 pg_log_error("could not read from input file: %m");
     216                 :           0 :                 return NULL;
     217                 :             :             }
     218                 :       17886 :             break;
     219                 :             :         }
     220                 :             : 
     221                 :      629002 :         appendPQExpBufferStr(buffer, line);
     222                 :             : 
     223   [ +  -  -  + ]:      629002 :         if (PQExpBufferBroken(buffer))
     224                 :             :         {
     225                 :           0 :             pg_log_error("out of memory");
     226                 :           0 :             return NULL;
     227                 :             :         }
     228                 :             : 
     229                 :             :         /* EOL? */
     230   [ +  -  +  + ]:      629002 :         if (buffer->len > 0 && buffer->data[buffer->len - 1] == '\n')
     231                 :             :         {
     232                 :      620922 :             buffer->data[buffer->len - 1] = '\0';
     233                 :      620922 :             return pg_strdup(buffer->data);
     234                 :             :         }
     235                 :             :     }
     236                 :             : 
     237         [ +  + ]:       17886 :     if (buffer->len > 0)      /* EOF after reading some bufferload(s) */
     238                 :        8007 :         return pg_strdup(buffer->data);
     239                 :             : 
     240                 :             :     /* EOF, so return null */
     241                 :        9879 :     return NULL;
     242                 :             : }
     243                 :             : 
     244                 :             : 
     245                 :             : #ifdef USE_READLINE
     246                 :             : 
     247                 :             : /*
     248                 :             :  * Macros to iterate over each element of the history list in order
     249                 :             :  *
     250                 :             :  * You would think this would be simple enough, but in its inimitable fashion
     251                 :             :  * libedit has managed to break it: in libreadline we must use next_history()
     252                 :             :  * to go from oldest to newest, but in libedit we must use previous_history().
     253                 :             :  * To detect what to do, we make a trial call of previous_history(): if it
     254                 :             :  * fails, then either next_history() is what to use, or there's zero or one
     255                 :             :  * history entry so that it doesn't matter which direction we go.
     256                 :             :  *
     257                 :             :  * In case that wasn't disgusting enough: the code below is not as obvious as
     258                 :             :  * it might appear.  In some libedit releases history_set_pos(0) fails until
     259                 :             :  * at least one add_history() call has been done.  This is not an issue for
     260                 :             :  * printHistory() or encode_history(), which cannot be invoked before that has
     261                 :             :  * happened.  In decode_history(), that's not so, and what actually happens is
     262                 :             :  * that we are sitting on the newest entry to start with, previous_history()
     263                 :             :  * fails, and we iterate over all the entries using next_history().  So the
     264                 :             :  * decode_history() loop iterates over the entries in the wrong order when
     265                 :             :  * using such a libedit release, and if there were another attempt to use
     266                 :             :  * BEGIN_ITERATE_HISTORY() before some add_history() call had happened, it
     267                 :             :  * wouldn't work.  Fortunately we don't care about either of those things.
     268                 :             :  *
     269                 :             :  * Usage pattern is:
     270                 :             :  *
     271                 :             :  *      BEGIN_ITERATE_HISTORY(varname);
     272                 :             :  *      {
     273                 :             :  *          loop body referencing varname->line;
     274                 :             :  *      }
     275                 :             :  *      END_ITERATE_HISTORY();
     276                 :             :  */
     277                 :             : #define BEGIN_ITERATE_HISTORY(VARNAME) \
     278                 :             :     do { \
     279                 :             :         HIST_ENTRY *VARNAME; \
     280                 :             :         bool        use_prev_; \
     281                 :             :         \
     282                 :             :         history_set_pos(0); \
     283                 :             :         use_prev_ = (previous_history() != NULL); \
     284                 :             :         history_set_pos(0); \
     285                 :             :         for (VARNAME = current_history(); VARNAME != NULL; \
     286                 :             :              VARNAME = use_prev_ ? previous_history() : next_history()) \
     287                 :             :         { \
     288                 :             :             (void) 0
     289                 :             : 
     290                 :             : #define END_ITERATE_HISTORY() \
     291                 :             :         } \
     292                 :             :     } while(0)
     293                 :             : 
     294                 :             : 
     295                 :             : /*
     296                 :             :  * Convert newlines to NL_IN_HISTORY for safe saving in readline history file
     297                 :             :  */
     298                 :             : static void
     299                 :           1 : encode_history(void)
     300                 :             : {
     301   [ -  +  +  + ]:          42 :     BEGIN_ITERATE_HISTORY(cur_hist);
     302                 :             :     {
     303                 :             :         char       *cur_ptr;
     304                 :             : 
     305                 :             :         /* some platforms declare HIST_ENTRY.line as const char * */
     306         [ +  + ]:        1198 :         for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
     307                 :             :         {
     308         [ +  + ]:        1157 :             if (*cur_ptr == '\n')
     309                 :           1 :                 *cur_ptr = NL_IN_HISTORY;
     310                 :             :         }
     311                 :             :     }
     312                 :             :     END_ITERATE_HISTORY();
     313                 :           1 : }
     314                 :             : 
     315                 :             : /*
     316                 :             :  * Reverse the above encoding
     317                 :             :  */
     318                 :             : static void
     319                 :           3 : decode_history(void)
     320                 :             : {
     321   [ -  -  -  + ]:           3 :     BEGIN_ITERATE_HISTORY(cur_hist);
     322                 :             :     {
     323                 :             :         char       *cur_ptr;
     324                 :             : 
     325                 :             :         /* some platforms declare HIST_ENTRY.line as const char * */
     326         [ #  # ]:           0 :         for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
     327                 :             :         {
     328         [ #  # ]:           0 :             if (*cur_ptr == NL_IN_HISTORY)
     329                 :           0 :                 *cur_ptr = '\n';
     330                 :             :         }
     331                 :             :     }
     332                 :             :     END_ITERATE_HISTORY();
     333                 :           3 : }
     334                 :             : #endif                          /* USE_READLINE */
     335                 :             : 
     336                 :             : 
     337                 :             : /*
     338                 :             :  * Put any startup stuff related to input in here. It's good to maintain
     339                 :             :  * abstraction this way.
     340                 :             :  *
     341                 :             :  * The only "flag" right now is 1 for use readline & history.
     342                 :             :  */
     343                 :             : void
     344                 :             : initializeInput(int flags)
     345                 :             : {
     346                 :             : #ifdef USE_READLINE
     347         [ +  - ]:           3 :     if (flags & 1)
     348                 :             :     {
     349                 :             :         const char *histfile;
     350                 :             :         char        home[MAXPGPATH];
     351                 :             : 
     352                 :           3 :         useReadline = true;
     353                 :             : 
     354                 :             :         /* set appropriate values for Readline's global variables */
     355                 :           3 :         initialize_readline();
     356                 :             : 
     357                 :             : #ifdef HAVE_RL_VARIABLE_BIND
     358                 :             :         /* set comment-begin to a useful value for SQL */
     359                 :           3 :         (void) rl_variable_bind("comment-begin", "-- ");
     360                 :             : #endif
     361                 :             : 
     362                 :             :         /* this reads ~/.inputrc, so do it after rl_variable_bind */
     363                 :           3 :         rl_initialize();
     364                 :             : 
     365                 :           3 :         useHistory = true;
     366                 :           3 :         using_history();
     367                 :           3 :         history_lines_added = 0;
     368                 :             : 
     369                 :           3 :         histfile = GetVariable(pset.vars, "HISTFILE");
     370                 :             : 
     371         [ +  - ]:           3 :         if (histfile == NULL)
     372                 :             :         {
     373                 :             :             char       *envhist;
     374                 :             : 
     375                 :           3 :             envhist = getenv("PSQL_HISTORY");
     376   [ +  -  +  - ]:           3 :             if (envhist != NULL && strlen(envhist) > 0)
     377                 :           3 :                 histfile = envhist;
     378                 :             :         }
     379                 :             : 
     380         [ -  + ]:           3 :         if (histfile == NULL)
     381                 :             :         {
     382         [ #  # ]:           0 :             if (get_home_path(home))
     383                 :           0 :                 psql_history = psprintf("%s/%s", home, PSQLHISTORY);
     384                 :             :         }
     385                 :             :         else
     386                 :             :         {
     387                 :           3 :             psql_history = pg_strdup(histfile);
     388                 :           3 :             expand_tilde(&psql_history);
     389                 :             :         }
     390                 :             : 
     391         [ +  - ]:           3 :         if (psql_history)
     392                 :             :         {
     393                 :           3 :             read_history(psql_history);
     394                 :           3 :             decode_history();
     395                 :             :         }
     396                 :             :     }
     397                 :             : #endif
     398                 :             : 
     399                 :           3 :     atexit(finishInput);
     400                 :           3 : }
     401                 :             : 
     402                 :             : 
     403                 :             : /*
     404                 :             :  * This function saves the readline history when psql exits.
     405                 :             :  *
     406                 :             :  * fname: pathname of history file.  (Should really be "const char *",
     407                 :             :  * but some ancient versions of readline omit the const-decoration.)
     408                 :             :  *
     409                 :             :  * max_lines: if >= 0, limit history file to that many entries.
     410                 :             :  */
     411                 :             : #ifdef USE_READLINE
     412                 :             : static bool
     413                 :           3 : saveHistory(char *fname, int max_lines)
     414                 :             : {
     415                 :             :     int         errnum;
     416                 :             : 
     417                 :             :     /*
     418                 :             :      * Suppressing the write attempt when HISTFILE is set to /dev/null may
     419                 :             :      * look like a negligible optimization, but it's necessary on e.g. macOS,
     420                 :             :      * where write_history will fail because it tries to chmod the target
     421                 :             :      * file.
     422                 :             :      */
     423         [ +  + ]:           3 :     if (strcmp(fname, DEVNULL) != 0)
     424                 :             :     {
     425                 :             :         /*
     426                 :             :          * Encode \n, since otherwise readline will reload multiline history
     427                 :             :          * entries as separate lines.  (libedit doesn't really need this, but
     428                 :             :          * we do it anyway since it's too hard to tell which implementation we
     429                 :             :          * are using.)
     430                 :             :          */
     431                 :           1 :         encode_history();
     432                 :             : 
     433                 :             :         /*
     434                 :             :          * On newer versions of libreadline, truncate the history file as
     435                 :             :          * needed and then append what we've added.  This avoids overwriting
     436                 :             :          * history from other concurrent sessions (although there are still
     437                 :             :          * race conditions when two sessions exit at about the same time). If
     438                 :             :          * we don't have those functions, fall back to write_history().
     439                 :             :          */
     440                 :             : #if defined(HAVE_HISTORY_TRUNCATE_FILE) && defined(HAVE_APPEND_HISTORY)
     441                 :             :         {
     442                 :             :             int         nlines;
     443                 :             :             int         fd;
     444                 :             : 
     445                 :             :             /* truncate previous entries if needed */
     446         [ +  - ]:           1 :             if (max_lines >= 0)
     447                 :             :             {
     448                 :           1 :                 nlines = Max(max_lines - history_lines_added, 0);
     449                 :           1 :                 (void) history_truncate_file(fname, nlines);
     450                 :             :             }
     451                 :             :             /* append_history fails if file doesn't already exist :-( */
     452                 :           1 :             fd = open(fname, O_CREAT | O_WRONLY | PG_BINARY, 0600);
     453         [ +  - ]:           1 :             if (fd >= 0)
     454                 :           1 :                 close(fd);
     455                 :             :             /* append the appropriate number of lines */
     456         [ +  - ]:           1 :             if (max_lines >= 0)
     457                 :           1 :                 nlines = Min(max_lines, history_lines_added);
     458                 :             :             else
     459                 :           0 :                 nlines = history_lines_added;
     460                 :           1 :             errnum = append_history(nlines, fname);
     461         [ +  - ]:           1 :             if (errnum == 0)
     462                 :           1 :                 return true;
     463                 :             :         }
     464                 :             : #else                           /* don't have append support */
     465                 :             :         {
     466                 :             :             /* truncate what we have ... */
     467                 :             :             if (max_lines >= 0)
     468                 :             :                 stifle_history(max_lines);
     469                 :             :             /* ... and overwrite file.  Tough luck for concurrent sessions. */
     470                 :             :             errnum = write_history(fname);
     471                 :             :             if (errnum == 0)
     472                 :             :                 return true;
     473                 :             :         }
     474                 :             : #endif
     475                 :             : 
     476                 :           0 :         pg_log_error("could not save history to file \"%s\": %m", fname);
     477                 :             :     }
     478                 :           2 :     return false;
     479                 :             : }
     480                 :             : #endif
     481                 :             : 
     482                 :             : 
     483                 :             : 
     484                 :             : /*
     485                 :             :  * Print history to the specified file, or to the console if fname is NULL
     486                 :             :  * (psql \s command)
     487                 :             :  *
     488                 :             :  * We used to use saveHistory() for this purpose, but that doesn't permit
     489                 :             :  * use of a pager; moreover libedit's implementation behaves incompatibly
     490                 :             :  * (preferring to encode its output) and may fail outright when the target
     491                 :             :  * file is specified as /dev/tty.
     492                 :             :  */
     493                 :             : bool
     494                 :             : printHistory(const char *fname, unsigned short int pager)
     495                 :             : {
     496                 :             : #ifdef USE_READLINE
     497                 :             :     FILE       *output;
     498                 :             :     bool        is_pager;
     499                 :             : 
     500         [ #  # ]:           0 :     if (!useHistory)
     501                 :           0 :         return false;
     502                 :             : 
     503         [ #  # ]:           0 :     if (fname == NULL)
     504                 :             :     {
     505                 :             :         /* use pager, if enabled, when printing to console */
     506         [ #  # ]:           0 :         output = PageOutput(INT_MAX, pager ? &(pset.popt.topt) : NULL);
     507                 :           0 :         is_pager = true;
     508                 :             :     }
     509                 :             :     else
     510                 :             :     {
     511                 :           0 :         output = fopen(fname, "w");
     512         [ #  # ]:           0 :         if (output == NULL)
     513                 :             :         {
     514                 :           0 :             pg_log_error("could not save history to file \"%s\": %m", fname);
     515                 :           0 :             return false;
     516                 :             :         }
     517                 :           0 :         is_pager = false;
     518                 :             :     }
     519                 :             : 
     520   [ #  #  #  # ]:           0 :     BEGIN_ITERATE_HISTORY(cur_hist);
     521                 :             :     {
     522                 :           0 :         fprintf(output, "%s\n", cur_hist->line);
     523                 :             :     }
     524                 :             :     END_ITERATE_HISTORY();
     525                 :             : 
     526         [ #  # ]:           0 :     if (is_pager)
     527                 :           0 :         ClosePager(output);
     528                 :             :     else
     529                 :           0 :         fclose(output);
     530                 :             : 
     531                 :           0 :     return true;
     532                 :             : #else
     533                 :             :     pg_log_error("history is not supported by this installation");
     534                 :             :     return false;
     535                 :             : #endif
     536                 :             : }
     537                 :             : 
     538                 :             : 
     539                 :             : static void
     540                 :           3 : finishInput(void)
     541                 :             : {
     542                 :             : #ifdef USE_READLINE
     543   [ +  -  +  - ]:           3 :     if (useHistory && psql_history)
     544                 :             :     {
     545                 :           3 :         (void) saveHistory(psql_history, pset.histsize);
     546                 :           3 :         free(psql_history);
     547                 :           3 :         psql_history = NULL;
     548                 :             :     }
     549                 :             : #endif
     550                 :           3 : }
        

Generated by: LCOV version 2.0-1