From 1bdf05097a3f2fda11bc244628d19217409c2403 Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi Date: Thu, 7 Apr 2016 13:38:54 +0900 Subject: [PATCH 4/4] Refactoring tab-complete to make psql_completion code simpler. psql_completion consists of a sequence of "else-if"s and succeeding finishing code. This structure prevents us from having anything other than if-conditions and completion code in every then-clause in the else-if sequence. For the reason we had no way to have operations like modifying previous_words other than implement it is boolean functions always return false. This patch separates the else-if sequence into individual function "psql_completion_internal". This modification allows the sequence to be simple if sequence and allows us to put any code midst of the sequence. --- src/bin/psql/Makefile | 2 + src/bin/psql/tab-complete-macros.h | 479 +++++++++ src/bin/psql/tab-complete.c | 1864 +++++++++++++++--------------------- 3 files changed, 1241 insertions(+), 1104 deletions(-) create mode 100644 src/bin/psql/tab-complete-macros.h diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile index 1f6a289..51f88ba 100644 --- a/src/bin/psql/Makefile +++ b/src/bin/psql/Makefile @@ -47,6 +47,8 @@ ifeq ($(GCC),yes) psqlscanslash.o: CFLAGS += -Wno-error endif +tab-complete.o: tab-complete-macros.h + distprep: sql_help.h psqlscanslash.c install: all installdirs diff --git a/src/bin/psql/tab-complete-macros.h b/src/bin/psql/tab-complete-macros.h new file mode 100644 index 0000000..e7ca851 --- /dev/null +++ b/src/bin/psql/tab-complete-macros.h @@ -0,0 +1,479 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright (c) 2000-2016, PostgreSQL Global Development Group + * + * src/bin/psql/tab-complete-macros.h + */ +#ifndef TAB_COMPLETE_MACROS_H +#define TAB_COMPLETE_MACROS_H + +/* + * For compactness, we use these macros to reference previous_words[]. + * Caution: do not access a previous_words[] entry without having checked + * previous_words_count to be sure it's valid. In most cases below, that + * check is implicit in a TailMatches() or similar macro, but in some places + * we have to check it explicitly. + */ +#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]) +#define prev7_wd (previous_words[6]) +#define prev8_wd (previous_words[7]) +#define prev9_wd (previous_words[8]) + +/* Move the position of the beginning word for matching macros. */ +#define SHIFTHEAD(n) \ + (head_shift += (n)) + +/* Set the position of the beginning word for matching macros. */ +#define SETHEAD(n) \ + (head_shift = (n)) + +/* Return the number of stored words counting head shift */ +#define WORD_COUNT() (previous_words_count - head_shift) + +/* + * Return the true index in previous_words for index from the + * beginning. n is 1-based and the result is 0-based. + */ +#define HEAD_INDEX(n) \ + (previous_words_count - head_shift - (n)) +/* + * remove n words from current shifted position. s and n are 1-based index. + */ +#define COLLAPSE(s, n) \ + do { \ + memmove(previous_words + HEAD_INDEX((s) + (n) - 1), previous_words + HEAD_INDEX((s) - 1), \ + sizeof(char *) * (previous_words_count - HEAD_INDEX((s) - 1))); \ + previous_words_count -= (n); \ + } while(0) + +/* + * Macros for matching the last N words before point, and after head_sift, + * case-insensitively. + */ +#define TailMatches1(p1) \ + (WORD_COUNT() >= 1 && \ + word_matches(p1, prev_wd)) + +#define TailMatches2(p2, p1) \ + (WORD_COUNT() >= 2 && \ + word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd)) + +#define TailMatches3(p3, p2, p1) \ + (WORD_COUNT() >= 3 && \ + word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd)) + +#define TailMatches4(p4, p3, p2, p1) \ + (WORD_COUNT() >= 4 && \ + word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd)) + +#define TailMatches5(p5, p4, p3, p2, p1) \ + (WORD_COUNT() >= 5 && \ + word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd) && \ + word_matches(p5, prev5_wd)) + +#define TailMatches6(p6, p5, p4, p3, p2, p1) \ + (WORD_COUNT() >= 6 && \ + word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd) && \ + word_matches(p5, prev5_wd) && \ + word_matches(p6, prev6_wd)) + +#define TailMatches7(p7, p6, p5, p4, p3, p2, p1) \ + (WORD_COUNT() >= 7 && \ + word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd) && \ + word_matches(p5, prev5_wd) && \ + word_matches(p6, prev6_wd) && \ + word_matches(p7, prev7_wd)) + +#define TailMatches8(p8, p7, p6, p5, p4, p3, p2, p1) \ + (WORD_COUNT() >= 8 && \ + word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd) && \ + word_matches(p5, prev5_wd) && \ + word_matches(p6, prev6_wd) && \ + word_matches(p7, prev7_wd) && \ + word_matches(p8, prev8_wd)) + +#define TailMatches9(p9, p8, p7, p6, p5, p4, p3, p2, p1) \ + (WORD_COUNT() >= 9 && \ + word_matches(p1, prev_wd) && \ + word_matches(p2, prev2_wd) && \ + word_matches(p3, prev3_wd) && \ + word_matches(p4, prev4_wd) && \ + word_matches(p5, prev5_wd) && \ + word_matches(p6, prev6_wd) && \ + word_matches(p7, prev7_wd) && \ + word_matches(p8, prev8_wd) && \ + word_matches(p9, prev9_wd)) + + /* + * Macros for matching the last N words before point, and after + * head_shift, case-sensitively. + */ +#define TailMatchesCS1(p1) \ + (WORD_COUNT() >= 1 && \ + word_matches_cs(p1, prev_wd)) +#define TailMatchesCS2(p2, p1) \ + (WORD_COUNT() >= 2 && \ + word_matches_cs(p1, prev_wd) && \ + word_matches_cs(p2, prev2_wd)) + + /* + * Macros for matching N words exactly to the line, and after head_shift, + * case-insensitively. + */ +#define Matches1(p1) \ + (WORD_COUNT() == 1 && \ + TailMatches1(p1)) +#define Matches2(p1, p2) \ + (WORD_COUNT() == 2 && \ + TailMatches2(p1, p2)) +#define Matches3(p1, p2, p3) \ + (WORD_COUNT() == 3 && \ + TailMatches3(p1, p2, p3)) +#define Matches4(p1, p2, p3, p4) \ + (WORD_COUNT() == 4 && \ + TailMatches4(p1, p2, p3, p4)) +#define Matches5(p1, p2, p3, p4, p5) \ + (WORD_COUNT() == 5 && \ + TailMatches5(p1, p2, p3, p4, p5)) +#define Matches6(p1, p2, p3, p4, p5, p6) \ + (WORD_COUNT() == 6 && \ + TailMatches6(p1, p2, p3, p4, p5, p6)) +#define Matches7(p1, p2, p3, p4, p5, p6, p7) \ + (WORD_COUNT() == 7 && \ + TailMatches7(p1, p2, p3, p4, p5, p6, p7)) +#define Matches8(p1, p2, p3, p4, p5, p6, p7, p8) \ + (WORD_COUNT() == 8 && \ + TailMatches8(p1, p2, p3, p4, p5, p6, p7, p8)) +#define Matches9(p1, p2, p3, p4, p5, p6, p7, p8, p9) \ + (WORD_COUNT() == 9 && \ + TailMatches9(p1, p2, p3, p4, p5, p6, p7, p8, p9)) + +/* + * Macros for matching N words after head_shift + sth in the line, regardless + * of what is after them, case-insensitively. + */ +#define MidMatches1(s, p1) \ + (HEAD_INDEX(s) >=0 && \ + word_matches(p1, previous_words[HEAD_INDEX(s)])) + +#define MidMatches2(s, p1, p2) \ + (HEAD_INDEX((s) + 1) >= 0 && \ + word_matches(p1, previous_words[HEAD_INDEX(s)]) && \ + word_matches(p2, previous_words[HEAD_INDEX((s) + 1)])) + +#define MidMatches3(s, p1, p2, p3) \ + (HEAD_INDEX((s) + 2) >= 0 && \ + word_matches(p1, previous_words[HEAD_INDEX(s)]) && \ + word_matches(p2, previous_words[HEAD_INDEX((s) + 1)]) && \ + word_matches(p3, previous_words[HEAD_INDEX((s) + 2)])) + +#define MidMatches4(s, p1, p2, p3, p4) \ + (HEAD_INDEX((s) + 3) >= 0 && \ + word_matches(p1, previous_words[HEAD_INDEX(s)]) && \ + word_matches(p2, previous_words[HEAD_INDEX((s) + 1)]) && \ + word_matches(p3, previous_words[HEAD_INDEX((s) + 2)]) && \ + word_matches(p4, previous_words[HEAD_INDEX((s) + 3)])) + +#define MidMatches5(s, p1, p2, p3, p4, p5) \ + (HEAD_INDEX((s) + 4) >= 0 && \ + word_matches(p1, previous_words[HEAD_INDEX(s)]) && \ + word_matches(p2, previous_words[HEAD_INDEX((s) + 1)]) && \ + word_matches(p3, previous_words[HEAD_INDEX((s) + 2)]) && \ + word_matches(p4, previous_words[HEAD_INDEX((s) + 3)]) && \ + word_matches(p5, previous_words[HEAD_INDEX((s) + 4)])) + +#define MidMatches6(s,p1, p2, p3, p4, p5, p6) \ + (HEAD_INDEX((s) + 5) >= 0 && \ + word_matches(p1, previous_words[HEAD_INDEX(s)]) && \ + word_matches(p2, previous_words[HEAD_INDEX((s) + 1)]) && \ + word_matches(p3, previous_words[HEAD_INDEX((s) + 2)]) && \ + word_matches(p4, previous_words[HEAD_INDEX((s) + 3)]) && \ + word_matches(p5, previous_words[HEAD_INDEX((s) + 4)]) && \ + word_matches(p6, previous_words[HEAD_INDEX((s) + 5)])) + +#define MidMatches7(s,p1, p2, p3, p4, p5, p6, p7) \ + (HEAD_INDEX((s) + 6) >= 0 && \ + word_matches(p1, previous_words[HEAD_INDEX(s)]) && \ + word_matches(p2, previous_words[HEAD_INDEX((s) + 1)]) && \ + word_matches(p3, previous_words[HEAD_INDEX((s) + 2)]) && \ + word_matches(p4, previous_words[HEAD_INDEX((s) + 3)]) && \ + word_matches(p5, previous_words[HEAD_INDEX((s) + 4)]) && \ + word_matches(p6, previous_words[HEAD_INDEX((s) + 5)]) && \ + word_matches(p7, previous_words[HEAD_INDEX((s) + 6)])) + +#define HeadMatches1(p1) \ + MidMatches1(1, p1) +#define HeadMatches2(p1, p2) \ + MidMatches2(1, p1, p2) +#define HeadMatches3(p1, p2, p3) \ + MidMatches3(1, p1, p2, p3) +#define HeadMatches4(p1, p2, p3, p4) \ + MidMatches4(1, p1, p2, p3, p4) +#define HeadMatches5(p1, p2, p3, p4, p5) \ + MidMatches5(1, p1, p2, p3, p4, p5) +#define HeadMatches6(p1, p2, p3, p4, p5, p6) \ + MidMatches6(1, p1, p2, p3, p4, p5, p6) +#define HeadMatches7(p1, p2, p3, p4, p5, p6, p7) \ + MidMatches7(1, p1, p2, p3, p4, p5, p6, p7) + +/* + * completion_charp is now not a simple string, but a PQExpBuffer. These + * macros are to make the appearance of completion_charp to be simpler. + */ + +/* Append a string to existing completion_charp */ +#define APPEND_COMPLETION_CHARP(charp) \ + appendPQExpBufferStr(completion_charp, charp); + +/* Set a string to completion_charp */ +#define SET_COMPLETION_CHARP(charp) \ + resetPQExpBuffer(completion_charp); \ + APPEND_COMPLETION_CHARP(charp); + +/* Read the completion_charp as a string */ +#define COMPLETION_CHARP (completion_charp->data) + + +/* + * A few macros to ease typing. You can use these to complete the given + * string with + * 1) The results from a query you pass it. (Perhaps one of those below?) + * 2) The results from a schema query you pass it. + * 3) The items from a null-pointer-terminated list (with or without + * case-sensitive comparison; see also COMPLETE_WITH_LISTn, below). + * 4) A string constant. + * 5) The list of attributes of the given table (possibly schema-qualified). + * 6) The list of arguments to the given function (possibly schema-qualified). + */ +#define COMPLETE_WITH_QUERY(query, addon) \ +do { \ + SET_COMPLETION_CHARP(query); \ + APPEND_COMPLETION_CHARP(addon); \ + return completion_matches(text, complete_from_query); \ +} while (0) + +#define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \ +do { \ + completion_squery = &(query); \ + SET_COMPLETION_CHARP(addon); \ + return completion_matches(text, complete_from_schema_query); \ +} while (0) + +#define COMPLETE_WITH_LIST_CS(list) \ +do { \ + completion_charpp = list; \ + completion_case_sensitive = true; \ + return completion_matches(text, complete_from_list); \ +} while (0) + +#define COMPLETE_WITH_LIST(list) \ +do { \ + completion_charpp = list; \ + completion_case_sensitive = false; \ + return completion_matches(text, complete_from_list); \ +} while (0) + +#define COMPLETE_WITH_CONST(string) \ +do { \ + SET_COMPLETION_CHARP(string); \ + completion_case_sensitive = false; \ + return completion_matches(text, complete_from_const); \ +} while (0) + +#define COMPLETE_WITH_ATTR(relation, addon) \ +do { \ + char *_completion_schema; \ + char *_completion_table; \ +\ + _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \ + false, false, pset.encoding); \ + (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \ + false, false, pset.encoding); \ + _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \ + false, false, pset.encoding); \ + if (_completion_table == NULL) \ + { \ + SET_COMPLETION_CHARP(Query_for_list_of_attributes); \ + APPEND_COMPLETION_CHARP(addon); \ + completion_info_charp = relation; \ + } \ + else \ + { \ + SET_COMPLETION_CHARP(Query_for_list_of_attributes_with_schema); \ + APPEND_COMPLETION_CHARP(addon); \ + completion_info_charp = _completion_table; \ + completion_info_charp2 = _completion_schema; \ + } \ + return completion_matches(text, complete_from_query); \ +} while (0) + +#define COMPLETE_WITH_FUNCTION_ARG(function) \ +do { \ + char *_completion_schema; \ + char *_completion_function; \ +\ + _completion_schema = strtokx(function, " \t\n\r", ".", "\"", 0, \ + false, false, pset.encoding); \ + (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \ + false, false, pset.encoding); \ + _completion_function = strtokx(NULL, " \t\n\r", ".", "\"", 0, \ + false, false, pset.encoding); \ + if (_completion_function == NULL) \ + { \ + SET_COMPLETION_CHARP(Query_for_list_of_arguments); \ + completion_info_charp = function; \ + } \ + else \ + { \ + SET_COMPLETION_CHARP(Query_for_list_of_arguments_with_schema); \ + completion_info_charp = _completion_function; \ + completion_info_charp2 = _completion_schema; \ + } \ + return completion_matches(text, complete_from_query); \ +} while (0) + +/* + * These macros simplify use of COMPLETE_WITH_LIST for short, fixed lists. + * There is no COMPLETE_WITH_LIST1; use COMPLETE_WITH_CONST for that case. + */ +#define COMPLETE_WITH_LIST2(s1, s2) \ +do { \ + static const char *const list[] = { s1, s2, NULL }; \ + COMPLETE_WITH_LIST(list); \ +} while (0) + +#define COMPLETE_WITH_LIST3(s1, s2, s3) \ +do { \ + static const char *const list[] = { s1, s2, s3, NULL }; \ + COMPLETE_WITH_LIST(list); \ +} while (0) + +#define COMPLETE_WITH_LIST4(s1, s2, s3, s4) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, NULL }; \ + COMPLETE_WITH_LIST(list); \ +} while (0) + +#define COMPLETE_WITH_LIST5(s1, s2, s3, s4, s5) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, NULL }; \ + COMPLETE_WITH_LIST(list); \ +} while (0) + +#define COMPLETE_WITH_LIST6(s1, s2, s3, s4, s5, s6) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, s6, NULL }; \ + COMPLETE_WITH_LIST(list); \ +} while (0) + +#define COMPLETE_WITH_LIST7(s1, s2, s3, s4, s5, s6, s7) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, NULL }; \ + COMPLETE_WITH_LIST(list); \ +} while (0) + +#define COMPLETE_WITH_LIST8(s1, s2, s3, s4, s5, s6, s7, s8) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, NULL }; \ + COMPLETE_WITH_LIST(list); \ +} while (0) + +#define COMPLETE_WITH_LIST9(s1, s2, s3, s4, s5, s6, s7, s8, s9) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, s9, NULL }; \ + COMPLETE_WITH_LIST(list); \ +} while (0) + +#define COMPLETE_WITH_LIST10(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, NULL }; \ + COMPLETE_WITH_LIST(list); \ +} while (0) + +/* + * Likewise for COMPLETE_WITH_LIST_CS. + */ +#define COMPLETE_WITH_LIST_CS2(s1, s2) \ +do { \ + static const char *const list[] = { s1, s2, NULL }; \ + COMPLETE_WITH_LIST_CS(list); \ +} while (0) + +#define COMPLETE_WITH_LIST_CS3(s1, s2, s3) \ +do { \ + static const char *const list[] = { s1, s2, s3, NULL }; \ + COMPLETE_WITH_LIST_CS(list); \ +} while (0) + +#define COMPLETE_WITH_LIST_CS4(s1, s2, s3, s4) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, NULL }; \ + COMPLETE_WITH_LIST_CS(list); \ +} while (0) + +#define COMPLETE_WITH_LIST_CS5(s1, s2, s3, s4, s5) \ +do { \ + static const char *const list[] = { s1, s2, s3, s4, s5, NULL }; \ + COMPLETE_WITH_LIST_CS(list); \ +} while (0) + +/* + * A macro to comlete "thing" at the pth position before from the current + * word. COMPLETE_THING(-1) completes the thing of the last word in + * previous_words. + */ +#define COMPLETE_THING(p) \ +do { \ + const pgsql_thing_t *ent = find_thing_entry(previous_words[-(p) - 1]); \ + if (ent) \ + { \ + if (ent->query) \ + COMPLETE_WITH_QUERY(ent->query, ""); \ + else if (ent->squery) \ + COMPLETE_WITH_SCHEMA_QUERY(*ent->squery, ""); \ + } \ + return NULL; \ +} while (0) + +/* + * Macros to construct a query to add additional keyword, additional_kw_query + * changes the case of the keywords following an input. + */ +#define ADDLIST1(s1) additional_kw_query(text, 1, s1) +#define ADDLIST2(s1, s2) additional_kw_query(text, 2, s1, s2) +#define ADDLIST3(s1, s2, s3) additional_kw_query(text, 3, s1, s2, s3) +#define ADDLIST4(s1, s2, s3, s4) \ + additional_kw_query(text, 4, s1, s2, s3, s4) +#define ADDLIST13(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13) \ + additional_kw_query(text, 13, s1, s2, s3, s4, s5, s6, s7, \ + s8, s9, s10, s11, s12, s13) +#define ADDLIST15(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15) \ + additional_kw_query(text, 15, s1, s2, s3, s4, s5, s6, s7, \ + s8, s9, s10, s11, s12, s13, s14, s15) + + +#endif /* TAB_COMPLETE_MACROS_H */ diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 832bcd7..d68d886 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -34,6 +34,7 @@ #include "postgres_fe.h" #include "tab-complete.h" +#include "tab-complete-macros.h" #include "input.h" /* If we don't have this, we might as well forget about the whole thing: */ @@ -133,210 +134,6 @@ static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */ static bool completion_case_sensitive; /* completion is case sensitive */ /* - * A few macros to ease typing. You can use these to complete the given - * string with - * 1) The results from a query you pass it. (Perhaps one of those below?) - * 2) The results from a schema query you pass it. - * 3) The items from a null-pointer-terminated list (with or without - * case-sensitive comparison; see also COMPLETE_WITH_LISTn, below). - * 4) A string constant. - * 5) The list of attributes of the given table (possibly schema-qualified). - * 6/ The list of arguments to the given function (possibly schema-qualified). - */ -#define APPEND_COMP_CHARP(charp) \ - appendPQExpBufferStr(completion_charp, charp); - -#define SET_COMP_CHARP(charp) \ - resetPQExpBuffer(completion_charp); \ - APPEND_COMP_CHARP(charp); - -#define COMPLETION_CHARP (completion_charp->data) - -#define COMPLETE_WITH_QUERY(query, addon) \ -do { \ - SET_COMP_CHARP(query); \ - APPEND_COMP_CHARP(addon); \ - matches = completion_matches(text, complete_from_query); \ -} while (0) - -#define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \ -do { \ - completion_squery = &(query); \ - SET_COMP_CHARP(addon); \ - matches = completion_matches(text, complete_from_schema_query); \ -} while (0) - -#define COMPLETE_WITH_LIST_CS(list) \ -do { \ - completion_charpp = list; \ - completion_case_sensitive = true; \ - matches = completion_matches(text, complete_from_list); \ -} while (0) - -#define COMPLETE_WITH_LIST(list) \ -do { \ - completion_charpp = list; \ - completion_case_sensitive = false; \ - matches = completion_matches(text, complete_from_list); \ -} while (0) - -#define COMPLETE_WITH_CONST(string) \ -do { \ - SET_COMP_CHARP(string); \ - completion_case_sensitive = false; \ - matches = completion_matches(text, complete_from_const); \ -} while (0) - -#define COMPLETE_WITH_ATTR(relation, addon) \ -do { \ - char *_completion_schema; \ - char *_completion_table; \ -\ - _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \ - false, false, pset.encoding); \ - (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \ - false, false, pset.encoding); \ - _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \ - false, false, pset.encoding); \ - if (_completion_table == NULL) \ - { \ - SET_COMP_CHARP(Query_for_list_of_attributes); \ - APPEND_COMP_CHARP(addon); \ - completion_info_charp = relation; \ - } \ - else \ - { \ - SET_COMP_CHARP(Query_for_list_of_attributes_with_schema); \ - APPEND_COMP_CHARP(addon); \ - completion_info_charp = _completion_table; \ - completion_info_charp2 = _completion_schema; \ - } \ - matches = completion_matches(text, complete_from_query); \ -} while (0) - -#define COMPLETE_WITH_FUNCTION_ARG(function) \ -do { \ - char *_completion_schema; \ - char *_completion_function; \ -\ - _completion_schema = strtokx(function, " \t\n\r", ".", "\"", 0, \ - false, false, pset.encoding); \ - (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \ - false, false, pset.encoding); \ - _completion_function = strtokx(NULL, " \t\n\r", ".", "\"", 0, \ - false, false, pset.encoding); \ - if (_completion_function == NULL) \ - { \ - SET_COMP_CHARP(Query_for_list_of_arguments); \ - completion_info_charp = function; \ - } \ - else \ - { \ - SET_COMP_CHARP(Query_for_list_of_arguments_with_schema); \ - completion_info_charp = _completion_function; \ - completion_info_charp2 = _completion_schema; \ - } \ - matches = completion_matches(text, complete_from_query); \ -} while (0) - -/* - * These macros simplify use of COMPLETE_WITH_LIST for short, fixed lists. - * There is no COMPLETE_WITH_LIST1; use COMPLETE_WITH_CONST for that case. - */ -#define COMPLETE_WITH_LIST2(s1, s2) \ -do { \ - static const char *const list[] = { s1, s2, NULL }; \ - COMPLETE_WITH_LIST(list); \ -} while (0) - -#define COMPLETE_WITH_LIST3(s1, s2, s3) \ -do { \ - static const char *const list[] = { s1, s2, s3, NULL }; \ - COMPLETE_WITH_LIST(list); \ -} while (0) - -#define COMPLETE_WITH_LIST4(s1, s2, s3, s4) \ -do { \ - static const char *const list[] = { s1, s2, s3, s4, NULL }; \ - COMPLETE_WITH_LIST(list); \ -} while (0) - -#define COMPLETE_WITH_LIST5(s1, s2, s3, s4, s5) \ -do { \ - static const char *const list[] = { s1, s2, s3, s4, s5, NULL }; \ - COMPLETE_WITH_LIST(list); \ -} while (0) - -#define COMPLETE_WITH_LIST6(s1, s2, s3, s4, s5, s6) \ -do { \ - static const char *const list[] = { s1, s2, s3, s4, s5, s6, NULL }; \ - COMPLETE_WITH_LIST(list); \ -} while (0) - -#define COMPLETE_WITH_LIST7(s1, s2, s3, s4, s5, s6, s7) \ -do { \ - static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, NULL }; \ - COMPLETE_WITH_LIST(list); \ -} while (0) - -#define COMPLETE_WITH_LIST8(s1, s2, s3, s4, s5, s6, s7, s8) \ -do { \ - static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, NULL }; \ - COMPLETE_WITH_LIST(list); \ -} while (0) - -#define COMPLETE_WITH_LIST9(s1, s2, s3, s4, s5, s6, s7, s8, s9) \ -do { \ - static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, s9, NULL }; \ - COMPLETE_WITH_LIST(list); \ -} while (0) - -#define COMPLETE_WITH_LIST10(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10) \ -do { \ - static const char *const list[] = { s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, NULL }; \ - COMPLETE_WITH_LIST(list); \ -} while (0) - -/* - * Likewise for COMPLETE_WITH_LIST_CS. - */ -#define COMPLETE_WITH_LIST_CS2(s1, s2) \ -do { \ - static const char *const list[] = { s1, s2, NULL }; \ - COMPLETE_WITH_LIST_CS(list); \ -} while (0) - -#define COMPLETE_WITH_LIST_CS3(s1, s2, s3) \ -do { \ - static const char *const list[] = { s1, s2, s3, NULL }; \ - COMPLETE_WITH_LIST_CS(list); \ -} while (0) - -#define COMPLETE_WITH_LIST_CS4(s1, s2, s3, s4) \ -do { \ - static const char *const list[] = { s1, s2, s3, s4, NULL }; \ - COMPLETE_WITH_LIST_CS(list); \ -} while (0) - -#define COMPLETE_WITH_LIST_CS5(s1, s2, s3, s4, s5) \ -do { \ - static const char *const list[] = { s1, s2, s3, s4, s5, NULL }; \ - COMPLETE_WITH_LIST_CS(list); \ -} while (0) - -#define ADDLIST1(s1) additional_kw_query(text, 1, s1) -#define ADDLIST2(s1, s2) additional_kw_query(text, 2, s1, s2) -#define ADDLIST3(s1, s2, s3) additional_kw_query(text, 3, s1, s2, s3) -#define ADDLIST4(s1, s2, s3, s4) \ - additional_kw_query(text, 4, s1, s2, s3, s4) -#define ADDLIST13(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13) \ - additional_kw_query(text, 12, s1, s2, s3, s4, s5, s6, s7, \ - s8, s9, s10, s11, s12, s13) -#define ADDLIST15(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15) \ - additional_kw_query(text, 12, s1, s2, s3, s4, s5, s6, s7, \ - s8, s9, s10, s11, s12, s13, s14, s15) - -/* * Assembly instructions for schema queries */ @@ -993,9 +790,11 @@ static PGresult *exec_query(const char *query); static char **get_previous_words(int point, char **buffer, int *nwords); -static char *get_guctype(const char *varname); +static bool get_guctype(char *buf, size_t len, const char *varname); static const pgsql_thing_t *find_thing_entry(char *word); +static char **psql_completion_internal(const char *text, char **previous_words, + int previous_words_count); #ifdef NOT_USED static char *quote_file_name(char *text, int match_type, char *quote_pointer); static char *dequote_file_name(char *text, char quote_char); @@ -1151,235 +950,60 @@ psql_completion(const char *text, int start, int end) /* The number of words found on the input line. */ int previous_words_count; - /* The number of prefixing words to be ignored */ - int head_shift = 0; + (void) end; /* "end" is not used */ - /* - * For compactness, we use these macros to reference previous_words[]. - * Caution: do not access a previous_words[] entry without having checked - * previous_words_count to be sure it's valid. In most cases below, that - * check is implicit in a TailMatches() or similar macro, but in some - * places we have to check it explicitly. - */ -#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]) -#define prev7_wd (previous_words[6]) -#define prev8_wd (previous_words[7]) -#define prev9_wd (previous_words[8]) - - /* Move the position of the beginning word for matching macros. */ -#define HEADSHIFT(n) \ - ((head_shift += n) || true) - - /* Return the number of stored words counting head shift */ -#define WORD_COUNT() (previous_words_count - head_shift) - - /* Return the true index in previous_words for index from the beginning */ -#define HEAD_INDEX(n) \ - (previous_words_count - head_shift - (n)) +#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER + rl_completion_append_character = ' '; +#endif - /* - * remove n words from current shifted position, see MidMatchAndRevmove2 - * for the reason for the return value - */ -#define COLLAPSE(n) \ - ((memmove(previous_words + HEAD_INDEX(n), previous_words + HEAD_INDEX(0), \ - sizeof(char *) * head_shift), \ - previous_words_count -= (n)) && false) + /* Clear a few things. */ + if (completion_charp == NULL) + completion_charp = createPQExpBuffer(); + completion_charpp = NULL; + completion_info_charp = NULL; + completion_info_charp2 = NULL; /* - * Find the position the specified word occurs last and shift to there. - * This is used to ignore the words before there. + * Scan the input line to extract the words before our current position. + * According to those we'll make some smart decisions on what the user is + * probably intending to type. */ -#define SHIFT_TO_LAST1(p1) \ - (HEADSHIFT(find_last_index_of(p1, previous_words, previous_words_count))|| \ - true) + previous_words = get_previous_words(start, + &words_buffer, + &previous_words_count); - /* - * Remove the specified words if they match from the sth word in - * previous_words. This is a bit tricky, COLLAPSE is skipped when - * HeadMatches failed but the last HEADSHIFT anyway should be done. - */ -#define MidMatchAndRemove1(s, p1) \ - ((HEADSHIFT(s) && HeadMatches1(p1) && COLLAPSE(1)) || HEADSHIFT(-s)) - -#define MidMatchAndRemove2(s, p1, p2) \ - ((HEADSHIFT(s) && HeadMatches2(p1, p2) && COLLAPSE(2)) || HEADSHIFT(-s)) - -#define MidMatchAndRemove3(s, p1, p2, p3) \ - ((HEADSHIFT(s) && HeadMatches3(p1, p2, p3) && COLLAPSE(3)) || HEADSHIFT(-s)) - - /* Macros for matching the last N words before point, case-insensitively. */ -#define TailMatches1(p1) \ - (WORD_COUNT() >= 1 && \ - word_matches(p1, prev_wd)) - -#define TailMatches2(p2, p1) \ - (WORD_COUNT() >= 2 && \ - word_matches(p1, prev_wd) && \ - word_matches(p2, prev2_wd)) - -#define TailMatches3(p3, p2, p1) \ - (WORD_COUNT() >= 3 && \ - word_matches(p1, prev_wd) && \ - word_matches(p2, prev2_wd) && \ - word_matches(p3, prev3_wd)) - -#define TailMatches4(p4, p3, p2, p1) \ - (WORD_COUNT() >= 4 && \ - word_matches(p1, prev_wd) && \ - word_matches(p2, prev2_wd) && \ - word_matches(p3, prev3_wd) && \ - word_matches(p4, prev4_wd)) - -#define TailMatches5(p5, p4, p3, p2, p1) \ - (WORD_COUNT() >= 5 && \ - word_matches(p1, prev_wd) && \ - word_matches(p2, prev2_wd) && \ - word_matches(p3, prev3_wd) && \ - word_matches(p4, prev4_wd) && \ - word_matches(p5, prev5_wd)) - -#define TailMatches6(p6, p5, p4, p3, p2, p1) \ - (WORD_COUNT() >= 6 && \ - word_matches(p1, prev_wd) && \ - word_matches(p2, prev2_wd) && \ - word_matches(p3, prev3_wd) && \ - word_matches(p4, prev4_wd) && \ - word_matches(p5, prev5_wd) && \ - word_matches(p6, prev6_wd)) - -#define TailMatches7(p7, p6, p5, p4, p3, p2, p1) \ - (WORD_COUNT() >= 7 && \ - word_matches(p1, prev_wd) && \ - word_matches(p2, prev2_wd) && \ - word_matches(p3, prev3_wd) && \ - word_matches(p4, prev4_wd) && \ - word_matches(p5, prev5_wd) && \ - word_matches(p6, prev6_wd) && \ - word_matches(p7, prev7_wd)) - -#define TailMatches8(p8, p7, p6, p5, p4, p3, p2, p1) \ - (WORD_COUNT() >= 8 && \ - word_matches(p1, prev_wd) && \ - word_matches(p2, prev2_wd) && \ - word_matches(p3, prev3_wd) && \ - word_matches(p4, prev4_wd) && \ - word_matches(p5, prev5_wd) && \ - word_matches(p6, prev6_wd) && \ - word_matches(p7, prev7_wd) && \ - word_matches(p8, prev8_wd)) - -#define TailMatches9(p9, p8, p7, p6, p5, p4, p3, p2, p1) \ - (WORD_COUNT() >= 9 && \ - word_matches(p1, prev_wd) && \ - word_matches(p2, prev2_wd) && \ - word_matches(p3, prev3_wd) && \ - word_matches(p4, prev4_wd) && \ - word_matches(p5, prev5_wd) && \ - word_matches(p6, prev6_wd) && \ - word_matches(p7, prev7_wd) && \ - word_matches(p8, prev8_wd) && \ - word_matches(p9, prev9_wd)) - - /* Macros for matching the last N words before point, case-sensitively. */ -#define TailMatchesCS1(p1) \ - (WORD_COUNT() >= 1 && \ - word_matches_cs(p1, prev_wd)) -#define TailMatchesCS2(p2, p1) \ - (WORD_COUNT() >= 2 && \ - word_matches_cs(p1, prev_wd) && \ - word_matches_cs(p2, prev2_wd)) + matches = psql_completion_internal(text, previous_words, + previous_words_count); - /* - * Macros for matching N words exactly to the line, - * case-insensitively. - */ -#define Matches1(p1) \ - (WORD_COUNT() == 1 && \ - TailMatches1(p1)) -#define Matches2(p1, p2) \ - (WORD_COUNT() == 2 && \ - TailMatches2(p1, p2)) -#define Matches3(p1, p2, p3) \ - (WORD_COUNT() == 3 && \ - TailMatches3(p1, p2, p3)) -#define Matches4(p1, p2, p3, p4) \ - (WORD_COUNT() == 4 && \ - TailMatches4(p1, p2, p3, p4)) -#define Matches5(p1, p2, p3, p4, p5) \ - (WORD_COUNT() == 5 && \ - TailMatches5(p1, p2, p3, p4, p5)) -#define Matches6(p1, p2, p3, p4, p5, p6) \ - (WORD_COUNT() == 6 && \ - TailMatches6(p1, p2, p3, p4, p5, p6)) -#define Matches7(p1, p2, p3, p4, p5, p6, p7) \ - (WORD_COUNT() == 7 && \ - TailMatches7(p1, p2, p3, p4, p5, p6, p7)) -#define Matches8(p1, p2, p3, p4, p5, p6, p7, p8) \ - (WORD_COUNT() == 8 && \ - TailMatches8(p1, p2, p3, p4, p5, p6, p7, p8)) -#define Matches9(p1, p2, p3, p4, p5, p6, p7, p8, p9) \ - (WORD_COUNT() == 9 && \ - TailMatches9(p1, p2, p3, p4, p5, p6, p7, p8, p9)) + /* free storage */ + free(previous_words); + free(words_buffer); + + if (matches != NULL) + return matches; /* - * Macros for matching N words at the start of the line, regardless of - * what is after them, case-insensitively. + * If we still don't have anything to match we have to fabricate some sort + * of default list. If we were to just return NULL, readline automatically + * attempts filename completion, and that's usually no good. */ -#define HeadMatches1(p1) \ - (HEAD_INDEX(1) >=0 && \ - word_matches(p1, previous_words[HEAD_INDEX(1)])) - -#define HeadMatches2(p1, p2) \ - (HEAD_INDEX(2) >= 0 && \ - word_matches(p1, previous_words[HEAD_INDEX(1)]) && \ - word_matches(p2, previous_words[HEAD_INDEX(2)])) - -#define HeadMatches3(p1, p2, p3) \ - (HEAD_INDEX(3) >= 0 && \ - word_matches(p1, previous_words[HEAD_INDEX(1)]) && \ - word_matches(p2, previous_words[HEAD_INDEX(2)]) && \ - word_matches(p3, previous_words[HEAD_INDEX(3)])) - -#define HeadMatches4(p1, p2, p3, p4) \ - (HEAD_INDEX(4) >= 0 && \ - word_matches(p1, previous_words[HEAD_INDEX(1)]) && \ - word_matches(p2, previous_words[HEAD_INDEX(2)]) && \ - word_matches(p3, previous_words[HEAD_INDEX(3)]) && \ - word_matches(p4, previous_words[HEAD_INDEX(4)])) - -#define HeadMatches5(p1, p2, p3, p4, p5) \ - (HEAD_INDEX(5) >= 0 && \ - word_matches(p1, previous_words[HEAD_INDEX(1)]) && \ - word_matches(p2, previous_words[HEAD_INDEX(2)]) && \ - word_matches(p3, previous_words[HEAD_INDEX(3)]) && \ - word_matches(p4, previous_words[HEAD_INDEX(4)]) && \ - word_matches(p5, previous_words[HEAD_INDEX(5)])) - -#define HeadMatches6(p1, p2, p3, p4, p5, p6) \ - (HEAD_INDEX(6) >= 0 && \ - word_matches(p1, previous_words[HEAD_INDEX(1)]) && \ - word_matches(p2, previous_words[HEAD_INDEX(2)]) && \ - word_matches(p3, previous_words[HEAD_INDEX(3)]) && \ - word_matches(p4, previous_words[HEAD_INDEX(4)]) && \ - word_matches(p5, previous_words[HEAD_INDEX(5)]) && \ - word_matches(p6, previous_words[HEAD_INDEX(6)])) - -#define HeadMatches7(p1, p2, p3, p4, p5, p6, p7) \ - (HEAD_INDEX(7) >= 0 && \ - word_matches(p1, previous_words[HEAD_INDEX(1)]) && \ - word_matches(p2, previous_words[HEAD_INDEX(2)]) && \ - word_matches(p3, previous_words[HEAD_INDEX(3)]) && \ - word_matches(p4, previous_words[HEAD_INDEX(4)]) && \ - word_matches(p5, previous_words[HEAD_INDEX(5)]) && \ - word_matches(p6, previous_words[HEAD_INDEX(6)]) && \ - word_matches(p7, previous_words[HEAD_INDEX(7)])) +#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER + rl_completion_append_character = '\0'; +#endif + COMPLETE_WITH_CONST(""); /* This returns matches */ +} +/* + * The completion function. + * + * Makes completion list. previous_words may be modified on the way of making + * the returning list. Note that COMPLETE_WITH_* macros immediately return to + * the caller of this function. + */ +static char ** +psql_completion_internal(const char *text, char **previous_words, + int previous_words_count) +{ /* Known command-starting keywords. */ static const char *const sql_commands[] = { "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", @@ -1411,104 +1035,122 @@ psql_completion(const char *text, int start, int end) "\\timing", "\\unset", "\\x", "\\w", "\\watch", "\\z", "\\!", NULL }; - (void) end; /* "end" is not used */ - -#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER - rl_completion_append_character = ' '; -#endif - - /* Clear a few things. */ - if (completion_charp == NULL) - completion_charp = createPQExpBuffer(); - completion_charpp = NULL; - completion_info_charp = NULL; - completion_info_charp2 = NULL; - - /* - * Scan the input line to extract the words before our current position. - * According to those we'll make some smart decisions on what the user is - * probably intending to type. - */ - previous_words = get_previous_words(start, - &words_buffer, - &previous_words_count); + /* The number of prefixing words to be ignored */ + int head_shift = 0; /* If current word is a backslash command, offer completions for that */ if (text[0] == '\\') COMPLETE_WITH_LIST_CS(backslash_commands); /* If current word is a variable interpolation, handle that case */ - else if (text[0] == ':' && text[1] != ':') + if (text[0] == ':' && text[1] != ':') { + char **matches = NULL; + if (text[1] == '\'') matches = complete_from_variables(text, ":'", "'", true); else if (text[1] == '"') matches = complete_from_variables(text, ":\"", "\"", true); else matches = complete_from_variables(text, ":", "", true); + + return matches; } /* If no previous word, suggest one of the basic sql commands */ - else if (previous_words_count == 0) + if (previous_words_count == 0) COMPLETE_WITH_LIST(sql_commands); /* * If this is in CREATE SCHEMA, seek to the last CREATE and regard it as * current command to complete. */ - else if (HeadMatches2("CREATE", "SCHEMA") && - SHIFT_TO_LAST1("CREATE") && - false) {} /* FALL THROUGH */ + if (HeadMatches2("CREATE", "SCHEMA")) + { + int n; + + /* CREATE SCHEMA */ + if (Matches2("CREATE", "SCHEMA")) + COMPLETE_WITH_QUERY(Query_for_list_of_schemas, + ADDLIST1("IF NOT EXISTS")); + /* Remove optional words IF NOT EXISTS */ + if (HeadMatches2("CREATE", "SCHEMA") && + MidMatches3(3, "IF", "NOT", "EXISTS")) + COLLAPSE(3, 3); + + if (Matches2("CREATE", "SCHEMA")) + COMPLETE_THING(-1); + + /* Else, move head match point past CREATE SCHEMA and go through */ + if ((n = find_last_index_of("CREATE", + previous_words, previous_words_count)) > 0) + SHIFTHEAD(n); + } + /* CREATE */ /* complete with something you can create */ - else if (Matches1("CREATE")) - matches = completion_matches(text, create_command_generator); + if (Matches1("CREATE")) + return completion_matches(text, create_command_generator); /* DROP, but not DROP embedded in other commands */ /* complete with something you can drop */ - else if (Matches1("DROP")) - matches = completion_matches(text, drop_command_generator); + if (Matches1("DROP")) + return completion_matches(text, drop_command_generator); /* ALTER */ - /* ALTER TABLE */ - else if (Matches2("ALTER", "TABLE")) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, - ADDLIST2("IF EXISTS", "ALL IN TABLESPACE")); - - /* ALTER TABLE after removing optional words IF EXISTS*/ - else if (HeadMatches2("ALTER", "TABLE") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches2("ALTER", "TABLE")) - COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); - /* ALTER something */ - else if (Matches1("ALTER")) + if (Matches1("ALTER")) { static const char *const list_ALTER[] = - {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", - "EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION", - "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR", - "POLICY", "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", "SYSTEM", "TABLE", - "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", - "USER", "USER MAPPING FOR", "VIEW", NULL}; + {"AGGREGATE", + "COLLATION", "CONVERSION", + "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN", + "EVENT TRIGGER", "EXTENSION", + "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION", + "GROUP", + "INDEX", + "LANGUAGE", "LARGE OBJECT", + "MATERIALIZED VIEW", + "OPERATOR", + "POLICY", + "ROLE", "RULE", + "SCHEMA", "SERVER", "SEQUENCE", "SYSTEM", + "TABLE", "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", + "USER", "USER MAPPING FOR", + "VIEW", + NULL}; COMPLETE_WITH_LIST(list_ALTER); } + /* ALTER TABLE */ + if (Matches2("ALTER", "TABLE")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, + ADDLIST2("IF EXISTS", "ALL IN TABLESPACE")); + + /* Remove optional words IF EXISTS just after ALTER TABLE */ + if (HeadMatches2("ALTER", "TABLE") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + /* ALTER TABLE */ + if (Matches2("ALTER", "TABLE")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); + /* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx */ - else if (TailMatches4("ALL", "IN", "TABLESPACE", MatchAny)) + if (TailMatches4("ALL", "IN", "TABLESPACE", MatchAny)) COMPLETE_WITH_LIST2("SET TABLESPACE", "OWNED BY"); /* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx OWNED BY */ - else if (TailMatches6("ALL", "IN", "TABLESPACE", MatchAny, "OWNED", "BY")) + if (TailMatches6("ALL", "IN", "TABLESPACE", MatchAny, "OWNED", "BY")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); /* ALTER TABLE,INDEX,MATERIALIZED VIEW ALL IN TABLESPACE xxx OWNED BY xxx */ - else if (TailMatches7("ALL", "IN", "TABLESPACE", MatchAny, "OWNED", "BY", MatchAny)) + if (TailMatches7("ALL", "IN", "TABLESPACE", MatchAny, "OWNED", "BY", MatchAny)) COMPLETE_WITH_CONST("SET TABLESPACE"); /* ALTER AGGREGATE,FUNCTION */ - else if (Matches3("ALTER", "AGGREGATE|FUNCTION", MatchAny)) + if (Matches3("ALTER", "AGGREGATE|FUNCTION", MatchAny)) COMPLETE_WITH_CONST("("); /* ALTER AGGREGATE,FUNCTION (...) */ - else if (Matches4("ALTER", "AGGREGATE|FUNCTION", MatchAny, MatchAny)) + if (Matches4("ALTER", "AGGREGATE|FUNCTION", MatchAny, MatchAny)) { if (ends_with(prev_wd, ')')) COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA"); @@ -1517,74 +1159,76 @@ psql_completion(const char *text, int start, int end) } /* ALTER SCHEMA */ - else if (Matches3("ALTER", "SCHEMA", MatchAny)) + if (Matches3("ALTER", "SCHEMA", MatchAny)) COMPLETE_WITH_LIST2("OWNER TO", "RENAME TO"); /* ALTER COLLATION */ - else if (Matches3("ALTER", "COLLATION", MatchAny)) + if (Matches3("ALTER", "COLLATION", MatchAny)) COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA"); /* ALTER CONVERSION */ - else if (Matches3("ALTER", "CONVERSION", MatchAny)) + if (Matches3("ALTER", "CONVERSION", MatchAny)) COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA"); /* ALTER DATABASE */ - else if (Matches3("ALTER", "DATABASE", MatchAny)) + if (Matches3("ALTER", "DATABASE", MatchAny)) COMPLETE_WITH_LIST7("RESET", "SET", "OWNER TO", "RENAME TO", "IS_TEMPLATE", "ALLOW_CONNECTIONS", "CONNECTION LIMIT"); /* ALTER EVENT TRIGGER */ - else if (Matches3("ALTER", "EVENT", "TRIGGER")) + if (Matches3("ALTER", "EVENT", "TRIGGER")) COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers, ""); /* ALTER EVENT TRIGGER */ - else if (Matches4("ALTER", "EVENT", "TRIGGER", MatchAny)) + if (Matches4("ALTER", "EVENT", "TRIGGER", MatchAny)) COMPLETE_WITH_LIST4("DISABLE", "ENABLE", "OWNER TO", "RENAME TO"); /* ALTER EVENT TRIGGER ENABLE */ - else if (Matches5("ALTER", "EVENT", "TRIGGER", MatchAny, "ENABLE")) + if (Matches5("ALTER", "EVENT", "TRIGGER", MatchAny, "ENABLE")) COMPLETE_WITH_LIST2("REPLICA", "ALWAYS"); /* ALTER EXTENSION */ - else if (Matches3("ALTER", "EXTENSION", MatchAny)) + if (Matches3("ALTER", "EXTENSION", MatchAny)) COMPLETE_WITH_LIST4("ADD", "DROP", "UPDATE", "SET SCHEMA"); /* ALTER EXTENSION UPDATE */ - else if (Matches4("ALTER", "EXTENSION", MatchAny, "UPDATE")) + if (Matches4("ALTER", "EXTENSION", MatchAny, "UPDATE")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions_with_TO,""); } /* ALTER EXTENSION UPDATE TO */ - else if (Matches5("ALTER", "EXTENSION", MatchAny, "UPDATE", "TO")) + if (Matches5("ALTER", "EXTENSION", MatchAny, "UPDATE", "TO")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions, ""); } /* ALTER FOREIGN */ - else if (Matches2("ALTER", "FOREIGN")) + if (Matches2("ALTER", "FOREIGN")) COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); /* ALTER FOREIGN DATA WRAPPER */ - else if (Matches5("ALTER", "FOREIGN", "DATA", "WRAPPER", MatchAny)) + if (Matches5("ALTER", "FOREIGN", "DATA", "WRAPPER", MatchAny)) COMPLETE_WITH_LIST5("HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", "RENAME TO"); /* ALTER FOREIGN TABLE */ - else if (Matches3("ALTER|DROP", "FOREIGN", "TABLE")) + if (Matches3("ALTER|DROP", "FOREIGN", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, ADDLIST1("IF EXISTS")); /* ALTER|DROP FOREIGN TABLE after removing optinal words IF EXISTS */ - else if (HeadMatches3("ALTER|DROP", "FOREIGN", "TABLE") && - MidMatchAndRemove2(3, "IF", "EXISTS") && - Matches3("ALTER|DROP", "FOREIGN", "TABLE")) + if (HeadMatches3("ALTER|DROP", "FOREIGN", "TABLE") && + MidMatches2(4, "IF", "EXISTS")) + COLLAPSE(4, 2); + + if (Matches3("ALTER|DROP", "FOREIGN", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, ""); /* ALTER FOREIGN TABLE */ - else if (Matches4("ALTER", "FOREIGN", "TABLE", MatchAny)) + if (Matches4("ALTER", "FOREIGN", "TABLE", MatchAny)) { static const char *const list_ALTER_FOREIGN_TABLE[] = {"ADD", "ALTER", "DISABLE TRIGGER", "DROP", "ENABLE", "INHERIT", @@ -1595,58 +1239,62 @@ psql_completion(const char *text, int start, int end) } /* ALTER FOREIGN TABLE xxx RENAME */ - else if (Matches5("ALTER", "FOREIGN", "TABLE", MatchAny, "RENAME")) + if (Matches5("ALTER", "FOREIGN", "TABLE", MatchAny, "RENAME")) COMPLETE_WITH_ATTR(prev2_wd, ADDLIST2("COLUMN", "TO")); /* ALTER INDEX */ - else if (Matches2("ALTER", "INDEX")) + if (Matches2("ALTER", "INDEX")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, ADDLIST2("IF EXISTS", "ALL IN TABLESPACE")); /* ALTER INDEX after removing optional words IF EXISTS */ - else if (HeadMatches2("ALTER", "INDEX") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches2("ALTER", "INDEX")) + if (HeadMatches2("ALTER", "INDEX") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches2("ALTER", "INDEX")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, ""); /* ALTER INDEX */ - else if (Matches3("ALTER", "INDEX", MatchAny)) + if (Matches3("ALTER", "INDEX", MatchAny)) COMPLETE_WITH_LIST4("OWNER TO", "RENAME TO", "SET", "RESET"); /* ALTER INDEX SET */ - else if (Matches4("ALTER", "INDEX", MatchAny, "SET")) + if (Matches4("ALTER", "INDEX", MatchAny, "SET")) COMPLETE_WITH_LIST2("(", "TABLESPACE"); /* ALTER INDEX RESET */ - else if (Matches4("ALTER", "INDEX", MatchAny, "RESET")) + if (Matches4("ALTER", "INDEX", MatchAny, "RESET")) COMPLETE_WITH_CONST("("); /* ALTER INDEX SET|RESET ( */ - else if (Matches5("ALTER", "INDEX", MatchAny, "RESET", "(")) + if (Matches5("ALTER", "INDEX", MatchAny, "RESET", "(")) COMPLETE_WITH_LIST3("fillfactor", "fastupdate", "gin_pending_list_limit"); - else if (Matches5("ALTER", "INDEX", MatchAny, "SET", "(")) + if (Matches5("ALTER", "INDEX", MatchAny, "SET", "(")) COMPLETE_WITH_LIST3("fillfactor =", "fastupdate =", "gin_pending_list_limit ="); /* ALTER LANGUAGE */ - else if (Matches3("ALTER", "LANGUAGE", MatchAny)) + if (Matches3("ALTER", "LANGUAGE", MatchAny)) COMPLETE_WITH_LIST2("OWNER_TO", "RENAME TO"); /* ALTER LARGE OBJECT */ - else if (Matches4("ALTER", "LARGE", "OBJECT", MatchAny)) + if (Matches4("ALTER", "LARGE", "OBJECT", MatchAny)) COMPLETE_WITH_CONST("OWNER TO"); /* ALTER MATERIALIZED VIEW */ - else if (Matches3("ALTER", "MATERIALIZED", "VIEW")) + if (Matches3("ALTER", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ADDLIST2("IF EXISTS", "ALL IN TABLESPACE")); /* ALTER MATERIALIZED VIEW with name after removing optional words */ - else if (HeadMatches3("ALTER", "MATERIALIZED", "VIEW") && - MidMatchAndRemove2(3, "IF", "EXISTS") && - Matches3("ALTER", "MATERIALIZED", "VIEW")) + if (HeadMatches3("ALTER", "MATERIALIZED", "VIEW") && + MidMatches2(4, "IF", "EXISTS")) + COLLAPSE(4, 2); + + if (Matches3("ALTER", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ""); /* ALTER USER,ROLE */ - else if (Matches3("ALTER", "USER|ROLE", MatchAny) && - !TailMatches2("USER", "MAPPING")) + if (Matches3("ALTER", "USER|ROLE", MatchAny) && + !TailMatches2("USER", "MAPPING")) { static const char *const list_ALTERUSER[] = {"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE", @@ -1660,7 +1308,7 @@ psql_completion(const char *text, int start, int end) } /* ALTER USER,ROLE WITH */ - else if (Matches4("ALTER", "USER|ROLE", MatchAny, "WITH")) + if (Matches4("ALTER", "USER|ROLE", MatchAny, "WITH")) { /* Similar to the above, but don't complete "WITH" again. */ static const char *const list_ALTERUSER_WITH[] = @@ -1675,63 +1323,67 @@ psql_completion(const char *text, int start, int end) } /* complete ALTER USER,ROLE ENCRYPTED,UNENCRYPTED with PASSWORD */ - else if (Matches4("ALTER", "USER|ROLE", MatchAny, "ENCRYPTED|UNENCRYPTED")) + if (Matches4("ALTER", "USER|ROLE", MatchAny, "ENCRYPTED|UNENCRYPTED")) COMPLETE_WITH_CONST("PASSWORD"); /* ALTER DEFAULT PRIVILEGES */ - else if (Matches3("ALTER", "DEFAULT", "PRIVILEGES")) + if (Matches3("ALTER", "DEFAULT", "PRIVILEGES")) COMPLETE_WITH_LIST3("FOR ROLE", "FOR USER", "IN SCHEMA"); /* ALTER DEFAULT PRIVILEGES FOR */ - else if (Matches4("ALTER", "DEFAULT", "PRIVILEGES", "FOR")) + if (Matches4("ALTER", "DEFAULT", "PRIVILEGES", "FOR")) COMPLETE_WITH_LIST2("ROLE", "USER"); /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */ - else if (Matches6("ALTER", "DEFAULT", "PRIVILEGES", "FOR", "ROLE|USER", MatchAny) || + if (Matches6("ALTER", "DEFAULT", "PRIVILEGES", "FOR", "ROLE|USER", MatchAny) || Matches6("ALTER", "DEFAULT", "PRIVILEGES", "IN", "SCHEMA", MatchAny)) COMPLETE_WITH_LIST2("GRANT", "REVOKE"); /* ALTER DOMAIN */ - else if (Matches3("ALTER", "DOMAIN", MatchAny)) + if (Matches3("ALTER", "DOMAIN", MatchAny)) COMPLETE_WITH_LIST6("ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT"); /* ALTER DOMAIN DROP */ - else if (Matches4("ALTER", "DOMAIN", MatchAny, "DROP")) + if (Matches4("ALTER", "DOMAIN", MatchAny, "DROP")) COMPLETE_WITH_LIST3("CONSTRAINT", "DEFAULT", "NOT NULL"); /* ALTER DOMAIN RENAME|VALIDATE CONSTRAINT */ - else if (Matches5("ALTER", "DOMAIN", MatchAny, "RENAME|VALIDATE", "CONSTRAINT")) + if (Matches5("ALTER", "DOMAIN", MatchAny, "RENAME|VALIDATE", "CONSTRAINT")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_constraint_of_type, ""); } /* ALTER DOMAIN DROP CONSTRAINT */ - else if (Matches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT")) + if (Matches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_constraint_of_type, ADDLIST1("IF EXISTS")); } /* Try the same match after removing optional words IF EXISTS */ - else if (HeadMatches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT") && - MidMatchAndRemove2(5, "IF", "EXISTS") && - Matches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT")) + if (HeadMatches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT") && + MidMatches2(6, "IF", "EXISTS")) + COLLAPSE(6, 2); + + if (Matches5("ALTER", "DOMAIN", MatchAny, "DROP", "CONSTRAINT")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_constraint_of_type, ""); } /* ALTER DOMAIN RENAME */ - else if (Matches4("ALTER", "DOMAIN", MatchAny, "RENAME")) + if (Matches4("ALTER", "DOMAIN", MatchAny, "RENAME")) COMPLETE_WITH_LIST2("CONSTRAINT", "TO"); /* ALTER DOMAIN RENAME CONSTRAINT */ - else if (Matches6("ALTER", "DOMAIN", MatchAny, "RENAME", "CONSTRAINT", MatchAny)) + if (Matches6("ALTER", "DOMAIN", MatchAny, "RENAME", "CONSTRAINT", MatchAny)) COMPLETE_WITH_CONST("TO"); /* ALTER DOMAIN SET */ - else if (Matches4("ALTER", "DOMAIN", MatchAny, "SET")) + if (Matches4("ALTER", "DOMAIN", MatchAny, "SET")) COMPLETE_WITH_LIST3("DEFAULT", "NOT NULL", "SCHEMA"); - else if (Matches2("ALTER", "SEQUENCE")) + if (Matches2("ALTER", "SEQUENCE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, ADDLIST1("IF EXISTS")); /* ALTER SEQUENCE with name after removing optional words IF EXISTS */ - else if (HeadMatches2("ALTER", "SEQUENCE") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches3("ALTER", "SEQUENCE", MatchAny)) + if (HeadMatches2("ALTER", "SEQUENCE") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches3("ALTER", "SEQUENCE", MatchAny)) { static const char *const list_ALTERSEQUENCE[] = {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE", @@ -1740,83 +1392,87 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTERSEQUENCE); } /* ALTER SEQUENCE NO */ - else if (Matches4("ALTER", "SEQUENCE", MatchAny, "NO")) + if (Matches4("ALTER", "SEQUENCE", MatchAny, "NO")) COMPLETE_WITH_LIST3("MINVALUE", "MAXVALUE", "CYCLE"); /* ALTER SERVER */ - else if (Matches3("ALTER", "SERVER", MatchAny)) + if (Matches3("ALTER", "SERVER", MatchAny)) COMPLETE_WITH_LIST4("VERSION", "OPTIONS", "OWNER TO", "RENAME TO"); /* ALTER SERVER VERSION */ - else if (Matches5("ALTER", "SERVER", MatchAny, "VERSION", MatchAny)) + if (Matches5("ALTER", "SERVER", MatchAny, "VERSION", MatchAny)) COMPLETE_WITH_CONST("OPTIONS"); /* ALTER SYSTEM SET, RESET, RESET ALL */ - else if (Matches2("ALTER", "SYSTEM")) + if (Matches2("ALTER", "SYSTEM")) COMPLETE_WITH_LIST2("SET", "RESET"); /* ALTER SYSTEM SET|RESET */ - else if (Matches3("ALTER", "SYSTEM", "SET|RESET")) + if (Matches3("ALTER", "SYSTEM", "SET|RESET")) COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars, ""); /* ALTER VIEW */ - else if (Matches2("ALTER", "VIEW")) + if (Matches2("ALTER", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, ADDLIST1("IF EXISTS")); /* ALTER VIEW with subcommands after removing optional worlds */ - else if (HeadMatches2("ALTER", "VIEW") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches3("ALTER", "VIEW", MatchAny)) + if (HeadMatches2("ALTER", "VIEW") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches3("ALTER", "VIEW", MatchAny)) COMPLETE_WITH_LIST4("ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA"); /* ALTER MATERIALIZED VIEW */ - else if (Matches4("ALTER", "MATERIALIZED", "VIEW", MatchAny)) + if (Matches4("ALTER", "MATERIALIZED", "VIEW", MatchAny)) COMPLETE_WITH_LIST4("ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA"); /* ALTER POLICY */ - else if (Matches2("ALTER", "POLICY")) + if (Matches2("ALTER", "POLICY")) COMPLETE_WITH_QUERY(Query_for_list_of_policies, ADDLIST1("IF EXISTS")); /* ALTER POLICY with ON after removing optional words IF EXISTS */ - else if (HeadMatches2("ALTER", "POLICY") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches3("ALTER", "POLICY", MatchAny)) + if (HeadMatches2("ALTER", "POLICY") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches3("ALTER", "POLICY", MatchAny)) COMPLETE_WITH_CONST("ON"); /* ALTER POLICY ON */ - else if (Matches4("ALTER", "POLICY", MatchAny, "ON")) + if (Matches4("ALTER", "POLICY", MatchAny, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy, ""); } /* ALTER POLICY ON
- show options */ - else if (Matches5("ALTER", "POLICY", MatchAny, "ON", MatchAny)) + if (Matches5("ALTER", "POLICY", MatchAny, "ON", MatchAny)) COMPLETE_WITH_LIST4("RENAME TO", "TO", "USING (", "WITH CHECK ("); /* ALTER POLICY ON
TO */ - else if (Matches6("ALTER", "POLICY", MatchAny, "ON", MatchAny, "TO")) + if (Matches6("ALTER", "POLICY", MatchAny, "ON", MatchAny, "TO")) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles, ""); /* ALTER POLICY ON
USING ( */ - else if (Matches6("ALTER", "POLICY", MatchAny, "ON", MatchAny, "USING")) + if (Matches6("ALTER", "POLICY", MatchAny, "ON", MatchAny, "USING")) COMPLETE_WITH_CONST("("); /* ALTER POLICY ON
WITH CHECK ( */ - else if (Matches7("ALTER", "POLICY", MatchAny, "ON", MatchAny, "WITH", "CHECK")) + if (Matches7("ALTER", "POLICY", MatchAny, "ON", MatchAny, "WITH", "CHECK")) COMPLETE_WITH_CONST("("); /* ALTER RULE , add ON */ - else if (Matches3("ALTER", "RULE", MatchAny)) + if (Matches3("ALTER", "RULE", MatchAny)) COMPLETE_WITH_CONST("ON"); /* If we have ALTER RULE ON, then add the correct tablename */ - else if (Matches4("ALTER", "RULE", MatchAny, "ON")) + if (Matches4("ALTER", "RULE", MatchAny, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule, ""); } /* ALTER RULE ON */ - else if (Matches5("ALTER", "RULE", MatchAny, "ON", MatchAny)) + if (Matches5("ALTER", "RULE", MatchAny, "ON", MatchAny)) COMPLETE_WITH_CONST("RENAME TO"); /* ALTER TRIGGER , add ON */ - else if (Matches3("ALTER", "TRIGGER", MatchAny)) + if (Matches3("ALTER", "TRIGGER", MatchAny)) COMPLETE_WITH_CONST("ON"); - else if (Matches4("ALTER", "TRIGGER", MatchAny, MatchAny)) + if (Matches4("ALTER", "TRIGGER", MatchAny, MatchAny)) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger, ""); @@ -1825,17 +1481,17 @@ psql_completion(const char *text, int start, int end) /* * If we have ALTER TRIGGER ON, then add the correct tablename */ - else if (Matches4("ALTER", "TRIGGER", MatchAny, "ON")) + if (Matches4("ALTER", "TRIGGER", MatchAny, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); /* ALTER TRIGGER ON */ - else if (Matches5("ALTER", "TRIGGER", MatchAny, "ON", MatchAny)) + if (Matches5("ALTER", "TRIGGER", MatchAny, "ON", MatchAny)) COMPLETE_WITH_CONST("RENAME TO"); /* * If we detect ALTER TABLE , suggest sub commands */ - else if (Matches3("ALTER", "TABLE", MatchAny)) + if (Matches3("ALTER", "TABLE", MatchAny)) { static const char *const list_ALTER2[] = {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT", @@ -1845,97 +1501,103 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTER2); } /* ALTER TABLE xxx ENABLE */ - else if (Matches4("ALTER", "TABLE", MatchAny, "ENABLE")) + if (Matches4("ALTER", "TABLE", MatchAny, "ENABLE")) COMPLETE_WITH_LIST5("ALWAYS", "REPLICA", "ROW LEVEL SECURITY", "RULE", "TRIGGER"); - else if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "REPLICA|ALWAYS")) + if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "REPLICA|ALWAYS")) COMPLETE_WITH_LIST2("RULE", "TRIGGER"); - else if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "RULE")) + if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "RULE")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_rule_of_table, ""); } - else if (Matches6("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "RULE")) + if (Matches6("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "RULE")) { completion_info_charp = prev4_wd; COMPLETE_WITH_QUERY(Query_for_rule_of_table, ""); } - else if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "TRIGGER")) + if (Matches5("ALTER", "TABLE", MatchAny, "ENABLE", "TRIGGER")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_trigger_of_table, ""); } - else if (Matches6("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "TRIGGER")) + if (Matches6("ALTER", "TABLE", MatchAny, "ENABLE", MatchAny, "TRIGGER")) { completion_info_charp = prev4_wd; COMPLETE_WITH_QUERY(Query_for_trigger_of_table, ""); } /* ALTER TABLE xxx INHERIT */ - else if (Matches4("ALTER", "TABLE", MatchAny, "INHERIT")) + if (Matches4("ALTER", "TABLE", MatchAny, "INHERIT")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); /* ALTER TABLE xxx NO INHERIT */ - else if (Matches5("ALTER", "TABLE", MatchAny, "NO", "INHERIT")) + if (Matches5("ALTER", "TABLE", MatchAny, "NO", "INHERIT")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); /* ALTER TABLE xxx DISABLE */ - else if (Matches4("ALTER", "TABLE", MatchAny, "DISABLE")) + if (Matches4("ALTER", "TABLE", MatchAny, "DISABLE")) COMPLETE_WITH_LIST3("ROW LEVEL SECURITY", "RULE", "TRIGGER"); - else if (Matches5("ALTER", "TABLE", MatchAny, "DISABLE", "RULE")) + if (Matches5("ALTER", "TABLE", MatchAny, "DISABLE", "RULE")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_rule_of_table, ""); } - else if (Matches5("ALTER", "TABLE", MatchAny, "DISABLE", "TRIGGER")) + if (Matches5("ALTER", "TABLE", MatchAny, "DISABLE", "TRIGGER")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_trigger_of_table, ""); } /* ALTER TABLE xxx ALTER */ - else if (Matches4("ALTER", "TABLE", MatchAny, "ALTER")) + if (Matches4("ALTER", "TABLE", MatchAny, "ALTER")) COMPLETE_WITH_ATTR(prev2_wd, ADDLIST2("COLUMN", "CONSTRAINT")); /* ALTER TABLE xxx RENAME */ - else if (Matches4("ALTER", "TABLE", MatchAny, "RENAME")) + if (Matches4("ALTER", "TABLE", MatchAny, "RENAME")) COMPLETE_WITH_ATTR(prev2_wd, ADDLIST3("COLUMN", "CONSTRAINT", "TO")); - else if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME", "COLUMN")) + if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME", "COLUMN")) COMPLETE_WITH_ATTR(prev3_wd, ""); /* ALTER [FOREIGN] TABLE xxx RENAME yyy */ - else if ((HeadMatches2("ALTER", "TABLE") || + if ((HeadMatches2("ALTER", "TABLE") || HeadMatches3("ALTER", "FOREIGN", "TABLE")) && TailMatches2("RENAME", MatchAnyExcept("CONSTRAINT|TO"))) COMPLETE_WITH_CONST("TO"); /* ALTER TABLE xxx RENAME COLUMN/CONSTRAINT yyy */ - else if (Matches6("ALTER", "TABLE", MatchAny, "RENAME", "COLUMN|CONSTRAINT", MatchAnyExcept("TO"))) + if (Matches6("ALTER", "TABLE", MatchAny, "RENAME", "COLUMN|CONSTRAINT", MatchAnyExcept("TO"))) COMPLETE_WITH_CONST("TO"); /* If we have ALTER TABLE DROP, provide COLUMN or CONSTRAINT */ - else if (Matches4("ALTER", "TABLE", MatchAny, "DROP")) + if (Matches4("ALTER", "TABLE", MatchAny, "DROP")) COMPLETE_WITH_LIST2("COLUMN", "CONSTRAINT"); /* ALTER TABLE DROP COLUMN may take IF EXISTS */ - else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN")) + if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN")) COMPLETE_WITH_ATTR(prev3_wd, ADDLIST1("IF EXISTS")); /* ALTER TABLE with ADD/ALTER/DROP after removing optional words */ - else if (HeadMatches4("ALTER", "TABLE", MatchAny, "ADD|ALTER|DROP") && - MidMatchAndRemove1(4, "COLUMN") && - MidMatchAndRemove2(4, "IF", "EXISTS") && - Matches4("ALTER", "TABLE", MatchAny, "ADD|ALTER|DROP")) + if (HeadMatches4("ALTER", "TABLE", MatchAny, "ADD|ALTER|DROP")) + { + if (MidMatches1(5, "COLUMN")) + COLLAPSE(5, 1); + if (MidMatches2(5, "IF", "EXISTS")) + COLLAPSE(5, 2); + } + if (Matches4("ALTER", "TABLE", MatchAny, "ADD|ALTER|DROP")) COMPLETE_WITH_ATTR(prev2_wd, ""); /* If we have ALTER TABLE DROP COLUMN, provide list of columns */ - else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN")) + if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN")) COMPLETE_WITH_ATTR(prev3_wd, ADDLIST1("IF EXISTS")); /* Try the same after removing optional words IF EXISTS */ - else if (HeadMatches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN") && - MidMatchAndRemove2(5, "IF", "EXISTS") && - Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN")) + if (HeadMatches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN") && + MidMatches2(6, "IF", "EXISTS")) + COLLAPSE(6, 2); + + if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "COLUMN")) COMPLETE_WITH_ATTR(prev3_wd, ""); /* * If we have ALTER TABLE ALTER|RENAME|VALIDATE CONSTRAINT, * provide list of constraints */ - else if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME|VALIDATE", "CONSTRAINT")) + if (Matches5("ALTER", "TABLE", MatchAny, "ALTER|RENAME|VALIDATE", "CONSTRAINT")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_constraint_of_table, ""); @@ -1944,49 +1606,51 @@ psql_completion(const char *text, int start, int end) * If we have ALTER TABLE DROP CONSTRAINT, * provide list of constraints */ - else if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT")) + if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_constraint_of_table, ADDLIST1("IF EXISTS")); } /* Try the same after removing optional words IF EXISTS */ - else if (HeadMatches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT") && - MidMatchAndRemove2(5, "IF", "EXISTS") && - Matches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT")) + if (HeadMatches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT") && + MidMatches2(6, "IF", "EXISTS")) + COLLAPSE(6, 2); + + if (Matches5("ALTER", "TABLE", MatchAny, "DROP", "CONSTRAINT")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_constraint_of_table, ""); } /* ALTER TABLE ALTER [COLUMN] */ - else if (Matches6("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny) || + if (Matches6("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny) || Matches5("ALTER", "TABLE", MatchAny, "ALTER", MatchAny)) COMPLETE_WITH_LIST4("TYPE", "SET", "RESET", "DROP"); /* ALTER TABLE ALTER [COLUMN] SET */ - else if (Matches7("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET") || + if (Matches7("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET") || Matches6("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "SET")) COMPLETE_WITH_LIST5("(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE"); /* ALTER TABLE ALTER [COLUMN] SET ( */ - else if (Matches8("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET", "(") || + if (Matches8("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET", "(") || Matches7("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "SET", "(")) COMPLETE_WITH_LIST2("n_distinct", "n_distinct_inherited"); /* ALTER TABLE ALTER [COLUMN] SET STORAGE */ - else if (Matches8("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET", "STORAGE") || + if (Matches8("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "SET", "STORAGE") || Matches7("ALTER", "TABLE", MatchAny, "ALTER", MatchAny, "SET", "STORAGE")) COMPLETE_WITH_LIST4("PLAIN", "EXTERNAL", "EXTENDED", "MAIN"); /* ALTER TABLE ALTER [COLUMN] DROP */ - else if (Matches7("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "DROP") || + if (Matches7("ALTER", "TABLE", MatchAny, "ALTER", "COLUMN", MatchAny, "DROP") || Matches8("ALTER", "TABLE", MatchAny, "TABLE", MatchAny, "ALTER", MatchAny, "DROP")) COMPLETE_WITH_LIST2("DEFAULT", "NOT NULL"); - else if (Matches4("ALTER", "TABLE", MatchAny, "CLUSTER")) + if (Matches4("ALTER", "TABLE", MatchAny, "CLUSTER")) COMPLETE_WITH_CONST("ON"); - else if (Matches5("ALTER", "TABLE", MatchAny, "CLUSTER", "ON")) + if (Matches5("ALTER", "TABLE", MatchAny, "CLUSTER", "ON")) { completion_info_charp = prev3_wd; COMPLETE_WITH_QUERY(Query_for_index_of_table, ""); } /* If we have ALTER TABLE SET, provide list of attributes and '(' */ - else if (Matches4("ALTER", "TABLE", MatchAny, "SET")) + if (Matches4("ALTER", "TABLE", MatchAny, "SET")) COMPLETE_WITH_LIST7("(", "LOGGED", "SCHEMA", "TABLESPACE", "UNLOGGED", "WITH", "WITHOUT"); @@ -1994,19 +1658,19 @@ psql_completion(const char *text, int start, int end) * If we have ALTER TABLE SET TABLESPACE provide a list of * tablespaces */ - else if (Matches5("ALTER", "TABLE", MatchAny, "SET", "TABLESPACE")) + if (Matches5("ALTER", "TABLE", MatchAny, "SET", "TABLESPACE")) COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces, ""); /* If we have ALTER TABLE SET WITH provide OIDS */ - else if (Matches5("ALTER", "TABLE", MatchAny, "SET", "WITH")) + if (Matches5("ALTER", "TABLE", MatchAny, "SET", "WITH")) COMPLETE_WITH_CONST("OIDS"); /* If we have ALTER TABLE SET WITHOUT provide CLUSTER or OIDS */ - else if (Matches5("ALTER", "TABLE", MatchAny, "SET", "WITHOUT")) + if (Matches5("ALTER", "TABLE", MatchAny, "SET", "WITHOUT")) COMPLETE_WITH_LIST2("CLUSTER", "OIDS"); /* ALTER TABLE RESET */ - else if (Matches4("ALTER", "TABLE", MatchAny, "RESET")) + if (Matches4("ALTER", "TABLE", MatchAny, "RESET")) COMPLETE_WITH_CONST("("); /* ALTER TABLE SET|RESET ( */ - else if (Matches5("ALTER", "TABLE", MatchAny, "SET|RESET", "(")) + if (Matches5("ALTER", "TABLE", MatchAny, "SET|RESET", "(")) { static const char *const list_TABLEOPTIONS[] = { @@ -2044,120 +1708,117 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_TABLEOPTIONS); } - else if (Matches7("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING", "INDEX")) + if (Matches7("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING", "INDEX")) { completion_info_charp = prev5_wd; COMPLETE_WITH_QUERY(Query_for_index_of_table, ""); } - else if (Matches6("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING")) + if (Matches6("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY", "USING")) COMPLETE_WITH_CONST("INDEX"); - else if (Matches5("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY")) + if (Matches5("ALTER", "TABLE", MatchAny, "REPLICA", "IDENTITY")) COMPLETE_WITH_LIST4("FULL", "NOTHING", "DEFAULT", "USING"); - else if (Matches4("ALTER", "TABLE", MatchAny, "REPLICA")) + if (Matches4("ALTER", "TABLE", MatchAny, "REPLICA")) COMPLETE_WITH_CONST("IDENTITY"); /* ALTER TABLESPACE with RENAME TO, OWNER TO, SET, RESET */ - else if (Matches3("ALTER", "TABLESPACE", MatchAny)) + if (Matches3("ALTER", "TABLESPACE", MatchAny)) COMPLETE_WITH_LIST4("RENAME TO", "OWNER TO", "SET", "RESET"); /* ALTER TABLESPACE SET|RESET */ - else if (Matches4("ALTER", "TABLESPACE", MatchAny, "SET|RESET")) + if (Matches4("ALTER", "TABLESPACE", MatchAny, "SET|RESET")) COMPLETE_WITH_CONST("("); /* ALTER TABLESPACE SET|RESET ( */ - else if (Matches5("ALTER", "TABLESPACE", MatchAny, "SET|RESET", "(")) + if (Matches5("ALTER", "TABLESPACE", MatchAny, "SET|RESET", "(")) COMPLETE_WITH_LIST3("seq_page_cost", "random_page_cost", "effective_io_concurrency"); /* ALTER TEXT SEARCH */ - else if (Matches3("ALTER", "TEXT", "SEARCH")) + if (Matches3("ALTER", "TEXT", "SEARCH")) COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); - else if (Matches5("ALTER", "TEXT", "SEARCH", "TEMPLATE|PARSER", MatchAny)) + if (Matches5("ALTER", "TEXT", "SEARCH", "TEMPLATE|PARSER", MatchAny)) COMPLETE_WITH_LIST2("RENAME TO", "SET SCHEMA"); - else if (Matches5("ALTER", "TEXT", "SEARCH", "DICTIONARY", MatchAny)) + if (Matches5("ALTER", "TEXT", "SEARCH", "DICTIONARY", MatchAny)) COMPLETE_WITH_LIST3("OWNER TO", "RENAME TO", "SET SCHEMA"); - else if (Matches5("ALTER", "TEXT", "SEARCH", "CONFIGURATION", MatchAny)) + if (Matches5("ALTER", "TEXT", "SEARCH", "CONFIGURATION", MatchAny)) COMPLETE_WITH_LIST6("ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING", "OWNER TO", "RENAME TO", "SET SCHEMA"); - else if (Matches7("ALTER", "TEXT", "SEARCH", "CONFIGURATION", MatchAny, "DROP", "MAPPING")) + if (Matches7("ALTER", "TEXT", "SEARCH", "CONFIGURATION", MatchAny, "DROP", "MAPPING")) COMPLETE_WITH_LIST2("FOR", "IF EXISTS FOR"); - /* Remove optional words IF EXISTS */ - else if (HeadMatches7("ALTER", "TEXT", "SEARCH", "CONFIGURATION", MatchAny, "DROP", "MAPPING") && - MidMatchAndRemove2(7, "IF", "EXISTS") && - false) {} /* Nothing to do for now */ /* complete ALTER TYPE with actions */ - else if (Matches3("ALTER", "TYPE", MatchAny)) + if (Matches3("ALTER", "TYPE", MatchAny)) COMPLETE_WITH_LIST7("ADD ATTRIBUTE", "ADD VALUE", "ALTER ATTRIBUTE", "DROP ATTRIBUTE", "OWNER TO", "RENAME", "SET SCHEMA"); /* complete ALTER TYPE ADD with actions */ - else if (Matches4("ALTER", "TYPE", MatchAny, "ADD")) + if (Matches4("ALTER", "TYPE", MatchAny, "ADD")) COMPLETE_WITH_LIST2("ATTRIBUTE", "VALUE"); - else if (Matches5("ALTER", "TYPE", MatchAny, "ADD", "VALUE")) + if (Matches5("ALTER", "TYPE", MatchAny, "ADD", "VALUE")) COMPLETE_WITH_LIST2("IF NOT EXISTS", ""); /* Remove optional words IF NOT EXISTS */ - else if (HeadMatches5("ALTER", "TYPE", MatchAny, "ADD", "VALUE") && - MidMatchAndRemove3(5, "IF", "NOT", "EXISTS") && - false) {} /* Nothing to do for now */ + if (HeadMatches5("ALTER", "TYPE", MatchAny, "ADD", "VALUE") && + MidMatches2(6, "IF", "EXISTS")) + COLLAPSE(6, 2); /* ALTER TYPE RENAME */ - else if (Matches4("ALTER", "TYPE", MatchAny, "RENAME")) + if (Matches4("ALTER", "TYPE", MatchAny, "RENAME")) COMPLETE_WITH_LIST2("ATTRIBUTE", "TO"); /* ALTER TYPE xxx RENAME ATTRIBUTE yyy */ - else if (Matches6("ALTER", "TYPE", MatchAny, "RENAME", "ATTRIBUTE", MatchAny)) + if (Matches6("ALTER", "TYPE", MatchAny, "RENAME", "ATTRIBUTE", MatchAny)) COMPLETE_WITH_CONST("TO"); /* * If we have ALTER TYPE ALTER/DROP/RENAME ATTRIBUTE, provide list * of attributes */ - else if (Matches5("ALTER", "TYPE", MatchAny, "ALTER|RENAME", "ATTRIBUTE")) + if (Matches5("ALTER", "TYPE", MatchAny, "ALTER|RENAME", "ATTRIBUTE")) COMPLETE_WITH_ATTR(prev3_wd, ""); - else if (Matches5("ALTER", "TYPE", MatchAny, "DROP", "ATTRIBUTE")) + if (Matches5("ALTER", "TYPE", MatchAny, "DROP", "ATTRIBUTE")) COMPLETE_WITH_ATTR(prev3_wd, ADDLIST1("IF EXISTS")); /* Remove optional words IF EXISTS */ - else if (HeadMatches5("ALTER", "TYPE", MatchAny, "DROP", "ATTRIBUTE") && - MidMatchAndRemove2(5, "IF", "EXISTS") && + if (HeadMatches5("ALTER", "TYPE", MatchAny, "DROP", "ATTRIBUTE") && + MidMatches2(6, "IF", "EXISTS")) + COLLAPSE(6, 2); /* ALTER TYPE ALTER ATTRIBUTE */ - Matches6("ALTER", "TYPE", MatchAny, "ALTER", "ATTRIBUTE", MatchAny)) + if (Matches6("ALTER", "TYPE", MatchAny, "ALTER", "ATTRIBUTE", MatchAny)) COMPLETE_WITH_CONST("TYPE"); /* complete ALTER GROUP */ - else if (Matches3("ALTER", "GROUP", MatchAny)) + if (Matches3("ALTER", "GROUP", MatchAny)) COMPLETE_WITH_LIST3("ADD USER", "DROP USER", "RENAME TO"); /* complete ALTER GROUP ADD|DROP with USER */ - else if (Matches4("ALTER", "GROUP", MatchAny, "ADD|DROP")) + if (Matches4("ALTER", "GROUP", MatchAny, "ADD|DROP")) COMPLETE_WITH_CONST("USER"); /* complete ALTER GROUP ADD|DROP USER with a user name */ - else if (Matches5("ALTER", "GROUP", MatchAny, "ADD|DROP", "USER")) + if (Matches5("ALTER", "GROUP", MatchAny, "ADD|DROP", "USER")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); /* BEGIN */ - else if (Matches1("BEGIN")) + if (Matches1("BEGIN")) COMPLETE_WITH_LIST6("WORK", "TRANSACTION", "ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE"); /* END, ABORT */ - else if (Matches1("END|ABORT")) + if (Matches1("END|ABORT")) COMPLETE_WITH_LIST2("WORK", "TRANSACTION"); /* COMMIT */ - else if (Matches1("COMMIT")) + if (Matches1("COMMIT")) COMPLETE_WITH_LIST3("WORK", "TRANSACTION", "PREPARED"); /* RELEASE SAVEPOINT */ - else if (Matches1("RELEASE")) + if (Matches1("RELEASE")) COMPLETE_WITH_CONST("SAVEPOINT"); /* ROLLBACK */ - else if (Matches1("ROLLBACK")) + if (Matches1("ROLLBACK")) COMPLETE_WITH_LIST4("WORK", "TRANSACTION", "TO SAVEPOINT", "PREPARED"); /* CLUSTER */ - else if (Matches1("CLUSTER")) + if (Matches1("CLUSTER")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ADDLIST1("VERBOSE")); - else if (Matches2("CLUSTER", "VERBOSE")) + if (Matches2("CLUSTER", "VERBOSE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ""); /* If we have CLUSTER , then add "USING" */ - else if (Matches2("CLUSTER", MatchAnyExcept("VERBOSE|ON"))) + if (Matches2("CLUSTER", MatchAnyExcept("VERBOSE|ON"))) COMPLETE_WITH_CONST("USING"); /* If we have CLUSTER VERBOSE , then add "USING" */ - else if (Matches3("CLUSTER", "VERBOSE", MatchAny)) + if (Matches3("CLUSTER", "VERBOSE", MatchAny)) COMPLETE_WITH_CONST("USING"); /* If we have CLUSTER USING, then add the index as well */ - else if (Matches3("CLUSTER", MatchAny, "USING") || + if (Matches3("CLUSTER", MatchAny, "USING") || Matches4("CLUSTER", "VERBOSE", MatchAny, "USING")) { completion_info_charp = prev2_wd; @@ -2165,9 +1826,9 @@ psql_completion(const char *text, int start, int end) } /* COMMENT */ - else if (Matches1("COMMENT")) + if (Matches1("COMMENT")) COMPLETE_WITH_CONST("ON"); - else if (Matches2("COMMENT", "ON")) + if (Matches2("COMMENT", "ON")) { static const char *const list_COMMENT[] = {"ACCESS METHOD", "CAST", "COLLATION", "CONVERSION", "DATABASE", @@ -2180,26 +1841,26 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_COMMENT); } - else if (Matches4("COMMENT", "ON", "ACCESS", "METHOD")) + if (Matches4("COMMENT", "ON", "ACCESS", "METHOD")) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods, ""); - else if (Matches3("COMMENT", "ON", "FOREIGN")) + if (Matches3("COMMENT", "ON", "FOREIGN")) COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); - else if (Matches4("COMMENT", "ON", "TEXT", "SEARCH")) + if (Matches4("COMMENT", "ON", "TEXT", "SEARCH")) COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); - else if (Matches3("COMMENT", "ON", "CONSTRAINT")) + if (Matches3("COMMENT", "ON", "CONSTRAINT")) COMPLETE_WITH_QUERY(Query_for_all_table_constraints, ""); - else if (Matches4("COMMENT", "ON", "CONSTRAINT", MatchAny)) + if (Matches4("COMMENT", "ON", "CONSTRAINT", MatchAny)) COMPLETE_WITH_CONST("ON"); - else if (Matches5("COMMENT", "ON", "CONSTRAINT", MatchAny, "ON")) + if (Matches5("COMMENT", "ON", "CONSTRAINT", MatchAny, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_constraint, ""); } - else if (Matches4("COMMENT", "ON", "MATERIALIZED", "VIEW")) + if (Matches4("COMMENT", "ON", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ""); - else if (Matches4("COMMENT", "ON", "EVENT", "TRIGGER")) + if (Matches4("COMMENT", "ON", "EVENT", "TRIGGER")) COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers, ""); - else if (Matches4("COMMENT", "ON", MatchAny, MatchAnyExcept("IS")) || + if (Matches4("COMMENT", "ON", MatchAny, MatchAnyExcept("IS")) || Matches5("COMMENT", "ON", MatchAny, MatchAny, MatchAnyExcept("IS")) || Matches6("COMMENT", "ON", MatchAny, MatchAny, MatchAny, MatchAnyExcept("IS"))) COMPLETE_WITH_CONST("IS"); @@ -2210,274 +1871,278 @@ psql_completion(const char *text, int start, int end) * If we have COPY, offer list of tables or "(" (Also cover the analogous * backslash command). */ - else if (Matches1("COPY|\\copy")) + if (Matches1("COPY|\\copy")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ADDLIST1("(")); /* If we have COPY BINARY, complete with list of tables */ - else if (Matches2("COPY", "BINARY")) + if (Matches2("COPY", "BINARY")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); /* If we have COPY (, complete it with legal commands */ - else if (Matches2("COPY|\\copy", "(")) + if (Matches2("COPY|\\copy", "(")) COMPLETE_WITH_LIST7("SELECT", "TABLE", "VALUES", "INSERT", "UPDATE", "DELETE", "WITH"); /* If we have COPY [BINARY] , complete it with "TO" or "FROM" */ - else if (Matches2("COPY|\\copy", MatchAny) || + if (Matches2("COPY|\\copy", MatchAny) || Matches3("COPY", "BINARY", MatchAny)) COMPLETE_WITH_LIST2("FROM", "TO"); /* If we have COPY [BINARY] FROM|TO, complete with filename */ - else if (Matches3("COPY|\\copy", MatchAny, "FROM|TO") || + if (Matches3("COPY|\\copy", MatchAny, "FROM|TO") || Matches4("COPY", "BINARY", MatchAny, "FROM|TO")) { - SET_COMP_CHARP(""); - matches = completion_matches(text, complete_from_files); + SET_COMPLETION_CHARP(""); + return completion_matches(text, complete_from_files); } /* Handle COPY [BINARY] FROM|TO filename */ - else if (Matches4("COPY|\\copy", MatchAny, "FROM|TO", MatchAny) || + if (Matches4("COPY|\\copy", MatchAny, "FROM|TO", MatchAny) || Matches5("COPY", "BINARY", MatchAny, "FROM|TO", MatchAny)) COMPLETE_WITH_LIST6("BINARY", "OIDS", "DELIMITER", "NULL", "CSV", "ENCODING"); /* Handle COPY [BINARY] FROM|TO filename CSV */ - else if (Matches5("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "CSV") || + if (Matches5("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "CSV") || Matches6("COPY", "BINARY", MatchAny, "FROM|TO", MatchAny, "CSV")) COMPLETE_WITH_LIST5("HEADER", "QUOTE", "ESCAPE", "FORCE QUOTE", "FORCE NOT NULL"); /* CREATE ACCESS METHOD */ /* Complete "CREATE ACCESS METHOD " */ - else if (Matches4("CREATE", "ACCESS", "METHOD", MatchAny)) + if (Matches4("CREATE", "ACCESS", "METHOD", MatchAny)) COMPLETE_WITH_CONST("TYPE"); /* Complete "CREATE ACCESS METHOD TYPE" */ - else if (Matches5("CREATE", "ACCESS", "METHOD", MatchAny, "TYPE")) + if (Matches5("CREATE", "ACCESS", "METHOD", MatchAny, "TYPE")) COMPLETE_WITH_CONST("INDEX"); /* Complete "CREATE ACCESS METHOD TYPE " */ - else if (Matches6("CREATE", "ACCESS", "METHOD", MatchAny, "TYPE", MatchAny)) + if (Matches6("CREATE", "ACCESS", "METHOD", MatchAny, "TYPE", MatchAny)) COMPLETE_WITH_CONST("HANDLER"); /* CREATE DATABASE */ - else if (Matches3("CREATE", "DATABASE", MatchAny)) + if (Matches3("CREATE", "DATABASE", MatchAny)) COMPLETE_WITH_LIST9("OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "IS_TEMPLATE", "ALLOW_CONNECTIONS", "CONNECTION LIMIT", "LC_COLLATE", "LC_CTYPE"); - else if (Matches4("CREATE", "DATABASE", MatchAny, "TEMPLATE")) + if (Matches4("CREATE", "DATABASE", MatchAny, "TEMPLATE")) COMPLETE_WITH_QUERY(Query_for_list_of_template_databases, ""); /* CREATE EXTENSION */ /* Complete with available extensions rather than installed ones. */ - else if (Matches2("CREATE", "EXTENSION")) + if (Matches2("CREATE", "EXTENSION")) COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions, ADDLIST1("IF NOT EXISTS")); /* Try the same after removing optional words IF NOT EXISTS */ - else if (HeadMatches2("CREATE", "EXTENSION") && - MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") && - Matches2("CREATE", "EXTENSION")) + if (HeadMatches2("CREATE", "EXTENSION") && + MidMatches3(3, "IF", "NOT", "EXISTS")) + COLLAPSE(3, 3); + + if (Matches2("CREATE", "EXTENSION")) COMPLETE_WITH_QUERY(Query_for_list_of_available_extensions, ""); /* CREATE EXTENSION */ - else if (Matches3("CREATE", "EXTENSION", MatchAny)) + if (Matches3("CREATE", "EXTENSION", MatchAny)) COMPLETE_WITH_LIST3("WITH SCHEMA", "CASCADE", "VERSION"); /* CREATE EXTENSION VERSION */ - else if (Matches4("CREATE", "EXTENSION", MatchAny, "VERSION")) + if (Matches4("CREATE", "EXTENSION", MatchAny, "VERSION")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_available_extension_versions, ""); } /* CREATE FOREIGN */ - else if (Matches2("CREATE", "FOREIGN")) + if (Matches2("CREATE", "FOREIGN")) COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); /* CREATE FOREIGN TABLE */ - else if (Matches3("CREATE", "FOREIGN", "TABLE")) + if (Matches3("CREATE", "FOREIGN", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, ADDLIST1("IF NOT EXISTS")); /* Remove optional words IF NOT EXISTS */ - else if (HeadMatches3("CREATE", "FOREIGN", "TABLE") && - MidMatchAndRemove3(3, "IF", "NOT", "EXISTS") && - false) {} /* FALL THROUGH */ + if (HeadMatches3("CREATE", "FOREIGN", "TABLE") && + MidMatches3(4, "IF", "NOT", "EXISTS")) + COLLAPSE(4, 3); + + if (Matches3("CREATE", "FOREIGN", "TABLE")) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, ""); /* CREATE FOREIGN DATA WRAPPER */ - else if (Matches5("CREATE", "FOREIGN", "DATA", "WRAPPER", MatchAny)) + if (Matches5("CREATE", "FOREIGN", "DATA", "WRAPPER", MatchAny)) COMPLETE_WITH_LIST3("HANDLER", "VALIDATOR", "OPTIONS"); /* CREATE INDEX --- is allowed inside CREATE SCHEMA, so use TailMatches */ /* First off we complete CREATE UNIQUE with "INDEX" */ - else if (TailMatches2("CREATE", "UNIQUE")) + if (TailMatches2("CREATE", "UNIQUE")) COMPLETE_WITH_CONST("INDEX"); - /* Remove optional word UNIQUE from CREATE UNIQUE INDEX */ - else if (HeadMatches3("CREATE", MatchAny, "INDEX") && - MidMatchAndRemove1(1, "UNIQUE") && - false) {} /* FALL THROUGH */ - /* If we have CREATE INDEX, then add "ON", "CONCURRENTLY" or IF NOT EXISTS, - and existing indexes */ - else if (Matches2("CREATE", "INDEX")) + /* + * Complete CREATE INDEX with "ON", "CONCURRENTLY" or IF NOT EXISTS, and + * existing indexes, after removing optional words + */ + if (HeadMatches2("CREATE", "UNIQUE") && + MidMatches1(2, "UNIQUE")) + COLLAPSE(2, 1); + + if (Matches2("CREATE", "INDEX")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, ADDLIST3("ON", "CONCURRENTLY", "IF NOT EXISTS")); /* Complete CREATE INDEX CONCURRENTLY with "ON" or IF NOT EXISTS and * existing indexes */ - else if (Matches3("CREATE", "INDEX", "CONCURRENTLY")) + if (Matches3("CREATE", "INDEX", "CONCURRENTLY")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, ADDLIST2("IF NOT EXISTS", "ON")); - /* Remove optional words "CONCURRENTLY", "IF NOT EXISTS" */ - else if (HeadMatches2("CREATE", "INDEX") && - MidMatchAndRemove1(2, "CONCURRENTLY") && - MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") && - false) {} /* FALL THROUGH */ - + /* Complete CREATE INDEX after removing optional words */ + if (HeadMatches2("CREATE", "INDEX")) + { + if (MidMatches1(3, "CONCURRENTLY")) + COLLAPSE(3, 1); + if (MidMatches3(3, "IF", "NOT", "EXISTS")) + COLLAPSE(3, 3); + } + if (Matches2("CREATE", "INDEX")) + COMPLETE_THING(-1); /* Complete CREATE INDEX [] ON with a list of tables */ - else if (Matches4("CREATE", "INDEX", MatchAny, "ON") || + if (Matches4("CREATE", "INDEX", MatchAny, "ON") || Matches3("CREATE", "INDEX", "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ""); /* Complete CREATE INDEX with "ON" */ - else if (Matches3("CREATE", "INDEX", MatchAny)) + if (Matches3("CREATE", "INDEX", MatchAny)) COMPLETE_WITH_CONST("ON"); /* * Complete INDEX ON
with a list of table columns (which * should really be in parens) */ - else if (TailMatches4("INDEX", MatchAny, "ON", MatchAny) || + if (TailMatches4("INDEX", MatchAny, "ON", MatchAny) || TailMatches3("INDEX", "ON", MatchAny)) COMPLETE_WITH_LIST2("(", "USING"); - else if (Matches5("INDEX", MatchAny, "ON", MatchAny, "(") || + if (Matches5("INDEX", MatchAny, "ON", MatchAny, "(") || Matches4("INDEX", "ON", MatchAny, "(")) COMPLETE_WITH_ATTR(prev2_wd, ""); /* same if you put in USING */ - else if (TailMatches5("ON", MatchAny, "USING", MatchAny, "(")) + if (TailMatches5("ON", MatchAny, "USING", MatchAny, "(")) COMPLETE_WITH_ATTR(prev4_wd, ""); /* Complete USING with an index method */ - else if (TailMatches5("INDEX", MatchAny, "ON", MatchAny, "USING") || + if (TailMatches5("INDEX", MatchAny, "ON", MatchAny, "USING") || TailMatches4("INDEX", "ON", MatchAny, "USING")) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods, ""); - else if (TailMatches4("ON", MatchAny, "USING", MatchAny) && + if (TailMatches4("ON", MatchAny, "USING", MatchAny) && !TailMatches6("POLICY", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny) && !TailMatches4("FOR", MatchAny, MatchAny, MatchAny)) COMPLETE_WITH_CONST("("); /* CREATE POLICY */ /* Complete "CREATE POLICY ON" */ - else if (Matches3("CREATE", "POLICY", MatchAny)) + if (Matches3("CREATE", "POLICY", MatchAny)) COMPLETE_WITH_CONST("ON"); /* Complete "CREATE POLICY ON
" */ - else if (Matches4("CREATE", "POLICY", MatchAny, "ON")) + if (Matches4("CREATE", "POLICY", MatchAny, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); /* Complete "CREATE POLICY ON
FOR|TO|USING|WITH CHECK" */ - else if (Matches5("CREATE", "POLICY", MatchAny, "ON", MatchAny)) + if (Matches5("CREATE", "POLICY", MatchAny, "ON", MatchAny)) COMPLETE_WITH_LIST4("FOR", "TO", "USING (", "WITH CHECK ("); /* CREATE POLICY ON
FOR ALL|SELECT|INSERT|UPDATE|DELETE */ - else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR")) + if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR")) COMPLETE_WITH_LIST5("ALL", "SELECT", "INSERT", "UPDATE", "DELETE"); /* Complete "CREATE POLICY ON
FOR INSERT TO|WITH CHECK" */ - else if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR", "INSERT")) + if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR", "INSERT")) COMPLETE_WITH_LIST2("TO", "WITH CHECK ("); /* Complete "CREATE POLICY ON
FOR SELECT|DELETE TO|USING" */ - else if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR", "SELECT|DELETE")) + if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR", "SELECT|DELETE")) COMPLETE_WITH_LIST2("TO", "USING ("); /* CREATE POLICY ON
FOR ALL|UPDATE TO|USING|WITH CHECK */ - else if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR", "ALL|UPDATE")) + if (Matches7("CREATE", "POLICY", MatchAny, "ON", MatchAny, "FOR", "ALL|UPDATE")) COMPLETE_WITH_LIST3("TO", "USING (", "WITH CHECK ("); /* Complete "CREATE POLICY ON
TO " */ - else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "TO")) + if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "TO")) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles, ""); /* Complete "CREATE POLICY ON
USING (" */ - else if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "USING")) + if (Matches6("CREATE", "POLICY", MatchAny, "ON", MatchAny, "USING")) COMPLETE_WITH_CONST("("); /* CREATE RULE */ /* Complete "CREATE RULE " with "AS ON" */ - else if (Matches3("CREATE", "RULE", MatchAny)) + if (Matches3("CREATE", "RULE", MatchAny)) COMPLETE_WITH_CONST("AS ON"); /* Complete "CREATE RULE AS" with "ON" */ - else if (Matches4("CREATE", "RULE", MatchAny, "AS")) + if (Matches4("CREATE", "RULE", MatchAny, "AS")) COMPLETE_WITH_CONST("ON"); /* Complete "CREATE RULE AS ON" with SELECT|UPDATE|INSERT|DELETE */ - else if (Matches5("CREATE", "RULE", MatchAny, "AS", "ON")) + if (Matches5("CREATE", "RULE", MatchAny, "AS", "ON")) COMPLETE_WITH_LIST4("SELECT", "UPDATE", "INSERT", "DELETE"); /* Complete "AS ON SELECT|UPDATE|INSERT|DELETE" with a "TO" */ - else if (TailMatches3("AS", "ON", "SELECT|UPDATE|INSERT|DELETE")) + if (TailMatches3("AS", "ON", "SELECT|UPDATE|INSERT|DELETE")) COMPLETE_WITH_CONST("TO"); /* Complete "AS ON TO" with a table name */ - else if (TailMatches4("AS", "ON", "SELECT|UPDATE|INSERT|DELETE", "TO")) + if (TailMatches4("AS", "ON", "SELECT|UPDATE|INSERT|DELETE", "TO")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); -/* Remove optional words TEMPORARY/TEMP */ - else if (HeadMatches3("CREATE", MatchAny, "SEQUENCE") && - MidMatchAndRemove1(1, "TEMP|TEMPORARY") && - false) {} /* FALL THROUGH */ -/* CREATE SEQUENCE */ - else if(Matches2("CREATE", "SEQUENCE")) + +/* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */ + if (Matches2("CREATE", "TEMP|TEMPORARY")) + COMPLETE_WITH_LIST3("SEQUENCE", "TABLE", "VIEW"); +/* Complete "CREATE UNLOGGED" with TABLE or MATVIEW */ + if (Matches2("CREATE", "UNLOGGED")) + COMPLETE_WITH_LIST2("TABLE", "MATERIALIZED VIEW"); + +/* CREATE SEQUCNE after removing optional words TEMPORARY/TEMP */ + if (HeadMatches1("CREATE") && + MidMatches1(2, "TEMP|TEMPORARY|UNLOGGED")) + COLLAPSE(2, 1); + + if (Matches2("CREATE", "SEQUENCE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, ADDLIST1("IF NOT EXISTS")); - else if(HeadMatches2("CREATE", "SEQUENCE") && - MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") && - Matches3("CREATE", "SEQUENCE", MatchAny)) + if(HeadMatches2("CREATE", "SEQUENCE") && + MidMatches3(3, "IF", "NOT", "EXISTS")) + COLLAPSE(3, 3); + + if (Matches3("CREATE", "SEQUENCE", MatchAny)) COMPLETE_WITH_LIST8("INCREMENT BY", "MINVALUE", "MAXVALUE", "NO", "CACHE", "CYCLE", "OWNED BY", "START WITH"); - else if (Matches4("CREATE", "SEQUENCE", MatchAny, "NO")) + if (Matches4("CREATE", "SEQUENCE", MatchAny, "NO")) COMPLETE_WITH_LIST3("MINVALUE", "MAXVALUE", "CYCLE"); /* CREATE SERVER */ - else if (Matches3("CREATE", "SERVER", MatchAny)) + if (Matches3("CREATE", "SERVER", MatchAny)) COMPLETE_WITH_LIST3("TYPE", "VERSION", "FOREIGN DATA WRAPPER"); -/* CREATE SCHEMA */ - else if (Matches2("CREATE", "SCHEMA")) - COMPLETE_WITH_QUERY(Query_for_list_of_schemas, - ADDLIST1("IF NOT EXISTS")); - /* Remove optional words IF NOT EXISTS */ - else if (HeadMatches2("CREATE", "SCHEMA") && - MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") && - false) {} /* FALL THROUGH*/ - /* CREATE TABLE */ - /* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */ - else if (Matches2("CREATE", "TEMP|TEMPORARY")) - COMPLETE_WITH_LIST3("SEQUENCE", "TABLE", "VIEW"); - /* Complete "CREATE UNLOGGED" with TABLE or MATVIEW */ - else if (Matches2("CREATE", "UNLOGGED")) - COMPLETE_WITH_LIST2("TABLE", "MATERIALIZED VIEW"); - + /* Optional words TEMP|TEMPORARY|UNLOGGED is already removed */ /* CREATE TABLE with name after removing optional words */ - else if (HeadMatches3("CREATE", MatchAny, "TABLE") && - MidMatchAndRemove1(1, "TEMP|TEMPORARY|UNLOGGED") && - false) {} /* FALL THROUGH*/ - else if (Matches2("CREATE", "TABLE")) + if (Matches2("CREATE", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ADDLIST1("IF NOT EXISTS")); + /* CREATE TABLE after removing optional words here */ + if (HeadMatches2("CREATE", "TABLE") && + MidMatches3(3, "IF", "NOT", "EXISTS")) + COLLAPSE(3, 3); - /* Remove optional words here */ - else if (HeadMatches2("CREATE", "TABLE") && - MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") && - false) {} /* FALL THROUGH */ - + if (Matches2("CREATE", "TABLE")) + COMPLETE_THING(-1); /* CREATE TABLESPACE */ - else if (Matches3("CREATE", "TABLESPACE", MatchAny)) + if (Matches3("CREATE", "TABLESPACE", MatchAny)) COMPLETE_WITH_LIST2("OWNER", "LOCATION"); /* Complete CREATE TABLESPACE name OWNER name with "LOCATION" */ - else if (Matches5("CREATE", "TABLESPACE", MatchAny, "OWNER", MatchAny)) + if (Matches5("CREATE", "TABLESPACE", MatchAny, "OWNER", MatchAny)) COMPLETE_WITH_CONST("LOCATION"); /* CREATE TEXT SEARCH */ - else if (Matches3("CREATE", "TEXT", "SEARCH")) + if (Matches3("CREATE", "TEXT", "SEARCH")) COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); - else if (Matches5("CREATE", "TEXT", "SEARCH", "CONFIGURATION", MatchAny)) + if (Matches5("CREATE", "TEXT", "SEARCH", "CONFIGURATION", MatchAny)) COMPLETE_WITH_CONST("("); /* CREATE TRIGGER */ /* complete CREATE TRIGGER with BEFORE,AFTER,INSTEAD OF */ - else if (Matches3("CREATE", "TRIGGER", MatchAny)) + if (Matches3("CREATE", "TRIGGER", MatchAny)) COMPLETE_WITH_LIST3("BEFORE", "AFTER", "INSTEAD OF"); /* complete CREATE TRIGGER BEFORE,AFTER with an event */ - else if (Matches4("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER")) + if (Matches4("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER")) COMPLETE_WITH_LIST4("INSERT", "DELETE", "UPDATE", "TRUNCATE"); /* complete CREATE TRIGGER INSTEAD OF with an event */ - else if (Matches5("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF")) + if (Matches5("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF")) COMPLETE_WITH_LIST3("INSERT", "DELETE", "UPDATE"); /* complete CREATE TRIGGER BEFORE,AFTER sth with OR,ON */ - else if (Matches5("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER", MatchAny) || + if (Matches5("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER", MatchAny) || TailMatches6("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF", MatchAny)) COMPLETE_WITH_LIST2("ON", "OR"); @@ -2485,17 +2150,17 @@ psql_completion(const char *text, int start, int end) * complete CREATE TRIGGER BEFORE,AFTER event ON with a list of * tables */ - else if (TailMatches6("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER", MatchAny, "ON")) + if (TailMatches6("CREATE", "TRIGGER", MatchAny, "BEFORE|AFTER", MatchAny, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); /* complete CREATE TRIGGER ... INSTEAD OF event ON with a list of views */ - else if (TailMatches7("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF", MatchAny, "ON")) + if (TailMatches7("CREATE", "TRIGGER", MatchAny, "INSTEAD", "OF", MatchAny, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, ""); /* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */ - else if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("EXECUTE")) + if (HeadMatches2("CREATE", "TRIGGER") && TailMatches1("EXECUTE")) COMPLETE_WITH_CONST("PROCEDURE"); /* CREATE ROLE,USER,GROUP */ - else if (Matches3("CREATE", "ROLE|GROUP|USER", MatchAny) && + if (Matches3("CREATE", "ROLE|GROUP|USER", MatchAny) && !TailMatches2("USER", "MAPPING")) { static const char *const list_CREATEROLE[] = @@ -2510,7 +2175,7 @@ psql_completion(const char *text, int start, int end) } /* CREATE ROLE,USER,GROUP WITH */ - else if (Matches4("CREATE", "ROLE|GROUP|USER", MatchAny, "WITH")) + if (Matches4("CREATE", "ROLE|GROUP|USER", MatchAny, "WITH")) { /* Similar to the above, but don't complete "WITH" again. */ static const char *const list_CREATEROLE_WITH[] = @@ -2528,84 +2193,88 @@ psql_completion(const char *text, int start, int end) * complete CREATE ROLE,USER,GROUP ENCRYPTED,UNENCRYPTED with * PASSWORD */ - else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "ENCRYPTED|UNENCRYPTED")) + if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "ENCRYPTED|UNENCRYPTED")) COMPLETE_WITH_CONST("PASSWORD"); /* complete CREATE ROLE,USER,GROUP IN with ROLE,GROUP */ - else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "IN")) + if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "IN")) COMPLETE_WITH_LIST2("GROUP", "ROLE"); /* CREATE VIEW */ - else if (Matches2("CREATE", "VIEW")) + if (Matches2("CREATE", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, ADDLIST1("IF NOT EXISTS")); /* CREATE VIEW with AS after removing optional words */ - else if (HeadMatches2("CREATE", "VIEW") && - MidMatchAndRemove3(2, "IF", "NOT", "EXISTS") && - Matches3("CREATE", "VIEW", MatchAny)) + if (HeadMatches2("CREATE", "VIEW") && + MidMatches3(3, "IF", "NOT", "EXISTS")) + COLLAPSE(3, 3); + + if (Matches3("CREATE", "VIEW", MatchAny)) COMPLETE_WITH_CONST("AS"); /* Complete "CREATE VIEW AS with "SELECT" */ - else if (TailMatches4("CREATE", "VIEW", MatchAny, "AS")) + if (TailMatches4("CREATE", "VIEW", MatchAny, "AS")) COMPLETE_WITH_CONST("SELECT"); /* CREATE MATERIALIZED VIEW */ - else if (Matches2("CREATE", "MATERIALIZED")) + if (Matches2("CREATE", "MATERIALIZED")) COMPLETE_WITH_CONST("VIEW"); - else if (Matches3("CREATE", "MATERIALIZED", "VIEW")) + if (Matches3("CREATE", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ADDLIST1("IF NOT EXISTS")); /* Try the same after removing optional words IF NOT EXISTS. VIEW will be * completed afterwards */ - else if (HeadMatches3("CREATE", "MATERIALIZED", "VIEW") && - MidMatchAndRemove3(3, "IF", "NOT", "EXISTS") && - Matches3("CREATE", "MATERIALIZED", "VIEW")) + if (HeadMatches3("CREATE", "MATERIALIZED", "VIEW") && + MidMatches3(4, "IF", "NOT", "EXISTS")) + COLLAPSE(4, 3); + + if (Matches3("CREATE", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ""); /* Complete CREATE MATERIALIZED VIEW with AS */ - else if (Matches4("CREATE", "MATERIALIZED", "VIEW", MatchAny)) + if (Matches4("CREATE", "MATERIALIZED", "VIEW", MatchAny)) COMPLETE_WITH_CONST("AS"); /* Complete "CREATE MATERIALIZED VIEW AS with "SELECT" */ - else if (Matches5("CREATE", "MATERIALIZED", "VIEW", MatchAny, "AS")) + if (Matches5("CREATE", "MATERIALIZED", "VIEW", MatchAny, "AS")) COMPLETE_WITH_CONST("SELECT"); /* CREATE EVENT TRIGGER */ - else if (Matches2("CREATE", "EVENT")) + if (Matches2("CREATE", "EVENT")) COMPLETE_WITH_CONST("TRIGGER"); /* Complete CREATE EVENT TRIGGER with ON */ - else if (Matches4("CREATE", "EVENT", "TRIGGER", MatchAny)) + if (Matches4("CREATE", "EVENT", "TRIGGER", MatchAny)) COMPLETE_WITH_CONST("ON"); /* Complete CREATE EVENT TRIGGER ON with event_type */ - else if (Matches5("CREATE", "EVENT", "TRIGGER", MatchAny, "ON")) + if (Matches5("CREATE", "EVENT", "TRIGGER", MatchAny, "ON")) COMPLETE_WITH_LIST3("ddl_command_start", "ddl_command_end", "sql_drop"); /* DECLARE */ - else if (Matches2("DECLARE", MatchAny)) + if (Matches2("DECLARE", MatchAny)) COMPLETE_WITH_LIST5("BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR"); - else if (HeadMatches1("DECLARE") && TailMatches1("CURSOR")) + if (HeadMatches1("DECLARE") && TailMatches1("CURSOR")) COMPLETE_WITH_LIST3("WITH HOLD", "WITHOUT HOLD", "FOR"); /* DELETE --- can be inside EXPLAIN, RULE, etc */ /* ... despite which, only complete DELETE with FROM at start of line */ - else if (Matches1("DELETE")) + if (Matches1("DELETE")) COMPLETE_WITH_CONST("FROM"); /* Complete DELETE FROM with a list of tables */ - else if (TailMatches2("DELETE", "FROM")) + if (TailMatches2("DELETE", "FROM")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, ""); /* Complete DELETE FROM
*/ - else if (TailMatches3("DELETE", "FROM", MatchAny)) + if (TailMatches3("DELETE", "FROM", MatchAny)) COMPLETE_WITH_LIST2("USING", "WHERE"); /* XXX: implement tab completion for DELETE ... USING */ /* DISCARD */ - else if (Matches1("DISCARD")) + if (Matches1("DISCARD")) COMPLETE_WITH_LIST4("ALL", "PLANS", "SEQUENCES", "TEMP"); /* DO */ - else if (Matches1("DO")) + if (Matches1("DO")) COMPLETE_WITH_CONST("LANGUAGE"); /* DROP */ /* Complete DROP object with CASCADE / RESTRICT */ - else if (Matches3("DROP", + if (Matches3("DROP", "COLLATION|CONVERSION|DOMAIN|EXTENSION|LANGUAGE|SCHEMA|SEQUENCE|SERVER|TABLE|TYPE|VIEW", MatchAny) || Matches4("DROP", "ACCESS", "METHOD", MatchAny) || @@ -2618,144 +2287,166 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST2("CASCADE", "RESTRICT"); /* help completing some of the variants */ - else if (Matches2("DROP", "AGGREGATE")) + if (Matches2("DROP", "AGGREGATE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, ADDLIST1("IF EXISTS")); - else if (Matches2("DROP", "FUNCTION")) + if (Matches2("DROP", "FUNCTION")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, ADDLIST1("IF EXISTS")); /* Try the same after removing optional words IF EXISTS */ - else if (HeadMatches2("DROP", "AGGREGATE|FUNCTION") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches3("DROP", "AGGREGATE|FUNCTION", MatchAny)) + if (HeadMatches2("DROP", "AGGREGATE|FUNCTION") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches3("DROP", "AGGREGATE|FUNCTION", MatchAny)) COMPLETE_WITH_CONST("("); - else if (Matches4("DROP", "AGGREGATE|FUNCTION", MatchAny, "(")) + if (Matches4("DROP", "AGGREGATE|FUNCTION", MatchAny, "(")) COMPLETE_WITH_FUNCTION_ARG(prev2_wd); - else if (Matches2("DROP", "FOREIGN")) + if (Matches2("DROP", "FOREIGN")) COMPLETE_WITH_LIST2("DATA WRAPPER", "TABLE"); - else if (Matches4("DROP", "FOREIGN", "DATA", "WRAPPER")) + if (Matches4("DROP", "FOREIGN", "DATA", "WRAPPER")) COMPLETE_WITH_QUERY(Query_for_list_of_fdws, ADDLIST1("IF EXISTS")); /* Try the same after removing optional words IF EXISTS */ - else if (HeadMatches4("DROP", "FOREIGN", "DATA", "WRAPPER") && - MidMatchAndRemove2(4, "IF", "EXISTS") && - false) {} /* FALL THROUGH */ + if (HeadMatches4("DROP", "FOREIGN", "DATA", "WRAPPER") && + MidMatches2(5, "IF", "EXISTS")) + COLLAPSE(5, 2); + + if (Matches4("DROP", "FOREIGN", "DATA", "WRAPPER")) + COMPLETE_WITH_QUERY(Query_for_list_of_fdws, ""); /* DROP INDEX */ - else if (Matches2("DROP", "INDEX")) + if (Matches2("DROP", "INDEX")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, ADDLIST2("IF EXISTS","CONCURRENTLY")); - else if (Matches3("DROP", "INDEX", "CONCURRENTLY")) + if (Matches3("DROP", "INDEX", "CONCURRENTLY")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, ADDLIST1("IF EXISTS")); /* Try the same after optional words CONCURRENTLY and IF NOT EXISTS */ - else if (HeadMatches2("DROP", "INDEX") && - MidMatchAndRemove1(2, "CONCURRENTLY") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches3("DROP", "INDEX", MatchAny)) + if (HeadMatches2("DROP", "INDEX")) + { + if (MidMatches1(3, "CONCURRENTLY")) + COLLAPSE(3, 1); + if (MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + } + if (Matches3("DROP", "INDEX", MatchAny)) COMPLETE_WITH_LIST2("CASCADE", "RESTRICT"); /* DROP MATERIALIZED VIEW */ - else if (Matches2("DROP", "MATERIALIZED")) + if (Matches2("DROP", "MATERIALIZED")) COMPLETE_WITH_CONST("VIEW"); - else if (Matches2("DROP", "VIEW")) + if (Matches2("DROP", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, ADDLIST1("IF EXISTS")); /* Remove optional words IF EXISTS */ - else if (HeadMatches2("DROP", "VIEW") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - false) {} /* FALL THROUGH */ - else if (Matches3("DROP", "MATERIALIZED", "VIEW")) + if (HeadMatches2("DROP", "VIEW") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches2("DROP", "VIEW")) + COMPLETE_THING(-1); + if (Matches3("DROP", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ADDLIST1("IF EXISTS")); /* Try the same after removing optional words IF EXISTS */ - else if (HeadMatches3("DROP", "MATERIALIZED", "VIEW") && - MidMatchAndRemove2(3, "IF", "EXISTS") && - Matches3("DROP", "MATERIALIZED", "VIEW")) + if (HeadMatches3("DROP", "MATERIALIZED", "VIEW") && + MidMatches2(4, "IF", "EXISTS")) + COLLAPSE(4, 2); + + if (Matches3("DROP", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ""); /* DROP OWNED BY */ - else if (Matches2("DROP", "OWNED")) + if (Matches2("DROP", "OWNED")) COMPLETE_WITH_CONST("BY"); - else if (Matches3("DROP", "OWNED", "BY")) + if (Matches3("DROP", "OWNED", "BY")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); - else if (Matches3("DROP", "TEXT", "SEARCH")) + if (Matches3("DROP", "TEXT", "SEARCH")) COMPLETE_WITH_LIST4("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); /* DROP TRIGGER */ - else if (Matches2("DROP", "TRIGGER")) + if (Matches2("DROP", "TRIGGER")) COMPLETE_WITH_QUERY(Query_for_list_of_triggers, ADDLIST1("IF EXISTS")); /* Try the same after removing optional words IF EXISTS */ - else if (HeadMatches2("DROP", "TRIGGER") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches3("DROP", "TRIGGER", MatchAny)) + if (HeadMatches2("DROP", "TRIGGER") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches3("DROP", "TRIGGER", MatchAny)) COMPLETE_WITH_CONST("ON"); - else if (Matches4("DROP", "TRIGGER", MatchAny, "ON")) + if (Matches4("DROP", "TRIGGER", MatchAny, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger, ""); } - else if (Matches5("DROP", "TRIGGER", MatchAny, "ON", MatchAny)) + if (Matches5("DROP", "TRIGGER", MatchAny, "ON", MatchAny)) COMPLETE_WITH_LIST2("CASCADE", "RESTRICT"); /* DROP ACCESS METHOD */ - else if (Matches2("DROP", "ACCESS")) + if (Matches2("DROP", "ACCESS")) COMPLETE_WITH_CONST("METHOD"); - else if (Matches3("DROP", "ACCESS", "METHOD")) + if (Matches3("DROP", "ACCESS", "METHOD")) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods, ""); /* DROP EVENT TRIGGER */ - else if (Matches2("DROP", "EVENT")) + if (Matches2("DROP", "EVENT")) COMPLETE_WITH_CONST("TRIGGER"); - else if (Matches3("DROP", "EVENT", "TRIGGER")) + if (Matches3("DROP", "EVENT", "TRIGGER")) COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers, ADDLIST1("IF EXISTS")); /* Trye the same after removing optional words IF EXISTS */ - else if (HeadMatches3("DROP", "EVENT", "TRIGGER") && - MidMatchAndRemove2(3, "IF", "EXISTS") && - Matches3("DROP", "EVENT", "TRIGGER")) + if (HeadMatches3("DROP", "EVENT", "TRIGGER") && + MidMatches2(4, "IF", "EXISTS")) + COLLAPSE(4, 2); + + if (Matches3("DROP", "EVENT", "TRIGGER")) COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers, ""); /* DROP POLICY */ - else if (Matches2("DROP", "POLICY")) + if (Matches2("DROP", "POLICY")) COMPLETE_WITH_QUERY(Query_for_list_of_policies, ADDLIST1("IF EXISTS")); /* Try the same after after removing optional words IF EXISTS */ - else if (HeadMatches2("DROP", "POLICY") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches2("DROP", "POLICY")) + if (HeadMatches2("DROP", "POLICY") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches2("DROP", "POLICY")) COMPLETE_WITH_QUERY(Query_for_list_of_policies, ""); /* DROP POLICY */ - else if (Matches3("DROP", "POLICY", MatchAny)) + if (Matches3("DROP", "POLICY", MatchAny)) COMPLETE_WITH_CONST("ON"); /* DROP POLICY ON */ - else if (Matches4("DROP", "POLICY", MatchAny, "ON")) + if (Matches4("DROP", "POLICY", MatchAny, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_policy, ""); } /* DROP RULE */ - else if (Matches2("DROP", "RULE")) + if (Matches2("DROP", "RULE")) COMPLETE_WITH_QUERY(Query_for_list_of_rules, ADDLIST1("IF EXISTS")); /* DROP RULE , after removing optional words IF EXISTS */ - else if (HeadMatches2("DROP", "RULE") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - Matches3("DROP", "RULE", MatchAny)) + if (HeadMatches2("DROP", "RULE") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches3("DROP", "RULE", MatchAny)) COMPLETE_WITH_CONST("ON"); - else if (Matches4("DROP", "RULE", MatchAny, "ON")) + if (Matches4("DROP", "RULE", MatchAny, "ON")) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule, ""); } - else if (Matches5("DROP", "RULE", MatchAny, "ON", MatchAny)) + if (Matches5("DROP", "RULE", MatchAny, "ON", MatchAny)) COMPLETE_WITH_LIST2("CASCADE", "RESTRICT"); /* IF EXISTS processing for DROP everything else */ - else if (Matches2("DROP", + if (Matches2("DROP", "CAST|COLLATION|CONVERSION|DATABASE|DOMAIN|" "GROUP|LANGUAGE|OPERATOR|ROLE|SCHEMA|SEQUENCE|" "SERVER|TABLE|TABLESPACE|TYPE|USER") || @@ -2789,19 +2480,25 @@ psql_completion(const char *text, int start, int end) } } /* Remove optional IF EXISTS from DROP */ - else if (HeadMatches2("DROP", - "CAST|COLLATION|CONVERSION|DATABASE|DOMAIN|GROUP|" - "LANGUAGE|OPERATOR|ROLE|SCHEMA|SEQUENCE|SERVER|" - "TABLE|TABLESPACE|TYPE|USER") && - MidMatchAndRemove2(2, "IF", "EXISTS") && - false) {} /* FALL THROUGH */ - else if (HeadMatches4("DROP", "TEXT", "SEARCH", - "CONFIGURATION|DICTIONARY|PARSER|TEMPLATE") && - MidMatchAndRemove2(4, "IF", "EXISTS") && - false) {} /* FALL THROUGH */ + if (HeadMatches2("DROP", + "CAST|COLLATION|CONVERSION|DATABASE|DOMAIN|GROUP|" + "LANGUAGE|OPERATOR|ROLE|SCHEMA|SEQUENCE|SERVER|" + "TABLE|TABLESPACE|TYPE|USER") && + MidMatches2(3, "IF", "EXISTS")) + COLLAPSE(3, 2); + + if (Matches2("DROP", MatchAny)) + COMPLETE_THING(-1); + if (HeadMatches4("DROP", "TEXT", "SEARCH", + "CONFIGURATION|DICTIONARY|PARSER|TEMPLATE") && + MidMatches2(5, "IF", "EXISTS")) + COLLAPSE(5, 2); + + if (Matches4("DROP", "TEXT", "SEARCH", MatchAny)) + COMPLETE_THING(-1); /* EXECUTE */ - else if (Matches1("EXECUTE")) + if (Matches1("EXECUTE")) COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements, ""); /* EXPLAIN */ @@ -2809,22 +2506,22 @@ psql_completion(const char *text, int start, int end) /* * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands */ - else if (Matches1("EXPLAIN")) + if (Matches1("EXPLAIN")) COMPLETE_WITH_LIST7("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "ANALYZE", "VERBOSE"); - else if (Matches2("EXPLAIN", "ANALYZE")) + if (Matches2("EXPLAIN", "ANALYZE")) COMPLETE_WITH_LIST6("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE", "VERBOSE"); - else if (Matches2("EXPLAIN", "VERBOSE") || + if (Matches2("EXPLAIN", "VERBOSE") || Matches3("EXPLAIN", "ANALYZE", "VERBOSE")) COMPLETE_WITH_LIST5("SELECT", "INSERT", "DELETE", "UPDATE", "DECLARE"); /* FETCH && MOVE */ /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */ - else if (Matches1("FETCH|MOVE")) + if (Matches1("FETCH|MOVE")) COMPLETE_WITH_LIST4("ABSOLUTE", "BACKWARD", "FORWARD", "RELATIVE"); /* Complete FETCH with one of ALL, NEXT, PRIOR */ - else if (Matches2("FETCH|MOVE", MatchAny)) + if (Matches2("FETCH|MOVE", MatchAny)) COMPLETE_WITH_LIST3("ALL", "NEXT", "PRIOR"); /* @@ -2832,30 +2529,30 @@ psql_completion(const char *text, int start, int end) * but we may as well tab-complete both: perhaps some users prefer one * variant or the other. */ - else if (Matches3("FETCH|MOVE", MatchAny, MatchAny)) + if (Matches3("FETCH|MOVE", MatchAny, MatchAny)) COMPLETE_WITH_LIST2("FROM", "IN"); /* FOREIGN DATA WRAPPER */ /* applies in ALTER/DROP FDW and in CREATE SERVER */ - else if (TailMatches3("FOREIGN", "DATA", "WRAPPER") && + if (TailMatches3("FOREIGN", "DATA", "WRAPPER") && !TailMatches4("CREATE", MatchAny, MatchAny, MatchAny)) COMPLETE_WITH_QUERY(Query_for_list_of_fdws, ""); /* applies in CREATE SERVER */ - else if (TailMatches4("FOREIGN", "DATA", "WRAPPER", MatchAny) && + if (TailMatches4("FOREIGN", "DATA", "WRAPPER", MatchAny) && HeadMatches2("CREATE", "SERVER")) COMPLETE_WITH_CONST("OPTIONS"); /* FOREIGN TABLE */ - else if (TailMatches2("FOREIGN", "TABLE")) + if (TailMatches2("FOREIGN", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, ""); /* FOREIGN SERVER */ - else if (TailMatches2("FOREIGN", "SERVER")) + if (TailMatches2("FOREIGN", "SERVER")) COMPLETE_WITH_QUERY(Query_for_list_of_servers, ""); /* GRANT && REVOKE --- is allowed inside CREATE SCHEMA, so use TailMatches */ /* Complete GRANT/REVOKE with a list of roles and privileges */ - else if (TailMatches1("GRANT|REVOKE")) + if (TailMatches1("GRANT|REVOKE")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ADDLIST13("SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", @@ -2865,11 +2562,11 @@ psql_completion(const char *text, int start, int end) * Complete GRANT/REVOKE with "ON", GRANT/REVOKE with * TO/FROM */ - else if (TailMatches2("GRANT|REVOKE", MatchAny)) + if (TailMatches2("GRANT|REVOKE", MatchAny)) { if (TailMatches1("SELECT|INSERT|UPDATE|DELETE|TRUNCATE|REFERENCES|TRIGGER|CREATE|CONNECT|TEMPORARY|TEMP|EXECUTE|USAGE|ALL")) COMPLETE_WITH_CONST("ON"); - else if (TailMatches2("GRANT", MatchAny)) + if (TailMatches2("GRANT", MatchAny)) COMPLETE_WITH_CONST("TO"); else COMPLETE_WITH_CONST("FROM"); @@ -2886,7 +2583,7 @@ psql_completion(const char *text, int start, int end) * here will only work if the privilege list contains exactly one * privilege. */ - else if (TailMatches3("GRANT|REVOKE", MatchAny, "ON")) + if (TailMatches3("GRANT|REVOKE", MatchAny, "ON")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, ADDLIST15("ALL FUNCTIONS IN SCHEMA", "ALL SEQUENCES IN SCHEMA", @@ -2904,11 +2601,11 @@ psql_completion(const char *text, int start, int end) "TABLESPACE", "TYPE")); - else if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", "ALL")) + if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", "ALL")) COMPLETE_WITH_LIST3("FUNCTIONS IN SCHEMA", "SEQUENCES IN SCHEMA", "TABLES IN SCHEMA"); - else if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", "FOREIGN")) + if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", "FOREIGN")) COMPLETE_WITH_LIST2("DATA WRAPPER", "SERVER"); /* @@ -2917,27 +2614,27 @@ psql_completion(const char *text, int start, int end) * * Complete "GRANT/REVOKE * ON *" with "TO/FROM". */ - else if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", MatchAny)) + if (TailMatches4("GRANT|REVOKE", MatchAny, "ON", MatchAny)) { if (TailMatches1("DATABASE")) COMPLETE_WITH_QUERY(Query_for_list_of_databases, ""); - else if (TailMatches1("DOMAIN")) + if (TailMatches1("DOMAIN")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, ""); - else if (TailMatches1("FUNCTION")) + if (TailMatches1("FUNCTION")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, ""); - else if (TailMatches1("LANGUAGE")) + if (TailMatches1("LANGUAGE")) COMPLETE_WITH_QUERY(Query_for_list_of_languages, ""); - else if (TailMatches1("SCHEMA")) + if (TailMatches1("SCHEMA")) COMPLETE_WITH_QUERY(Query_for_list_of_schemas, ""); - else if (TailMatches1("SEQUENCE")) + if (TailMatches1("SEQUENCE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, ""); - else if (TailMatches1("TABLE")) + if (TailMatches1("TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, ""); - else if (TailMatches1("TABLESPACE")) + if (TailMatches1("TABLESPACE")) COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces, ""); - else if (TailMatches1("TYPE")) + if (TailMatches1("TYPE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, ""); - else if (TailMatches4("GRANT", MatchAny, MatchAny, MatchAny)) + if (TailMatches4("GRANT", MatchAny, MatchAny, MatchAny)) COMPLETE_WITH_CONST("TO"); else COMPLETE_WITH_CONST("FROM"); @@ -2947,18 +2644,18 @@ psql_completion(const char *text, int start, int end) * Complete "GRANT/REVOKE ... TO/FROM" with username, PUBLIC, * CURRENT_USER, or SESSION_USER. */ - else if ((HeadMatches1("GRANT") && TailMatches1("TO")) || + if ((HeadMatches1("GRANT") && TailMatches1("TO")) || (HeadMatches1("REVOKE") && TailMatches1("FROM"))) COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles, ""); /* Complete "GRANT/REVOKE ... ON * *" with TO/FROM */ - else if (HeadMatches1("GRANT") && TailMatches3("ON", MatchAny, MatchAny)) + if (HeadMatches1("GRANT") && TailMatches3("ON", MatchAny, MatchAny)) COMPLETE_WITH_CONST("TO"); - else if (HeadMatches1("REVOKE") && TailMatches3("ON", MatchAny, MatchAny)) + if (HeadMatches1("REVOKE") && TailMatches3("ON", MatchAny, MatchAny)) COMPLETE_WITH_CONST("FROM"); /* Complete "GRANT/REVOKE * ON ALL * IN SCHEMA *" with TO/FROM */ - else if (TailMatches8("GRANT|REVOKE", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny)) + if (TailMatches8("GRANT|REVOKE", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny)) { if (TailMatches8("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny)) COMPLETE_WITH_CONST("TO"); @@ -2967,7 +2664,7 @@ psql_completion(const char *text, int start, int end) } /* Complete "GRANT/REVOKE * ON FOREIGN DATA WRAPPER *" with TO/FROM */ - else if (TailMatches7("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "DATA", "WRAPPER", MatchAny)) + if (TailMatches7("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "DATA", "WRAPPER", MatchAny)) { if (TailMatches7("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny)) COMPLETE_WITH_CONST("TO"); @@ -2976,7 +2673,7 @@ psql_completion(const char *text, int start, int end) } /* Complete "GRANT/REVOKE * ON FOREIGN SERVER *" with TO/FROM */ - else if (TailMatches6("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "SERVER", MatchAny)) + if (TailMatches6("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "SERVER", MatchAny)) { if (TailMatches6("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny)) COMPLETE_WITH_CONST("TO"); @@ -2985,62 +2682,62 @@ psql_completion(const char *text, int start, int end) } /* GROUP BY */ - else if (TailMatches3("FROM", MatchAny, "GROUP")) + if (TailMatches3("FROM", MatchAny, "GROUP")) COMPLETE_WITH_CONST("BY"); /* IMPORT FOREIGN SCHEMA */ - else if (Matches1("IMPORT")) + if (Matches1("IMPORT")) COMPLETE_WITH_CONST("FOREIGN SCHEMA"); - else if (Matches2("IMPORT", "FOREIGN")) + if (Matches2("IMPORT", "FOREIGN")) COMPLETE_WITH_CONST("SCHEMA"); /* INSERT --- can be inside EXPLAIN, RULE, etc */ /* Complete INSERT with "INTO" */ - else if (TailMatches1("INSERT")) + if (TailMatches1("INSERT")) COMPLETE_WITH_CONST("INTO"); /* Complete INSERT INTO with table names */ - else if (TailMatches2("INSERT", "INTO")) + if (TailMatches2("INSERT", "INTO")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, ""); /* Complete "INSERT INTO
(" with attribute names */ - else if (TailMatches4("INSERT", "INTO", MatchAny, "(")) + if (TailMatches4("INSERT", "INTO", MatchAny, "(")) COMPLETE_WITH_ATTR(prev2_wd, ""); /* * Complete INSERT INTO
with "(" or "VALUES" or "SELECT" or * "TABLE" or "DEFAULT VALUES" */ - else if (TailMatches3("INSERT", "INTO", MatchAny)) + if (TailMatches3("INSERT", "INTO", MatchAny)) COMPLETE_WITH_LIST5("(", "DEFAULT VALUES", "SELECT", "TABLE", "VALUES"); /* * Complete INSERT INTO
(attribs) with "VALUES" or "SELECT" or * "TABLE" */ - else if (TailMatches4("INSERT", "INTO", MatchAny, MatchAny) && + if (TailMatches4("INSERT", "INTO", MatchAny, MatchAny) && ends_with(prev_wd, ')')) COMPLETE_WITH_LIST3("SELECT", "TABLE", "VALUES"); /* Insert an open parenthesis after "VALUES" */ - else if (TailMatches1("VALUES") && !TailMatches2("DEFAULT", "VALUES")) + if (TailMatches1("VALUES") && !TailMatches2("DEFAULT", "VALUES")) COMPLETE_WITH_CONST("("); /* LOCK */ /* Complete LOCK [TABLE] with a list of tables */ - else if (Matches1("LOCK")) + if (Matches1("LOCK")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ADDLIST1("TABLE")); - else if (Matches2("LOCK", "TABLE")) + if (Matches2("LOCK", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); /* For the following, handle the case of a single table only for now */ /* Complete LOCK [TABLE]
with "IN" */ - else if (Matches2("LOCK", MatchAnyExcept("TABLE")) || + if (Matches2("LOCK", MatchAnyExcept("TABLE")) || Matches3("LOCK", "TABLE", MatchAny)) COMPLETE_WITH_CONST("IN"); /* Complete LOCK [TABLE]
IN with a lock mode */ - else if (Matches3("LOCK", MatchAny, "IN") || + if (Matches3("LOCK", MatchAny, "IN") || Matches4("LOCK", "TABLE", MatchAny, "IN")) COMPLETE_WITH_LIST8("ACCESS SHARE MODE", "ROW SHARE MODE", "ROW EXCLUSIVE MODE", @@ -3049,25 +2746,25 @@ psql_completion(const char *text, int start, int end) "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE"); /* NOTIFY --- can be inside EXPLAIN, RULE, etc */ - else if (TailMatches1("NOTIFY")) + if (TailMatches1("NOTIFY")) COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s'", ""); /* OPTIONS */ - else if (TailMatches1("OPTIONS")) + if (TailMatches1("OPTIONS")) COMPLETE_WITH_CONST("("); /* OWNER TO - complete with available roles */ - else if (TailMatches2("OWNER", "TO")) + if (TailMatches2("OWNER", "TO")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); /* ORDER BY */ - else if (TailMatches3("FROM", MatchAny, "ORDER")) + if (TailMatches3("FROM", MatchAny, "ORDER")) COMPLETE_WITH_CONST("BY"); - else if (TailMatches4("FROM", MatchAny, "ORDER", "BY")) + if (TailMatches4("FROM", MatchAny, "ORDER", "BY")) COMPLETE_WITH_ATTR(prev3_wd, ""); /* PREPARE xx AS */ - else if (Matches3("PREPARE", MatchAny, "AS")) + if (Matches3("PREPARE", MatchAny, "AS")) COMPLETE_WITH_LIST4("SELECT", "UPDATE", "INSERT", "DELETE FROM"); /* @@ -3076,60 +2773,60 @@ psql_completion(const char *text, int start, int end) */ /* REASSIGN OWNED BY xxx TO yyy */ - else if (Matches1("REASSIGN")) + if (Matches1("REASSIGN")) COMPLETE_WITH_CONST("OWNED BY"); - else if (Matches2("REASSIGN", "OWNED")) + if (Matches2("REASSIGN", "OWNED")) COMPLETE_WITH_CONST("BY"); - else if (Matches3("REASSIGN", "OWNED", "BY")) + if (Matches3("REASSIGN", "OWNED", "BY")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); - else if (Matches4("REASSIGN", "OWNED", "BY", MatchAny)) + if (Matches4("REASSIGN", "OWNED", "BY", MatchAny)) COMPLETE_WITH_CONST("TO"); - else if (Matches5("REASSIGN", "OWNED", "BY", MatchAny, "TO")) + if (Matches5("REASSIGN", "OWNED", "BY", MatchAny, "TO")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); /* REFRESH MATERIALIZED VIEW */ - else if (Matches1("REFRESH")) + if (Matches1("REFRESH")) COMPLETE_WITH_CONST("MATERIALIZED VIEW"); - else if (Matches2("REFRESH", "MATERIALIZED")) + if (Matches2("REFRESH", "MATERIALIZED")) COMPLETE_WITH_CONST("VIEW"); - else if (Matches3("REFRESH", "MATERIALIZED", "VIEW")) + if (Matches3("REFRESH", "MATERIALIZED", "VIEW")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ADDLIST1("CONCURRENTLY")); - else if (Matches4("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY")) + if (Matches4("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ""); - else if (Matches4("REFRESH", "MATERIALIZED", "VIEW", MatchAny)) + if (Matches4("REFRESH", "MATERIALIZED", "VIEW", MatchAny)) COMPLETE_WITH_CONST("WITH"); - else if (Matches5("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny)) + if (Matches5("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny)) COMPLETE_WITH_CONST("WITH"); - else if (Matches5("REFRESH", "MATERIALIZED", "VIEW", MatchAny, "WITH")) + if (Matches5("REFRESH", "MATERIALIZED", "VIEW", MatchAny, "WITH")) COMPLETE_WITH_LIST2("NO DATA", "DATA"); - else if (Matches6("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny, "WITH")) + if (Matches6("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny, "WITH")) COMPLETE_WITH_LIST2("NO DATA", "DATA"); - else if (Matches6("REFRESH", "MATERIALIZED", "VIEW", MatchAny, "WITH", "NO")) + if (Matches6("REFRESH", "MATERIALIZED", "VIEW", MatchAny, "WITH", "NO")) COMPLETE_WITH_CONST("DATA"); - else if (Matches7("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny, "WITH", "NO")) + if (Matches7("REFRESH", "MATERIALIZED", "VIEW", "CONCURRENTLY", MatchAny, "WITH", "NO")) COMPLETE_WITH_CONST("DATA"); /* REINDEX */ - else if (Matches1("REINDEX")) + if (Matches1("REINDEX")) COMPLETE_WITH_LIST5("TABLE", "INDEX", "SYSTEM", "SCHEMA", "DATABASE"); - else if (Matches2("REINDEX", "TABLE")) + if (Matches2("REINDEX", "TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ""); - else if (Matches2("REINDEX", "INDEX")) + if (Matches2("REINDEX", "INDEX")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, ""); - else if (Matches2("REINDEX", "SCHEMA")) + if (Matches2("REINDEX", "SCHEMA")) COMPLETE_WITH_QUERY(Query_for_list_of_schemas, ""); - else if (Matches2("REINDEX", "SYSTEM|DATABASE")) + if (Matches2("REINDEX", "SYSTEM|DATABASE")) COMPLETE_WITH_QUERY(Query_for_list_of_databases, ""); /* SECURITY LABEL */ - else if (Matches1("SECURITY")) + if (Matches1("SECURITY")) COMPLETE_WITH_CONST("LABEL"); - else if (Matches2("SECURITY", "LABEL")) + if (Matches2("SECURITY", "LABEL")) COMPLETE_WITH_LIST2("ON", "FOR"); - else if (Matches4("SECURITY", "LABEL", "FOR", MatchAny)) + if (Matches4("SECURITY", "LABEL", "FOR", MatchAny)) COMPLETE_WITH_CONST("ON"); - else if (Matches3("SECURITY", "LABEL", "ON") || + if (Matches3("SECURITY", "LABEL", "ON") || Matches5("SECURITY", "LABEL", "FOR", MatchAny, "ON")) { static const char *const list_SECURITY_LABEL[] = @@ -3140,7 +2837,7 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(list_SECURITY_LABEL); } - else if (Matches5("SECURITY", "LABEL", "ON", MatchAny, MatchAny)) + if (Matches5("SECURITY", "LABEL", "ON", MatchAny, MatchAny)) COMPLETE_WITH_CONST("IS"); /* SELECT */ @@ -3148,71 +2845,55 @@ psql_completion(const char *text, int start, int end) /* SET, RESET, SHOW */ /* Complete with a variable name */ - else if (TailMatches1("SET|RESET") && !TailMatches3("UPDATE", MatchAny, "SET")) + if (TailMatches1("SET|RESET") && !TailMatches3("UPDATE", MatchAny, "SET")) COMPLETE_WITH_QUERY(Query_for_list_of_set_vars, ""); - else if (Matches1("SHOW")) + if (Matches1("SHOW")) COMPLETE_WITH_QUERY(Query_for_list_of_show_vars, ""); /* Complete "SET TRANSACTION" */ - else if (Matches2("SET", "TRANSACTION")) - COMPLETE_WITH_LIST5("SNAPSHOT", "ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE"); - else if (Matches2("BEGIN|START", "TRANSACTION") || + if (Matches2("SET|BEGIN|START", "TRANSACTION") || Matches2("BEGIN", "WORK") || - Matches1("BEGIN") || Matches5("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION")) - COMPLETE_WITH_LIST4("ISOLATION LEVEL", "READ", "DEFERRABLE", "NOT DEFERRABLE"); - else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "NOT") || - Matches2("BEGIN", "NOT") || - Matches6("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "NOT")) - COMPLETE_WITH_CONST("DEFERRABLE"); - else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION") || - Matches2("BEGIN", "ISOLATION") || + COMPLETE_WITH_LIST2("ISOLATION LEVEL", "READ"); + if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION") || Matches6("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION")) COMPLETE_WITH_CONST("LEVEL"); - else if (Matches4("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL") || - Matches3("BEGIN", "ISOLATION", "LEVEL") || - Matches7("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION", "LEVEL")) + if (Matches4("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL")) COMPLETE_WITH_LIST3("READ", "REPEATABLE READ", "SERIALIZABLE"); - else if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "READ") || - Matches4("BEGIN", "ISOLATION", "LEVEL", "READ") || - Matches8("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION", "LEVEL", "READ")) + if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "READ")) COMPLETE_WITH_LIST2("UNCOMMITTED", "COMMITTED"); - else if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "REPEATABLE") || - Matches4("BEGIN", "ISOLATION", "LEVEL", "REPEATABLE") || - Matches8("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "ISOLATION", "LEVEL", "REPEATABLE")) + if (Matches5("SET|BEGIN|START", "TRANSACTION|WORK", "ISOLATION", "LEVEL", "REPEATABLE")) COMPLETE_WITH_CONST("READ"); - else if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "READ") || - Matches2("BEGIN", "READ") || - Matches6("SET", "SESSION", "CHARACTERISTICS", "AS", "TRANSACTION", "READ")) + if (Matches3("SET|BEGIN|START", "TRANSACTION|WORK", "READ")) COMPLETE_WITH_LIST2("ONLY", "WRITE"); /* SET CONSTRAINTS */ - else if (Matches2("SET", "CONSTRAINTS")) + if (Matches2("SET", "CONSTRAINTS")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_constraints_with_schema, ADDLIST1("ALL")); /* Complete SET CONSTRAINTS with DEFERRED|IMMEDIATE */ - else if (Matches3("SET", "CONSTRAINTS", MatchAny)) + if (Matches3("SET", "CONSTRAINTS", MatchAny)) COMPLETE_WITH_LIST2("DEFERRED", "IMMEDIATE"); /* Complete SET ROLE */ - else if (Matches2("SET", "ROLE")) + if (Matches2("SET", "ROLE")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */ - else if (Matches2("SET", "SESSION")) + if (Matches2("SET", "SESSION")) COMPLETE_WITH_LIST2("AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION"); /* Complete SET SESSION AUTHORIZATION with username */ - else if (Matches3("SET", "SESSION", "AUTHORIZATION")) + if (Matches3("SET", "SESSION", "AUTHORIZATION")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ADDLIST1("DEFAULT")); /* Complete RESET SESSION with AUTHORIZATION */ - else if (Matches2("RESET", "SESSION")) + if (Matches2("RESET", "SESSION")) COMPLETE_WITH_CONST("AUTHORIZATION"); /* Complete SET with "TO" */ - else if (Matches2("SET", MatchAny)) + if (Matches2("SET", MatchAny)) COMPLETE_WITH_CONST("TO"); /* Complete ALTER DATABASE|FUNCTION|ROLE|USER ... SET */ - else if (HeadMatches2("ALTER", "DATABASE|FUNCTION|ROLE|USER") && + if (HeadMatches2("ALTER", "DATABASE|FUNCTION|ROLE|USER") && TailMatches2("SET", MatchAny)) COMPLETE_WITH_LIST2("FROM CURRENT", "TO"); /* Suggest possible variable values */ - else if (TailMatches3("SET", MatchAny, "TO|=")) + if (TailMatches3("SET", MatchAny, "TO|=")) { /* special cased code for individual GUCs */ if (TailMatches2("DateStyle", "TO|=")) @@ -3225,7 +2906,7 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST(my_list); } - else if (TailMatches2("search_path", "TO|=")) + if (TailMatches2("search_path", "TO|=")) COMPLETE_WITH_QUERY(Query_for_list_of_schemas " AND nspname not like 'pg\\_toast%%' " " AND nspname not like 'pg\\_temp%%' ", @@ -3233,103 +2914,108 @@ psql_completion(const char *text, int start, int end) else { /* generic, type based, GUC support */ - char *guctype = get_guctype(prev2_wd); + char guctype[6]; - if (guctype && strcmp(guctype, "enum") == 0) + /* + * The value guc_guctype returned is + */ + if (get_guctype(guctype, 6, prev2_wd)) { - char querybuf[1024]; + if (strcmp(guctype, "enum") == 0) + { + char querybuf[1024]; - snprintf(querybuf, sizeof(querybuf), Query_for_enum, prev2_wd); - COMPLETE_WITH_QUERY(querybuf, ""); + snprintf(querybuf, sizeof(querybuf), + Query_for_enum, prev2_wd); + COMPLETE_WITH_QUERY(querybuf, ""); + } + if (strcmp(guctype, "bool") == 0) + COMPLETE_WITH_LIST9("on", "off", "true", "false", + "yes", "no", "1", "0", "DEFAULT"); } - else if (guctype && strcmp(guctype, "bool") == 0) - COMPLETE_WITH_LIST9("on", "off", "true", "false", "yes", "no", - "1", "0", "DEFAULT"); else COMPLETE_WITH_CONST("DEFAULT"); - - if (guctype) - free(guctype); } } /* START TRANSACTION */ - else if (Matches1("START")) + if (Matches1("START")) COMPLETE_WITH_CONST("TRANSACTION"); /* TABLE, but not TABLE embedded in other commands */ - else if (Matches1("TABLE")) + if (Matches1("TABLE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, ""); /* TABLESAMPLE */ - else if (TailMatches1("TABLESAMPLE")) + if (TailMatches1("TABLESAMPLE")) COMPLETE_WITH_QUERY(Query_for_list_of_tablesample_methods, ""); - else if (TailMatches2("TABLESAMPLE", MatchAny)) + if (TailMatches2("TABLESAMPLE", MatchAny)) COMPLETE_WITH_CONST("("); /* TRUNCATE */ - else if (Matches1("TRUNCATE")) + if (Matches1("TRUNCATE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); /* UNLISTEN */ - else if (Matches1("UNLISTEN")) + if (Matches1("UNLISTEN")) COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(channel) FROM pg_catalog.pg_listening_channels() AS channel WHERE substring(pg_catalog.quote_ident(channel),1,%d)='%s' UNION SELECT '*'", ""); /* UPDATE --- can be inside EXPLAIN, RULE, etc */ /* If prev. word is UPDATE suggest a list of tables */ - else if (TailMatches1("UPDATE")) + if (TailMatches1("UPDATE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_updatables, ""); /* Complete UPDATE
with "SET" */ - else if (TailMatches2("UPDATE", MatchAny)) + if (TailMatches2("UPDATE", MatchAny)) COMPLETE_WITH_CONST("SET"); /* Complete UPDATE
SET with list of attributes */ - else if (TailMatches3("UPDATE", MatchAny, "SET")) + if (TailMatches3("UPDATE", MatchAny, "SET")) COMPLETE_WITH_ATTR(prev2_wd, ""); /* UPDATE
SET = */ - else if (TailMatches4("UPDATE", MatchAny, "SET", MatchAny)) + if (TailMatches4("UPDATE", MatchAny, "SET", MatchAny)) COMPLETE_WITH_CONST("="); /* USER MAPPING */ - else if (Matches3("ALTER|CREATE", "USER", "MAPPING")) + if (Matches3("ALTER|CREATE", "USER", "MAPPING")) COMPLETE_WITH_CONST("FOR"); - else if (Matches3("DROP", "USER", "MAPPING")) + if (Matches3("DROP", "USER", "MAPPING")) COMPLETE_WITH_LIST2("FOR", "IF EXISTS FOR"); - else if (HeadMatches3("DROP", "USER", "MAPPING") && - MidMatchAndRemove2(3, "IF", "EXISTS") && - false) {} /* FALL THROUGH */ - else if (Matches4("CREATE", "USER", "MAPPING", "FOR")) + if (HeadMatches3("DROP", "USER", "MAPPING") && + MidMatches2(4, "IF", "EXISTS")) + COLLAPSE(4, 2); + + if (Matches4("CREATE", "USER", "MAPPING", "FOR")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ADDLIST3("CURRENT_USER", "PUBLIC", "USER")); - else if (Matches4("ALTER|DROP", "USER", "MAPPING", "FOR")) + if (Matches4("ALTER|DROP", "USER", "MAPPING", "FOR")) COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings, ""); - else if (Matches5("CREATE|ALTER|DROP", "USER", "MAPPING", "FOR", MatchAny)) + if (Matches5("CREATE|ALTER|DROP", "USER", "MAPPING", "FOR", MatchAny)) COMPLETE_WITH_CONST("SERVER"); - else if (Matches7("CREATE|ALTER", "USER", "MAPPING", "FOR", MatchAny, "SERVER", MatchAny)) + if (Matches7("CREATE|ALTER", "USER", "MAPPING", "FOR", MatchAny, "SERVER", MatchAny)) COMPLETE_WITH_CONST("OPTIONS"); /* * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ] * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ] */ - else if (Matches1("VACUUM")) + if (Matches1("VACUUM")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ADDLIST4("FULL", "FREEZE", "ANALYZE", "VERBOSE")); - else if (Matches2("VACUUM", "FULL|FREEZE")) + if (Matches2("VACUUM", "FULL|FREEZE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ADDLIST2("ANALYZE", "VERBOSE")); - else if (Matches3("VACUUM", "FULL|FREEZE", "ANALYZE")) + if (Matches3("VACUUM", "FULL|FREEZE", "ANALYZE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ADDLIST1("VERBOSE")); - else if (Matches3("VACUUM", "FULL|FREEZE", "VERBOSE")) + if (Matches3("VACUUM", "FULL|FREEZE", "VERBOSE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ADDLIST1("ANALYZE")); - else if (Matches2("VACUUM", "VERBOSE")) + if (Matches2("VACUUM", "VERBOSE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ADDLIST1("ANALYZE")); - else if (Matches2("VACUUM", "ANALYZE")) + if (Matches2("VACUUM", "ANALYZE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ADDLIST1("VERBOSE")); - else if (HeadMatches1("VACUUM")) + if (HeadMatches1("VACUUM")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tm, ""); /* WITH [RECURSIVE] */ @@ -3338,114 +3024,114 @@ psql_completion(const char *text, int start, int end) * Only match when WITH is the first word, as WITH may appear in many * other contexts. */ - else if (Matches1("WITH")) + if (Matches1("WITH")) COMPLETE_WITH_CONST("RECURSIVE"); /* ANALYZE */ /* Complete with list of tables */ - else if (Matches1("ANALYZE")) + if (Matches1("ANALYZE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tmf, ""); /* WHERE */ /* Simple case of the word before the where being the table name */ - else if (TailMatches2(MatchAny, "WHERE")) + if (TailMatches2(MatchAny, "WHERE")) COMPLETE_WITH_ATTR(prev2_wd, ""); /* ... FROM ... */ /* TODO: also include SRF ? */ - else if (TailMatches1("FROM") && !Matches3("COPY|\\copy", MatchAny, "FROM")) + if (TailMatches1("FROM") && !Matches3("COPY|\\copy", MatchAny, "FROM")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, ""); /* ... JOIN ... */ - else if (TailMatches1("JOIN")) + if (TailMatches1("JOIN")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, ""); /* Backslash commands */ /* TODO: \dc \dd \dl */ - else if (TailMatchesCS1("\\?")) + if (TailMatchesCS1("\\?")) COMPLETE_WITH_LIST_CS3("commands", "options", "variables"); - else if (TailMatchesCS1("\\connect|\\c")) + if (TailMatchesCS1("\\connect|\\c")) { if (!recognized_connection_string(text)) COMPLETE_WITH_QUERY(Query_for_list_of_databases, ""); } - else if (TailMatchesCS2("\\connect|\\c", MatchAny)) + if (TailMatchesCS2("\\connect|\\c", MatchAny)) { if (!recognized_connection_string(prev_wd)) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); } - else if (TailMatchesCS1("\\da*")) + if (TailMatchesCS1("\\da*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, ""); - else if (TailMatchesCS1("\\dA*")) + if (TailMatchesCS1("\\dA*")) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods, ""); - else if (TailMatchesCS1("\\db*")) + if (TailMatchesCS1("\\db*")) COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces, ""); - else if (TailMatchesCS1("\\dD*")) + if (TailMatchesCS1("\\dD*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, ""); - else if (TailMatchesCS1("\\des*")) + if (TailMatchesCS1("\\des*")) COMPLETE_WITH_QUERY(Query_for_list_of_servers, ""); - else if (TailMatchesCS1("\\deu*")) + if (TailMatchesCS1("\\deu*")) COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings, ""); - else if (TailMatchesCS1("\\dew*")) + if (TailMatchesCS1("\\dew*")) COMPLETE_WITH_QUERY(Query_for_list_of_fdws, ""); - else if (TailMatchesCS1("\\df*")) + if (TailMatchesCS1("\\df*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, ""); - else if (TailMatchesCS1("\\dFd*")) + if (TailMatchesCS1("\\dFd*")) COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries, ""); - else if (TailMatchesCS1("\\dFp*")) + if (TailMatchesCS1("\\dFp*")) COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers, ""); - else if (TailMatchesCS1("\\dFt*")) + if (TailMatchesCS1("\\dFt*")) COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates, ""); /* must be at end of \dF alternatives: */ - else if (TailMatchesCS1("\\dF*")) + if (TailMatchesCS1("\\dF*")) COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations, ""); - else if (TailMatchesCS1("\\di*")) + if (TailMatchesCS1("\\di*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, ""); - else if (TailMatchesCS1("\\dL*")) + if (TailMatchesCS1("\\dL*")) COMPLETE_WITH_QUERY(Query_for_list_of_languages, ""); - else if (TailMatchesCS1("\\dn*")) + if (TailMatchesCS1("\\dn*")) COMPLETE_WITH_QUERY(Query_for_list_of_schemas, ""); - else if (TailMatchesCS1("\\dp") || TailMatchesCS1("\\z")) + if (TailMatchesCS1("\\dp") || TailMatchesCS1("\\z")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf, ""); - else if (TailMatchesCS1("\\ds*")) + if (TailMatchesCS1("\\ds*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, ""); - else if (TailMatchesCS1("\\dt*")) + if (TailMatchesCS1("\\dt*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ""); - else if (TailMatchesCS1("\\dT*")) + if (TailMatchesCS1("\\dT*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, ""); - else if (TailMatchesCS1("\\du*") || TailMatchesCS1("\\dg*")) + if (TailMatchesCS1("\\du*") || TailMatchesCS1("\\dg*")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); - else if (TailMatchesCS1("\\dv*")) + if (TailMatchesCS1("\\dv*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, ""); - else if (TailMatchesCS1("\\dx*")) + if (TailMatchesCS1("\\dx*")) COMPLETE_WITH_QUERY(Query_for_list_of_extensions, ""); - else if (TailMatchesCS1("\\dm*")) + if (TailMatchesCS1("\\dm*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, ""); - else if (TailMatchesCS1("\\dE*")) + if (TailMatchesCS1("\\dE*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_foreign_tables, ""); - else if (TailMatchesCS1("\\dy*")) + if (TailMatchesCS1("\\dy*")) COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers, ""); /* must be at end of \d alternatives: */ - else if (TailMatchesCS1("\\d*")) + if (TailMatchesCS1("\\d*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, ""); - else if (TailMatchesCS1("\\ef")) + if (TailMatchesCS1("\\ef")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, ""); - else if (TailMatchesCS1("\\ev")) + if (TailMatchesCS1("\\ev")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, ""); - else if (TailMatchesCS1("\\encoding")) + if (TailMatchesCS1("\\encoding")) COMPLETE_WITH_QUERY(Query_for_list_of_encodings, ""); - else if (TailMatchesCS1("\\h") || TailMatchesCS1("\\help")) + if (TailMatchesCS1("\\h") || TailMatchesCS1("\\help")) COMPLETE_WITH_LIST(sql_commands); - else if (TailMatchesCS1("\\l*") && !TailMatchesCS1("\\lo*")) + if (TailMatchesCS1("\\l*") && !TailMatchesCS1("\\lo*")) COMPLETE_WITH_QUERY(Query_for_list_of_databases, ""); - else if (TailMatchesCS1("\\password")) + if (TailMatchesCS1("\\password")) COMPLETE_WITH_QUERY(Query_for_list_of_roles, ""); - else if (TailMatchesCS1("\\pset")) + if (TailMatchesCS1("\\pset")) { static const char *const my_list[] = {"border", "columns", "expanded", "fieldsep", "fieldsep_zero", @@ -3456,7 +3142,7 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST_CS(my_list); } - else if (TailMatchesCS2("\\pset", MatchAny)) + if (TailMatchesCS2("\\pset", MatchAny)) { if (TailMatchesCS1("format")) { @@ -3466,53 +3152,53 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH_LIST_CS(my_list); } - else if (TailMatchesCS1("linestyle")) + if (TailMatchesCS1("linestyle")) COMPLETE_WITH_LIST_CS3("ascii", "old-ascii", "unicode"); - else if (TailMatchesCS1("unicode_border_linestyle|" + if (TailMatchesCS1("unicode_border_linestyle|" "unicode_column_linestyle|" "unicode_header_linestyle")) COMPLETE_WITH_LIST_CS2("single", "double"); } - else if (TailMatchesCS1("\\unset")) + if (TailMatchesCS1("\\unset")) { - matches = complete_from_variables(text, "", "", true); + return complete_from_variables(text, "", "", true); } - else if (TailMatchesCS1("\\set")) + if (TailMatchesCS1("\\set")) { - matches = complete_from_variables(text, "", "", false); + return complete_from_variables(text, "", "", false); } - else if (TailMatchesCS2("\\set", MatchAny)) + if (TailMatchesCS2("\\set", MatchAny)) { if (TailMatchesCS1("AUTOCOMMIT|ON_ERROR_STOP|QUIET|" "SINGLELINE|SINGLESTEP")) COMPLETE_WITH_LIST_CS2("on", "off"); - else if (TailMatchesCS1("COMP_KEYWORD_CASE")) + if (TailMatchesCS1("COMP_KEYWORD_CASE")) COMPLETE_WITH_LIST_CS4("lower", "upper", "preserve-lower", "preserve-upper"); - else if (TailMatchesCS1("ECHO")) + if (TailMatchesCS1("ECHO")) COMPLETE_WITH_LIST_CS4("errors", "queries", "all", "none"); - else if (TailMatchesCS1("ECHO_HIDDEN")) + if (TailMatchesCS1("ECHO_HIDDEN")) COMPLETE_WITH_LIST_CS3("noexec", "off", "on"); - else if (TailMatchesCS1("HISTCONTROL")) + if (TailMatchesCS1("HISTCONTROL")) COMPLETE_WITH_LIST_CS4("ignorespace", "ignoredups", "ignoreboth", "none"); - else if (TailMatchesCS1("ON_ERROR_ROLLBACK")) + if (TailMatchesCS1("ON_ERROR_ROLLBACK")) COMPLETE_WITH_LIST_CS3("on", "off", "interactive"); - else if (TailMatchesCS1("SHOW_CONTEXT")) + if (TailMatchesCS1("SHOW_CONTEXT")) COMPLETE_WITH_LIST_CS3("never", "errors", "always"); - else if (TailMatchesCS1("VERBOSITY")) + if (TailMatchesCS1("VERBOSITY")) COMPLETE_WITH_LIST_CS3("default", "verbose", "terse"); } - else if (TailMatchesCS1("\\sf*")) + if (TailMatchesCS1("\\sf*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, ""); - else if (TailMatchesCS1("\\sv*")) + if (TailMatchesCS1("\\sv*")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, ""); - else if (TailMatchesCS1("\\cd|\\e|\\edit|\\g|\\i|\\include|" + if (TailMatchesCS1("\\cd|\\e|\\edit|\\g|\\i|\\include|" "\\ir|\\include_relative|\\o|\\out|" "\\s|\\w|\\write|\\lo_import")) { - SET_COMP_CHARP("\\"); - matches = completion_matches(text, complete_from_files); + SET_COMPLETION_CHARP("\\"); + return completion_matches(text, complete_from_files); } /* @@ -3520,41 +3206,9 @@ psql_completion(const char *text, int start, int end) * check if that was the previous word. If so, execute the query to get a * list of them. */ - else - { - const pgsql_thing_t *ent = find_thing_entry(prev_wd); - - if (ent) - { - if (ent->query) - COMPLETE_WITH_QUERY(ent->query, ""); - else if (ent->squery) - COMPLETE_WITH_SCHEMA_QUERY(*ent->squery, ""); - } - } - - /* - * If we still don't have anything to match we have to fabricate some sort - * of default list. If we were to just return NULL, readline automatically - * attempts filename completion, and that's usually no good. - */ - if (matches == NULL) - { - COMPLETE_WITH_CONST(""); -#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER - rl_completion_append_character = '\0'; -#endif - } - - /* free storage */ - free(previous_words); - free(words_buffer); - - /* Return our Grand List O' Matches */ - return matches; + COMPLETE_THING(-1); } - /* * GENERATOR FUNCTIONS * @@ -4320,14 +3974,15 @@ get_previous_words(int point, char **buffer, int *nwords) * Returns NULL if the variable is unknown. Otherwise the returned string, * containing the type, has to be freed. */ -static char * -get_guctype(const char *varname) +static bool +get_guctype(char *buf, size_t len, const char *varname) { PQExpBufferData query_buffer; char *e_varname; PGresult *result; - char *guctype = NULL; + bool success = true; + memset(buf, 0, len); e_varname = escape_string(varname); initPQExpBuffer(&query_buffer); @@ -4341,11 +3996,12 @@ get_guctype(const char *varname) free(e_varname); if (PQresultStatus(result) == PGRES_TUPLES_OK && PQntuples(result) > 0) - guctype = pg_strdup(PQgetvalue(result, 0, 0)); - + strncpy(buf, PQgetvalue(result, 0, 0), len - 1); + else + success = false; PQclear(result); - return guctype; + return success; } /* -- 2.9.2