--- tab-complete.in.out.c.orig	2024-07-13 12:29:47.798865506 -0400
+++ tab-complete.in.out.c	2024-07-13 12:33:51.329264489 -0400
@@ -1398,7 +1398,8 @@ static const char *const view_optional_p
 
 /* Forward declaration of functions */
 static char **psql_completion(const char *text, int start, int end);
-static char **match_previous_words(const char *text, int start, int end,
+static char **match_previous_words(int pattern_id,
+								   const char *text, int start, int end,
 								   char **previous_words,
 								   int previous_words_count);
 static char *create_command_generator(const char *text, int state);
@@ -1931,17 +1932,78 @@ psql_completion(const char *text, int st
 		COMPLETE_WITH_LIST(sql_commands);
 
 	/* Else try completions based on matching patterns of previous words */
-	else if ((matches = match_previous_words(text, start, end,
+	else
+	{
+		/*
+		 * For now, we have to try the patterns in the order they are stored
+		 * (matching the order of switch cases in match_previous_words),
+		 * because some of the logic in match_previous_words assumes that
+		 * previous matches have been eliminated.  This is fairly
+		 * unprincipled, and it is likely that there are undesirable as well
+		 * as desirable interactions hidden in the order of the pattern
+		 * checks.  TODO: think about a better way to manage that.
+		 */
+		for (int tindx = 0; tindx < lengthof(tcpatterns); tindx++)
+		{
+			const TCPattern *tcpat = tcpatterns + tindx;
+			bool		match = false;
+
+			switch (tcpat->kind)
+			{
+				case Match:
+					match = MatchesArray(false,
+										 previous_words_count,
+										 previous_words,
+										 tcpat->nwords, tcpat->words);
+					break;
+				case MatchCS:
+					match = MatchesArray(true,
+										 previous_words_count,
+										 previous_words,
+										 tcpat->nwords, tcpat->words);
+					break;
+				case HeadMatch:
+					match = HeadMatchesArray(false,
+											 previous_words_count,
+											 previous_words,
+											 tcpat->nwords, tcpat->words);
+					break;
+				case HeadMatchCS:
+					match = HeadMatchesArray(true,
+											 previous_words_count,
+											 previous_words,
+											 tcpat->nwords, tcpat->words);
+					break;
+				case TailMatch:
+					match = TailMatchesArray(false,
+											 previous_words_count,
 											 previous_words,
-											 previous_words_count)) != NULL)
-		 /* skip */ ;
+											 tcpat->nwords, tcpat->words);
+					break;
+				case TailMatchCS:
+					match = TailMatchesArray(true,
+											 previous_words_count,
+											 previous_words,
+											 tcpat->nwords, tcpat->words);
+					break;
+			}
+			if (match)
+			{
+				matches = match_previous_words(tcpat->id, text, start, end,
+											   previous_words,
+											   previous_words_count);
+				if (matches != NULL)
+					break;
+			}
+		}
+	}
 
 	/*
 	 * Finally, we look through the list of "things", such as TABLE, INDEX and
 	 * check if that was the previous word. If so, execute the query to get a
 	 * list of them.
 	 */
-	else
+	if (matches == NULL)
 	{
 		const pgsql_thing_t *wac;
 
@@ -2000,17 +2062,16 @@ psql_completion(const char *text, int st
  * Returns a matches list, or NULL if no match.
  */
 static char **
-match_previous_words(const char *text, int start, int end,
+match_previous_words(int pattern_id,
+					 const char *text, int start, int end,
 					 char **previous_words, int previous_words_count)
 {
 	/* This is the variable we'll return. */
 	char	  **matches = NULL;
 
-	/* Dummy, to be replaced by switch */
-	if (0)
-		;
-			break;
-
+	/* Examine the pattern identified by the caller. */
+	switch (pattern_id)
+	{
 /* CREATE */
 	/* complete with something you can create */
 		case TailMatches("CREATE"):
@@ -5760,10 +5821,12 @@ match_previous_words(const char *text, i
 		case TailMatchesCS("\\sv*"):
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
 			break;
-		case TailMatchesCS("\\cd|\\e|\\edit|\\g|\\gx|\\i|\\include|" "\\ir|\\include_relative|\\o|\\out|" "\\s|\\w|\\write|\\lo_import"):
+		case TailMatchesCS("\\cd|\\e|\\edit|\\g|\\gx|\\i|\\include|\\ir|\\include_relative|\\o|\\out|\\s|\\w|\\write|\\lo_import"):
 		completion_charp = "\\";
 		completion_force_quote = false;
 		matches = rl_completion_matches(text, complete_from_files);
+			break;
+	}
 
 	return matches;
 }
