diff -cr cvs/pgsql/src/bin/psql/tab-complete.c cvs.build/pgsql/src/bin/psql/tab-complete.c *** cvs/pgsql/src/bin/psql/tab-complete.c 2006-01-11 10:46:08.000000000 +0100 --- cvs.build/pgsql/src/bin/psql/tab-complete.c 2006-02-04 01:12:59.000000000 +0100 *************** *** 125,134 **** * Communication variables set by COMPLETE_WITH_FOO macros and then used by * the completion callback functions. Ugly but there is no better way. */ ! static const char *completion_charp; /* to pass a string */ ! static const char *const * completion_charpp; /* to pass a list of strings */ ! static const char *completion_info_charp; /* to pass a second string */ ! static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */ /* A couple of macros to ease typing. You can use these to complete the given string with --- 125,145 ---- * Communication variables set by COMPLETE_WITH_FOO macros and then used by * the completion callback functions. Ugly but there is no better way. */ ! ! /* to pass a string */ ! static const char *completion_charp; ! ! /* to pass a const list of strings */ ! static const char *const * completion_charpp; ! ! /* to pass a malloced list of strings */ ! static char **completion_malloced_charpp; ! ! /* to pass a second string */ ! static const char *completion_info_charp; ! ! /* to pass a SchemaQuery */ ! static const SchemaQuery *completion_squery; /* A couple of macros to ease typing. You can use these to complete the given string with *************** *** 137,153 **** 3) The items from a null-pointer-terminated list. 4) A string constant 5) The list of attributes to the given table. */ #define COMPLETE_WITH_QUERY(query) \ ! do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0) #define COMPLETE_WITH_SCHEMA_QUERY(query,addon) \ ! do { completion_squery = &(query); completion_charp = addon; matches = completion_matches(text, complete_from_schema_query); } while(0) #define COMPLETE_WITH_LIST(list) \ ! do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0) #define COMPLETE_WITH_CONST(string) \ ! do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0) #define COMPLETE_WITH_ATTR(table) \ ! do {completion_charp = Query_for_list_of_attributes; completion_info_charp = table; matches = completion_matches(text, complete_from_query); } while(0) /* * Assembly instructions for schema queries --- 148,196 ---- 3) The items from a null-pointer-terminated list. 4) A string constant 5) The list of attributes to the given table. + 6) A list that can contain several of the above (malloc'ed list). */ #define COMPLETE_WITH_QUERY(query) \ ! do { completion_charp = query; \ ! matches = completion_matches(text, complete_from_query); \ ! } while(0) #define COMPLETE_WITH_SCHEMA_QUERY(query,addon) \ ! do { completion_squery = &(query); \ ! completion_charp = addon; \ ! matches = completion_matches(text, complete_from_schema_query); \ ! } while(0) #define COMPLETE_WITH_LIST(list) \ ! do { completion_charpp = list; \ ! matches = completion_matches(text, complete_from_list); \ ! } while(0) #define COMPLETE_WITH_CONST(string) \ ! do { completion_charp = string; \ ! matches = completion_matches(text, complete_from_const); \ ! } while(0) #define COMPLETE_WITH_ATTR(table) \ ! do {completion_charp = Query_for_list_of_attributes; \ ! completion_info_charp = table; \ ! matches = completion_matches(text, complete_from_query); \ ! } while(0) ! ! /* ! * Keep the "malloced" keyword in all the names such that we remember that ! * memory got allocated here. COMPLETE_WITH_MALLOCED_LIST frees this memory. ! */ ! #define COMPLETE_WITH_MALLOCED_LIST(list) \ ! do { completion_malloced_charpp = list; \ ! matches = completion_matches(text, complete_from_malloced_list); \ ! free(completion_malloced_charpp); \ ! completion_malloced_charpp = NULL; \ ! } while(0) ! #define MALLOCED_LIST_ADD_ITEM(list, item) \ ! ((list) = list_add_item((list), (item))) ! #define GET_MALLOCED_LIST_WITH_ATTR(table) \ ! (get_query_list(text, Query_for_list_of_attributes, (table))) ! #define GET_MALLOCED_LIST_WITH_QUERY(query) \ ! (get_query_list(text, (query), NULL)) ! #define GET_MALLOCED_LIST_WITH_SCHEMA_QUERY(query,addon) \ ! (get_schema_query_list(text, &(query), addon)) /* * Assembly instructions for schema queries *************** *** 463,468 **** --- 506,521 ---- /* Forward declaration of functions */ + static char **get_empty_list(void); + static char **get_query_list(const char *text, const char *query, + const char *completion_info); + static char **get_schema_query_list(const char *text, const SchemaQuery* squery, + const char *completion_info); + static char **_get_query_list(int is_schema_query, + const char *text, const char *query, + const char *completion_info); + static char **list_add_item(char **list, char *item); + static char **psql_completion(char *text, int start, int end); static char *create_command_generator(const char *text, int state); static char *complete_from_query(const char *text, int state); *************** *** 470,476 **** --- 523,533 ---- static char *_complete_from_query(int is_schema_query, const char *text, int state); static char *complete_from_const(const char *text, int state); + static char *complete_from_list(const char *text, int state); + static char *complete_from_malloced_list(const char *text, int state); + static char *_complete_from_list(bool is_list_malloced, const char *text, + int state); static PGresult *exec_query(const char *query); *************** *** 754,760 **** else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && (pg_strcasecmp(prev_wd, "ALTER") == 0 || pg_strcasecmp(prev_wd, "RENAME") == 0)) ! COMPLETE_WITH_ATTR(prev2_wd); /* ALTER TABLE xxx RENAME yyy */ else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && --- 811,827 ---- else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && (pg_strcasecmp(prev_wd, "ALTER") == 0 || pg_strcasecmp(prev_wd, "RENAME") == 0)) ! { ! char **list = GET_MALLOCED_LIST_WITH_ATTR(prev2_wd); ! MALLOCED_LIST_ADD_ITEM(list, "COLUMN"); ! COMPLETE_WITH_MALLOCED_LIST(list); ! } ! /* If we have TABLE ALTER COLUMN|RENAME COLUMN, provide list of columns */ ! else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && ! pg_strcasecmp(prev_wd, "COLUMN") == 0 && ! (pg_strcasecmp(prev2_wd, "ALTER") == 0 || ! pg_strcasecmp(prev2_wd, "RENAME") == 0)) ! COMPLETE_WITH_ATTR(prev3_wd); /* ALTER TABLE xxx RENAME yyy */ else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 && *************** *** 762,767 **** --- 829,841 ---- pg_strcasecmp(prev_wd, "TO") != 0) COMPLETE_WITH_CONST("TO"); + /* ALTER TABLE xxx RENAME COLUMN yyy */ + else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 && + pg_strcasecmp(prev3_wd, "RENAME") == 0 && + pg_strcasecmp(prev2_wd, "COLUMN") == 0 && + pg_strcasecmp(prev_wd, "TO") != 0) + COMPLETE_WITH_CONST("TO"); + /* If we have TABLE DROP, provide COLUMN or CONSTRAINT */ else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 && pg_strcasecmp(prev_wd, "DROP") == 0) *************** *** 1454,1461 **** else if (pg_strcasecmp(prev_wd, "LOCK") == 0 || (pg_strcasecmp(prev_wd, "TABLE") == 0 && pg_strcasecmp(prev2_wd, "LOCK") == 0)) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); ! /* For the following, handle the case of a single table only for now */ /* Complete LOCK [TABLE] with "IN" */ --- 1528,1541 ---- else if (pg_strcasecmp(prev_wd, "LOCK") == 0 || (pg_strcasecmp(prev_wd, "TABLE") == 0 && pg_strcasecmp(prev2_wd, "LOCK") == 0)) ! { ! char **list = GET_MALLOCED_LIST_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); ! /* if we have only seen LOCK but not LOCK TABLE so far, offer ! * the TABLE keyword as well */ ! if (pg_strcasecmp(prev_wd, "LOCK") == 0) ! MALLOCED_LIST_ADD_ITEM(list, "TABLE"); ! COMPLETE_WITH_MALLOCED_LIST(list); ! } /* For the following, handle the case of a single table only for now */ /* Complete LOCK [TABLE]
with "IN" */ *************** *** 1638,1644 **** else if (pg_strcasecmp(prev3_wd, "SET") == 0 && pg_strcasecmp(prev2_wd, "SESSION") == 0 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0) ! COMPLETE_WITH_QUERY(Query_for_list_of_roles); /* Complete RESET SESSION with AUTHORIZATION */ else if (pg_strcasecmp(prev2_wd, "RESET") == 0 && pg_strcasecmp(prev_wd, "SESSION") == 0) --- 1718,1728 ---- else if (pg_strcasecmp(prev3_wd, "SET") == 0 && pg_strcasecmp(prev2_wd, "SESSION") == 0 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0) ! { ! char **list = GET_MALLOCED_LIST_WITH_QUERY(Query_for_list_of_roles); ! MALLOCED_LIST_ADD_ITEM(list, "DEFAULT"); ! COMPLETE_WITH_MALLOCED_LIST(list); ! } /* Complete RESET SESSION with AUTHORIZATION */ else if (pg_strcasecmp(prev2_wd, "RESET") == 0 && pg_strcasecmp(prev_wd, "SESSION") == 0) *************** *** 2128,2133 **** --- 2219,2238 ---- static char * complete_from_list(const char *text, int state) { + return _complete_from_list(false, text, state); + } + + static char * + complete_from_malloced_list(const char *text, int state) + { + return _complete_from_list(true, text, state); + } + + /* this function does the actual work and is called by the two functions + * above */ + static char * + _complete_from_list(bool is_list_malloced, const char *text, int state) + { static int string_length, list_index, matches; *************** *** 2135,2141 **** const char *item; /* need to have a list */ ! psql_assert(completion_charpp); /* Initialization */ if (state == 0) --- 2240,2249 ---- const char *item; /* need to have a list */ ! if (is_list_malloced) ! psql_assert(completion_malloced_charpp); ! else ! psql_assert(completion_charpp); /* Initialization */ if (state == 0) *************** *** 2146,2153 **** matches = 0; } ! while ((item = completion_charpp[list_index++])) { /* First pass is case sensitive */ if (casesensitive && strncmp(text, item, string_length) == 0) { --- 2254,2267 ---- matches = 0; } ! while (1) { + if (is_list_malloced) + item = completion_malloced_charpp[list_index++]; + else + item = completion_charpp[list_index++]; + if (!item) + break; /* First pass is case sensitive */ if (casesensitive && strncmp(text, item, string_length) == 0) { *************** *** 2169,2182 **** casesensitive = false; list_index = 0; state++; ! return complete_from_list(text, state); } /* If no more matches, return null. */ return NULL; } - /* This function returns one fixed string the first time even if it doesn't match what's there, and nothing the second time. This should be used if there is only one possibility that can appear at a certain spot, so misspellings --- 2283,2295 ---- casesensitive = false; list_index = 0; state++; ! return _complete_from_list(is_list_malloced, text, state); } /* If no more matches, return null. */ return NULL; } /* This function returns one fixed string the first time even if it doesn't match what's there, and nothing the second time. This should be used if there is only one possibility that can appear at a certain spot, so misspellings *************** *** 2315,2320 **** --- 2428,2498 ---- } + /* LIST HELPER FUNCTIONS */ + + static char ** + get_empty_list(void) + { + char **list = (char **) malloc(sizeof(char *)); + list[0] = NULL; + return list; + } + + /* the following two functions are wrappers for _get_query_list */ + static char ** + get_schema_query_list(const char *text, + const SchemaQuery *squery, + const char *addon) + { + completion_squery = squery; + return _get_query_list(1, text, addon, NULL); + } + + static char ** + get_query_list(const char *text, + const char *query, + const char *completion_info) + { + return _get_query_list(0, text, query, completion_info); + } + + static char ** + _get_query_list(int is_schema_query, + const char *text, + const char *query, + const char *completion_info) + { + char **list = get_empty_list(); + char *entry; + int state = 0; + + completion_charp = query; + completion_info_charp = completion_info; + + do { + if (is_schema_query) + entry = complete_from_schema_query(text, state++); + else + entry = complete_from_query(text, state++); + list = list_add_item(list, entry); + } while (entry); + + return list; + } + + static char ** + list_add_item(char **list, char *item) + { + int size = 0; + while (list[size]) + size++; + list = realloc(list, sizeof(char *) * (size + 1 + 1)); + list[size] = item; + list[size+1] = NULL; + return list; + } + + #if 0 /*