LCOV - differential code coverage report
Current view: top level - src/bin/psql - input.c (source / functions) Coverage Total Hit LBC UIC UBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 78.0 % 132 103 1 16 12 59 1 43 17 57 2
Current Date: 2023-04-08 17:13:01 Functions: 90.0 % 10 9 1 6 1 2 1 6
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 78.0 % 132 103 1 16 12 59 1 43 17 57
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 52.9 % 17 9 1 6 1 2 1 6

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

Generated by: LCOV version v1.16-55-g56c0a2a