LCOV - code coverage report
Current view: top level - src/bin/psql - input.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 97 132 73.5 %
Date: 2020-06-03 10:06:28 Functions: 9 10 90.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13