Commit f5a4370a authored by Tom Lane's avatar Tom Lane

Fix calculation of space needed for parsed words in tab completion.

Yesterday in commit d854118c, I had a serious brain fade leading me to
underestimate the number of words that the tab-completion logic could
divide a line into.  On input such as "(((((", each character will get
seen as a separate word, which means we do indeed sometimes need more
space for the words than for the original line.  Fix that.
parent 6f8cb1e2
...@@ -3652,41 +3652,39 @@ get_previous_words(int point, char **buffer, int *nwords) ...@@ -3652,41 +3652,39 @@ get_previous_words(int point, char **buffer, int *nwords)
{ {
char **previous_words; char **previous_words;
char *buf; char *buf;
int buflen; char *outptr;
int words_found = 0; int words_found = 0;
int i; int i;
/* /*
* Construct a writable buffer including both preceding and current lines * If we have anything in tab_completion_query_buf, paste it together with
* of the query, up to "point" which is where the currently completable * rl_line_buffer to construct the full query. Otherwise we can just use
* word begins. Because our definition of "word" is such that a non-word * rl_line_buffer as the input string.
* character must end each word, we can use this buffer to return the word
* data as-is, by placing a '\0' after each word.
*/ */
buflen = point + 1; if (tab_completion_query_buf && tab_completion_query_buf->len > 0)
if (tab_completion_query_buf) {
buflen += tab_completion_query_buf->len + 1; i = tab_completion_query_buf->len;
*buffer = buf = pg_malloc(buflen); buf = pg_malloc(point + i + 2);
i = 0; memcpy(buf, tab_completion_query_buf->data, i);
if (tab_completion_query_buf)
{
memcpy(buf, tab_completion_query_buf->data,
tab_completion_query_buf->len);
i += tab_completion_query_buf->len;
buf[i++] = '\n'; buf[i++] = '\n';
memcpy(buf + i, rl_line_buffer, point);
i += point;
buf[i] = '\0';
/* Readjust point to reference appropriate offset in buf */
point = i;
} }
memcpy(buf + i, rl_line_buffer, point); else
i += point; buf = rl_line_buffer;
buf[i] = '\0';
/* Readjust point to reference appropriate offset in buf */
point = i;
/* /*
* Allocate array of word start points. There can be at most length/2 + 1 * Allocate an array of string pointers and a buffer to hold the strings
* words in the buffer. * themselves. The worst case is that the line contains only
* non-whitespace WORD_BREAKS characters, making each one a separate word.
* This is usually much more space than we need, but it's cheaper than
* doing a separate malloc() for each word.
*/ */
previous_words = (char **) pg_malloc((point / 2 + 1) * sizeof(char *)); previous_words = (char **) pg_malloc(point * sizeof(char *));
*buffer = outptr = (char *) pg_malloc(point * 2);
/* /*
* First we look for a non-word char before the current point. (This is * First we look for a non-word char before the current point. (This is
...@@ -3752,14 +3750,20 @@ get_previous_words(int point, char **buffer, int *nwords) ...@@ -3752,14 +3750,20 @@ get_previous_words(int point, char **buffer, int *nwords)
} }
/* Return the word located at start to end inclusive */ /* Return the word located at start to end inclusive */
previous_words[words_found] = &buf[start]; previous_words[words_found++] = outptr;
buf[end + 1] = '\0'; i = end - start + 1;
words_found++; memcpy(outptr, &buf[start], i);
outptr += i;
*outptr++ = '\0';
/* Continue searching */ /* Continue searching */
point = start - 1; point = start - 1;
} }
/* Release parsing input workspace, if we made one above */
if (buf != rl_line_buffer)
free(buf);
*nwords = words_found; *nwords = words_found;
return previous_words; return previous_words;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment