From 6d2ff1de4d0b66eb0288e21021c3741b9df1df0d Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Tue, 4 Nov 2025 10:51:39 -0800 Subject: psql: Add tab completion for COPY ... PROGRAM. This commit adds tab completion support for COPY TO PROGRAM and COPY FROM PROGRAM syntax in psql. Author: Yugo Nagata Reviewed-by: Masahiko Sawada Discussion: https://postgr.es/m/20250605100835.b396f9d656df1018f65a4556@sraoss.co.jp --- src/bin/psql/tab-complete.in.c | 51 ++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 5f59564b1e3..316a2dafbf1 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -3336,48 +3336,61 @@ match_previous_words(int pattern_id, /* Complete COPY */ else if (Matches("COPY|\\copy", MatchAny)) COMPLETE_WITH("FROM", "TO"); - /* Complete COPY|\copy FROM|TO with filename or STDIN/STDOUT */ + /* Complete COPY|\copy FROM|TO with filename or STDIN/STDOUT/PROGRAM */ else if (Matches("COPY|\\copy", MatchAny, "FROM|TO")) { /* COPY requires quoted filename */ bool force_quote = HeadMatches("COPY"); if (TailMatches("FROM")) - COMPLETE_WITH_FILES_PLUS("", force_quote, "STDIN"); + COMPLETE_WITH_FILES_PLUS("", force_quote, "STDIN", "PROGRAM"); else - COMPLETE_WITH_FILES_PLUS("", force_quote, "STDOUT"); + COMPLETE_WITH_FILES_PLUS("", force_quote, "STDOUT", "PROGRAM"); } - /* Complete COPY TO */ - else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAny)) + /* Complete COPY|\copy FROM|TO PROGRAM */ + else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", "PROGRAM")) + COMPLETE_WITH_FILES("", HeadMatches("COPY")); /* COPY requires quoted + * filename */ + + /* Complete COPY TO [PROGRAM] */ + else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAnyExcept("PROGRAM")) || + Matches("COPY|\\copy", MatchAny, "TO", "PROGRAM", MatchAny)) COMPLETE_WITH("WITH ("); - /* Complete COPY FROM */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny)) + /* Complete COPY FROM [PROGRAM] */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM")) || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny)) COMPLETE_WITH("WITH (", "WHERE"); - /* Complete COPY FROM filename WITH ( */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, "WITH", "(")) + /* Complete COPY FROM [PROGRAM] filename WITH ( */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", "(") || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", "(")) COMPLETE_WITH(Copy_from_options); - /* Complete COPY TO filename WITH ( */ - else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAny, "WITH", "(")) + /* Complete COPY TO [PROGRAM] filename WITH ( */ + else if (Matches("COPY|\\copy", MatchAny, "TO", MatchAnyExcept("PROGRAM"), "WITH", "(") || + Matches("COPY|\\copy", MatchAny, "TO", "PROGRAM", MatchAny, "WITH", "(")) COMPLETE_WITH(Copy_to_options); - /* Complete COPY FROM|TO filename WITH (FORMAT */ - else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "(", "FORMAT")) + /* Complete COPY FROM|TO [PROGRAM] WITH (FORMAT */ + else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAnyExcept("PROGRAM"), "WITH", "(", "FORMAT") || + Matches("COPY|\\copy", MatchAny, "FROM|TO", "PROGRAM", MatchAny, "WITH", "(", "FORMAT")) COMPLETE_WITH("binary", "csv", "text"); - /* Complete COPY FROM filename WITH (ON_ERROR */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, "WITH", "(", "ON_ERROR")) + /* Complete COPY FROM [PROGRAM] filename WITH (ON_ERROR */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", "(", "ON_ERROR") || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", "(", "ON_ERROR")) COMPLETE_WITH("stop", "ignore"); - /* Complete COPY FROM filename WITH (LOG_VERBOSITY */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, "WITH", "(", "LOG_VERBOSITY")) + /* Complete COPY FROM [PROGRAM] filename WITH (LOG_VERBOSITY */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", "(", "LOG_VERBOSITY") || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", "(", "LOG_VERBOSITY")) COMPLETE_WITH("silent", "default", "verbose"); - /* Complete COPY FROM WITH () */ - else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, "WITH", MatchAny)) + /* Complete COPY FROM [PROGRAM] WITH () */ + else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAnyExcept("PROGRAM"), "WITH", MatchAny) || + Matches("COPY|\\copy", MatchAny, "FROM", "PROGRAM", MatchAny, "WITH", MatchAny)) COMPLETE_WITH("WHERE"); /* CREATE ACCESS METHOD */ -- cgit v1.2.3