LCOV - code coverage report
Current view: top level - src/bin/psql - input.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 18.1 % 171 31
Test Date: 2026-01-26 10:56:24 Functions: 20.0 % 10 2
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 16.8 % 107 18

             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                 :           0 : gets_interactive(const char *prompt, PQExpBuffer query_buf)
      68                 :             : {
      69                 :             : #ifdef USE_READLINE
      70         [ #  # ]:           0 :         if (useReadline)
      71                 :             :         {
      72                 :           0 :                 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                 :           0 :                 rl_reset_screen_size();
      83                 :             : #endif
      84                 :             : 
      85                 :             :                 /* Make current query_buf available to tab completion callback */
      86                 :           0 :                 tab_completion_query_buf = query_buf;
      87                 :             : 
      88                 :             :                 /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
      89                 :           0 :                 sigint_interrupt_enabled = true;
      90                 :             : 
      91                 :           0 :                 result = readline(prompt);
      92                 :             : 
      93                 :             :                 /* Disable SIGINT again */
      94                 :           0 :                 sigint_interrupt_enabled = false;
      95                 :             : 
      96                 :             :                 /* Pure neatnik-ism */
      97                 :           0 :                 tab_completion_query_buf = NULL;
      98                 :             : 
      99                 :           0 :                 return result;
     100                 :           0 :         }
     101                 :             : #endif
     102                 :             : 
     103                 :           0 :         fputs(prompt, stdout);
     104                 :           0 :         fflush(stdout);
     105                 :           0 :         return gets_fromFile(stdin);
     106                 :           0 : }
     107                 :             : 
     108                 :             : 
     109                 :             : /*
     110                 :             :  * Append the line to the history buffer, making sure there is a trailing '\n'
     111                 :             :  */
     112                 :             : void
     113                 :           0 : pg_append_history(const char *s, PQExpBuffer history_buf)
     114                 :             : {
     115                 :             : #ifdef USE_READLINE
     116   [ #  #  #  # ]:           0 :         if (useHistory && s)
     117                 :             :         {
     118                 :           0 :                 appendPQExpBufferStr(history_buf, s);
     119   [ #  #  #  # ]:           0 :                 if (!s[0] || s[strlen(s) - 1] != '\n')
     120                 :           0 :                         appendPQExpBufferChar(history_buf, '\n');
     121                 :           0 :         }
     122                 :             : #endif
     123                 :           0 : }
     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                 :          23 : pg_send_history(PQExpBuffer history_buf)
     136                 :             : {
     137                 :             : #ifdef USE_READLINE
     138                 :             :         static char *prev_hist = NULL;
     139                 :             : 
     140                 :          23 :         char       *s = history_buf->data;
     141                 :          23 :         int                     i;
     142                 :             : 
     143                 :             :         /* Trim any trailing \n's (OK to scribble on history_buf) */
     144   [ +  -  +  - ]:          23 :         for (i = strlen(s) - 1; i >= 0 && s[i] == '\n'; i--)
     145                 :             :                 ;
     146                 :          23 :         s[i + 1] = '\0';
     147                 :             : 
     148   [ -  +  #  # ]:          23 :         if (useHistory && s[0])
     149                 :             :         {
     150         [ #  # ]:           0 :                 if (((pset.histcontrol & hctl_ignorespace) &&
     151         [ #  # ]:           0 :                          s[0] == ' ') ||
     152         [ #  # ]:           0 :                         ((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                 :           0 :                 }
     157                 :             :                 else
     158                 :             :                 {
     159                 :             :                         /* Save each previous line for ignoredups processing */
     160                 :           0 :                         free(prev_hist);
     161                 :           0 :                         prev_hist = pg_strdup(s);
     162                 :             :                         /* And send it to readline */
     163                 :           0 :                         add_history(s);
     164                 :             :                         /* Count lines added to history for use later */
     165                 :           0 :                         history_lines_added++;
     166                 :             :                 }
     167                 :           0 :         }
     168                 :             : 
     169                 :          23 :         resetPQExpBuffer(history_buf);
     170                 :             : #endif
     171                 :          23 : }
     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                 :      120320 : gets_fromFile(FILE *source)
     187                 :             : {
     188                 :             :         static PQExpBuffer buffer = NULL;
     189                 :             : 
     190                 :      120320 :         char            line[1024];
     191                 :             : 
     192         [ +  + ]:      120320 :         if (buffer == NULL)                     /* first time through? */
     193                 :         269 :                 buffer = createPQExpBuffer();
     194                 :             :         else
     195                 :      120051 :                 resetPQExpBuffer(buffer);
     196                 :             : 
     197                 :      120321 :         for (;;)
     198                 :             :         {
     199                 :      120321 :                 char       *result;
     200                 :             : 
     201                 :             :                 /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
     202                 :      120321 :                 sigint_interrupt_enabled = true;
     203                 :             : 
     204                 :             :                 /* Get some data */
     205                 :      120321 :                 result = fgets(line, sizeof(line), source);
     206                 :             : 
     207                 :             :                 /* Disable SIGINT again */
     208                 :      120321 :                 sigint_interrupt_enabled = false;
     209                 :             : 
     210                 :             :                 /* EOF or error? */
     211         [ +  + ]:      120321 :                 if (result == NULL)
     212                 :             :                 {
     213         [ -  + ]:         267 :                         if (ferror(source))
     214                 :             :                         {
     215                 :           0 :                                 pg_log_error("could not read from input file: %m");
     216                 :           0 :                                 return NULL;
     217                 :             :                         }
     218                 :         267 :                         break;
     219                 :             :                 }
     220                 :             : 
     221                 :      120054 :                 appendPQExpBufferStr(buffer, line);
     222                 :             : 
     223   [ +  -  -  + ]:      120054 :                 if (PQExpBufferBroken(buffer))
     224                 :             :                 {
     225                 :           0 :                         pg_log_error("out of memory");
     226                 :           0 :                         return NULL;
     227                 :             :                 }
     228                 :             : 
     229                 :             :                 /* EOL? */
     230   [ +  -  +  + ]:      120054 :                 if (buffer->len > 0 && buffer->data[buffer->len - 1] == '\n')
     231                 :             :                 {
     232                 :      120053 :                         buffer->data[buffer->len - 1] = '\0';
     233                 :      120053 :                         return pg_strdup(buffer->data);
     234                 :             :                 }
     235      [ +  +  + ]:      120321 :         }
     236                 :             : 
     237         [ +  + ]:         267 :         if (buffer->len > 0)              /* EOF after reading some bufferload(s) */
     238                 :           1 :                 return pg_strdup(buffer->data);
     239                 :             : 
     240                 :             :         /* EOF, so return null */
     241                 :         266 :         return NULL;
     242                 :      120320 : }
     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                 :           0 : encode_history(void)
     300                 :             : {
     301   [ #  #  #  # ]:           0 :         BEGIN_ITERATE_HISTORY(cur_hist);
     302                 :             :         {
     303                 :           0 :                 char       *cur_ptr;
     304                 :             : 
     305                 :             :                 /* some platforms declare HIST_ENTRY.line as const char * */
     306         [ #  # ]:           0 :                 for (cur_ptr = (char *) cur_hist->line; *cur_ptr; cur_ptr++)
     307                 :             :                 {
     308         [ #  # ]:           0 :                         if (*cur_ptr == '\n')
     309                 :           0 :                                 *cur_ptr = NL_IN_HISTORY;
     310                 :           0 :                 }
     311                 :           0 :         }
     312                 :           0 :         END_ITERATE_HISTORY();
     313                 :           0 : }
     314                 :             : 
     315                 :             : /*
     316                 :             :  * Reverse the above encoding
     317                 :             :  */
     318                 :             : static void
     319                 :           0 : decode_history(void)
     320                 :             : {
     321   [ #  #  #  # ]:           0 :         BEGIN_ITERATE_HISTORY(cur_hist);
     322                 :             :         {
     323                 :           0 :                 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                 :           0 :                 }
     331                 :           0 :         }
     332                 :           0 :         END_ITERATE_HISTORY();
     333                 :           0 : }
     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                 :           0 : initializeInput(int flags)
     345                 :             : {
     346                 :             : #ifdef USE_READLINE
     347         [ #  # ]:           0 :         if (flags & 1)
     348                 :             :         {
     349                 :           0 :                 const char *histfile;
     350                 :           0 :                 char            home[MAXPGPATH];
     351                 :             : 
     352                 :           0 :                 useReadline = true;
     353                 :             : 
     354                 :             :                 /* set appropriate values for Readline's global variables */
     355                 :           0 :                 initialize_readline();
     356                 :             : 
     357                 :             : #ifdef HAVE_RL_VARIABLE_BIND
     358                 :             :                 /* set comment-begin to a useful value for SQL */
     359                 :           0 :                 (void) rl_variable_bind("comment-begin", "-- ");
     360                 :             : #endif
     361                 :             : 
     362                 :             :                 /* this reads ~/.inputrc, so do it after rl_variable_bind */
     363                 :           0 :                 rl_initialize();
     364                 :             : 
     365                 :           0 :                 useHistory = true;
     366                 :           0 :                 using_history();
     367                 :           0 :                 history_lines_added = 0;
     368                 :             : 
     369                 :           0 :                 histfile = GetVariable(pset.vars, "HISTFILE");
     370                 :             : 
     371         [ #  # ]:           0 :                 if (histfile == NULL)
     372                 :             :                 {
     373                 :           0 :                         char       *envhist;
     374                 :             : 
     375                 :           0 :                         envhist = getenv("PSQL_HISTORY");
     376   [ #  #  #  # ]:           0 :                         if (envhist != NULL && strlen(envhist) > 0)
     377                 :           0 :                                 histfile = envhist;
     378                 :           0 :                 }
     379                 :             : 
     380         [ #  # ]:           0 :                 if (histfile == NULL)
     381                 :             :                 {
     382         [ #  # ]:           0 :                         if (get_home_path(home))
     383                 :           0 :                                 psql_history = psprintf("%s/%s", home, PSQLHISTORY);
     384                 :           0 :                 }
     385                 :             :                 else
     386                 :             :                 {
     387                 :           0 :                         psql_history = pg_strdup(histfile);
     388                 :           0 :                         expand_tilde(&psql_history);
     389                 :             :                 }
     390                 :             : 
     391         [ #  # ]:           0 :                 if (psql_history)
     392                 :             :                 {
     393                 :           0 :                         read_history(psql_history);
     394                 :           0 :                         decode_history();
     395                 :           0 :                 }
     396                 :           0 :         }
     397                 :             : #endif
     398                 :             : 
     399                 :           0 :         atexit(finishInput);
     400                 :           0 : }
     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                 :           0 : saveHistory(char *fname, int max_lines)
     414                 :             : {
     415                 :           0 :         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         [ #  # ]:           0 :         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                 :           0 :                 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                 :           0 :                         int                     nlines;
     443                 :           0 :                         int                     fd;
     444                 :             : 
     445                 :             :                         /* truncate previous entries if needed */
     446         [ #  # ]:           0 :                         if (max_lines >= 0)
     447                 :             :                         {
     448         [ #  # ]:           0 :                                 nlines = Max(max_lines - history_lines_added, 0);
     449                 :           0 :                                 (void) history_truncate_file(fname, nlines);
     450                 :           0 :                         }
     451                 :             :                         /* append_history fails if file doesn't already exist :-( */
     452                 :           0 :                         fd = open(fname, O_CREAT | O_WRONLY | PG_BINARY, 0600);
     453         [ #  # ]:           0 :                         if (fd >= 0)
     454                 :           0 :                                 close(fd);
     455                 :             :                         /* append the appropriate number of lines */
     456         [ #  # ]:           0 :                         if (max_lines >= 0)
     457         [ #  # ]:           0 :                                 nlines = Min(max_lines, history_lines_added);
     458                 :             :                         else
     459                 :           0 :                                 nlines = history_lines_added;
     460                 :           0 :                         errnum = append_history(nlines, fname);
     461         [ #  # ]:           0 :                         if (errnum == 0)
     462                 :           0 :                                 return true;
     463         [ #  # ]:           0 :                 }
     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                 :           0 :         }
     478                 :           0 :         return false;
     479                 :           0 : }
     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                 :           0 : printHistory(const char *fname, unsigned short int pager)
     495                 :             : {
     496                 :             : #ifdef USE_READLINE
     497                 :           0 :         FILE       *output;
     498                 :           0 :         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                 :           0 :         }
     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                 :           0 :         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                 :           0 : }
     537                 :             : 
     538                 :             : 
     539                 :             : static void
     540                 :           0 : finishInput(void)
     541                 :             : {
     542                 :             : #ifdef USE_READLINE
     543   [ #  #  #  # ]:           0 :         if (useHistory && psql_history)
     544                 :             :         {
     545                 :           0 :                 (void) saveHistory(psql_history, pset.histsize);
     546                 :           0 :                 free(psql_history);
     547                 :           0 :                 psql_history = NULL;
     548                 :           0 :         }
     549                 :             : #endif
     550                 :           0 : }
        

Generated by: LCOV version 2.3.2-1