@@ -3652,41 +3652,39 @@ get_previous_words(int point, char **buffer, int *nwords)
36523652{
36533653 char * * previous_words ;
36543654 char * buf ;
3655- int buflen ;
3655+ char * outptr ;
36563656 int words_found = 0 ;
36573657 int i ;
36583658
36593659 /*
3660- * Construct a writable buffer including both preceding and current lines
3661- * of the query, up to "point" which is where the currently completable
3662- * word begins. Because our definition of "word" is such that a non-word
3663- * character must end each word, we can use this buffer to return the word
3664- * data as-is, by placing a '\0' after each word.
3660+ * If we have anything in tab_completion_query_buf, paste it together with
3661+ * rl_line_buffer to construct the full query. Otherwise we can just use
3662+ * rl_line_buffer as the input string.
36653663 */
3666- buflen = point + 1 ;
3667- if (tab_completion_query_buf )
3668- buflen += tab_completion_query_buf -> len + 1 ;
3669- * buffer = buf = pg_malloc (buflen );
3670- i = 0 ;
3671- if (tab_completion_query_buf )
3672- {
3673- memcpy (buf , tab_completion_query_buf -> data ,
3674- tab_completion_query_buf -> len );
3675- i += tab_completion_query_buf -> len ;
3664+ if (tab_completion_query_buf && tab_completion_query_buf -> len > 0 )
3665+ {
3666+ i = tab_completion_query_buf -> len ;
3667+ buf = pg_malloc (point + i + 2 );
3668+ memcpy (buf , tab_completion_query_buf -> data , i );
36763669 buf [i ++ ] = '\n' ;
3670+ memcpy (buf + i , rl_line_buffer , point );
3671+ i += point ;
3672+ buf [i ] = '\0' ;
3673+ /* Readjust point to reference appropriate offset in buf */
3674+ point = i ;
36773675 }
3678- memcpy (buf + i , rl_line_buffer , point );
3679- i += point ;
3680- buf [i ] = '\0' ;
3681-
3682- /* Readjust point to reference appropriate offset in buf */
3683- point = i ;
3676+ else
3677+ buf = rl_line_buffer ;
36843678
36853679 /*
3686- * Allocate array of word start points. There can be at most length/2 + 1
3687- * words in the buffer.
3680+ * Allocate an array of string pointers and a buffer to hold the strings
3681+ * themselves. The worst case is that the line contains only
3682+ * non-whitespace WORD_BREAKS characters, making each one a separate word.
3683+ * This is usually much more space than we need, but it's cheaper than
3684+ * doing a separate malloc() for each word.
36883685 */
3689- previous_words = (char * * ) pg_malloc ((point / 2 + 1 ) * sizeof (char * ));
3686+ previous_words = (char * * ) pg_malloc (point * sizeof (char * ));
3687+ * buffer = outptr = (char * ) pg_malloc (point * 2 );
36903688
36913689 /*
36923690 * 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)
37523750 }
37533751
37543752 /* Return the word located at start to end inclusive */
3755- previous_words [words_found ] = & buf [start ];
3756- buf [end + 1 ] = '\0' ;
3757- words_found ++ ;
3753+ previous_words [words_found ++ ] = outptr ;
3754+ i = end - start + 1 ;
3755+ memcpy (outptr , & buf [start ], i );
3756+ outptr += i ;
3757+ * outptr ++ = '\0' ;
37583758
37593759 /* Continue searching */
37603760 point = start - 1 ;
37613761 }
37623762
3763+ /* Release parsing input workspace, if we made one above */
3764+ if (buf != rl_line_buffer )
3765+ free (buf );
3766+
37633767 * nwords = words_found ;
37643768 return previous_words ;
37653769}
0 commit comments