LCOV - code coverage report
Current view: top level - src/bin/psql - input.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 26 132 19.7 %
Date: 2019-09-19 17:07:13 Functions: 2 10 20.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13