static PGresult *exec_query(const char *query);
 
-static char *previous_word(int point, int skip);
+static void get_previous_words(int point, char **previous_words, int nwords);
 
 #ifdef NOT_USED
 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
    /* This is the variable we'll return. */
    char      **matches = NULL;
 
-   /* These are going to contain some scannage of the input line. */
-   char       *prev_wd,
-              *prev2_wd,
-              *prev3_wd,
-              *prev4_wd,
-              *prev5_wd,
-              *prev6_wd;
+   /* This array will contain some scannage of the input line. */
+   char       *previous_words[6];
+
+   /* For compactness, we use these macros to reference previous_words[]. */
+#define prev_wd   (previous_words[0])
+#define prev2_wd  (previous_words[1])
+#define prev3_wd  (previous_words[2])
+#define prev4_wd  (previous_words[3])
+#define prev5_wd  (previous_words[4])
+#define prev6_wd  (previous_words[5])
 
    static const char *const sql_commands[] = {
        "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
    completion_info_charp2 = NULL;
 
    /*
-    * Scan the input line before our current position for the last five
+    * Scan the input line before our current position for the last few
     * words. According to those we'll make some smart decisions on what the
-    * user is probably intending to type. TODO: Use strtokx() to do this.
+    * user is probably intending to type.
     */
-   prev_wd = previous_word(start, 0);
-   prev2_wd = previous_word(start, 1);
-   prev3_wd = previous_word(start, 2);
-   prev4_wd = previous_word(start, 3);
-   prev5_wd = previous_word(start, 4);
-   prev6_wd = previous_word(start, 5);
+   get_previous_words(start, previous_words, lengthof(previous_words));
 
    /* If a backslash command was started, continue */
    if (text[0] == '\\')
    }
 
    /* If no previous word, suggest one of the basic sql commands */
-   else if (!prev_wd)
+   else if (prev_wd[0] == '\0')
        COMPLETE_WITH_LIST(sql_commands);
 
 /* CREATE */
    else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
        matches = completion_matches(text, create_command_generator);
 
-/* DROP, but watch out for DROP embedded in other commands */
+/* DROP, but not DROP embedded in other commands */
    /* complete with something you can drop */
    else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
-            pg_strcasecmp(prev2_wd, "DROP") == 0)
+            prev2_wd[0] == '\0')
        matches = completion_matches(text, drop_command_generator);
 
 /* ALTER */
    }
 
    /* free storage */
-   free(prev_wd);
-   free(prev2_wd);
-   free(prev3_wd);
-   free(prev4_wd);
-   free(prev5_wd);
+   {
+       int         i;
+
+       for (i = 0; i < lengthof(previous_words); i++)
+           free(previous_words[i]);
+   }
 
    /* Return our Grand List O' Matches */
    return matches;
 
 
 /*
- * Return the word (space delimited) before point. Set skip > 0 to
- * skip that many words; e.g. skip=1 finds the word before the
- * previous one. Return value is NULL or a malloc'ed string.
+ * Return the nwords word(s) before point.  Words are returned right to left,
+ * that is, previous_words[0] gets the last word before point.
+ * If we run out of words, remaining array elements are set to empty strings.
+ * Each array element is filled with a malloc'd string.
  */
-static char *
-previous_word(int point, int skip)
+static void
+get_previous_words(int point, char **previous_words, int nwords)
 {
-   int         i,
-               start = 0,
-               end = -1,
-               inquotes = 0;
-   char       *s;
    const char *buf = rl_line_buffer;   /* alias */
+   int         i;
 
-   /* first we look for a space or a parenthesis before the current word */
+   /* first we look for a non-word char before the current point */
    for (i = point - 1; i >= 0; i--)
        if (strchr(WORD_BREAKS, buf[i]))
            break;
    point = i;
 
-   while (skip-- >= 0)
+   while (nwords-- > 0)
    {
-       int         parentheses = 0;
+       int         start,
+                   end;
+       char       *s;
 
        /* now find the first non-space which then constitutes the end */
+       end = -1;
        for (i = point; i >= 0; i--)
-           if (buf[i] != ' ')
+       {
+           if (!isspace((unsigned char) buf[i]))
            {
                end = i;
                break;
            }
+       }
 
        /*
-        * If no end found we return null, because there is no word before the
-        * point
-        */
-       if (end == -1)
-           return NULL;
-
-       /*
-        * Otherwise we now look for the start. The start is either the last
-        * character before any space going backwards from the end, or it's
-        * simply character 0. We also handle open quotes and parentheses.
+        * If no end found we return an empty string, because there is no word
+        * before the point
         */
-       for (start = end; start > 0; start--)
+       if (end < 0)
+       {
+           point = end;
+           s = pg_strdup("");
+       }
+       else
        {
-           if (buf[start] == '"')
-               inquotes = !inquotes;
-           if (inquotes == 0)
+           /*
+            * Otherwise we now look for the start. The start is either the
+            * last character before any word-break character going backwards
+            * from the end, or it's simply character 0. We also handle open
+            * quotes and parentheses.
+            */
+           bool        inquotes = false;
+           int         parentheses = 0;
+
+           for (start = end; start > 0; start--)
            {
-               if (buf[start] == ')')
-                   parentheses++;
-               else if (buf[start] == '(')
+               if (buf[start] == '"')
+                   inquotes = !inquotes;
+               else if (!inquotes)
                {
-                   if (--parentheses <= 0)
+                   if (buf[start] == ')')
+                       parentheses++;
+                   else if (buf[start] == '(')
+                   {
+                       if (--parentheses <= 0)
+                           break;
+                   }
+                   else if (parentheses == 0 &&
+                            strchr(WORD_BREAKS, buf[start - 1]))
                        break;
                }
-               else if (parentheses == 0 &&
-                        strchr(WORD_BREAKS, buf[start - 1]))
-                   break;
            }
-       }
 
-       point = start - 1;
-   }
+           point = start - 1;
 
-   /* make a copy */
-   s = pg_malloc(end - start + 2);
-   strlcpy(s, &buf[start], end - start + 2);
+           /* make a copy of chars from start to end inclusive */
+           s = pg_malloc(end - start + 2);
+           strlcpy(s, &buf[start], end - start + 2);
+       }
 
-   return s;
+       *previous_words++ = s;
+   }
 }
 
 #ifdef NOT_USED