On Fri, Feb 03, 2006 at 01:59:19PM -0500, Bruce Momjian wrote:
> I will adjust this patch based on later feedback emails.
I have another version of the patch. Minor style errors are corrected in it.
As far as I can see, open items are:
- Should all the
const char* foocompletion = { "BAR", "BAZ" };
be changed to
char* foocompletion = { "BAR", "BAZ" };
(including all functions that deal with that and take const char*'s now)
or should a cast be used only for the growable-list-case.
- is the simple list_add_item() algorithm sufficient for the psql use case
or not?
I append the version of the patch that I think is the latest I have.
Joachim
diff -ur 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 2005-12-23 16:58:19.000000000
+0100
+++ cvs.build/pgsql/src/bin/psql/tab-complete.c 2006-01-08 13:06:15.000000000
+0100
@@ -137,6 +137,7 @@
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)
@@ -150,6 +151,21 @@
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 { COMPLETE_WITH_LIST((const char **) list); free(list); list = 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,6 +479,16 @@
/* 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);
@@ -754,7 +780,17 @@
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);
+ {
+ char **list = GET_MALLOCED_LIST_WITH_ATTR(prev2_wd);
+ MALLOCED_LIST_ADD_ITEM(list, "COLUMN");
+ COMPLETE_WITH_MALLOCED_LIST(list);
+ }
+ /* If we have TABLE <sth> 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,6 +798,13 @@
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 <sth> DROP, provide COLUMN or CONSTRAINT */
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
pg_strcasecmp(prev_wd, "DROP") == 0)
@@ -1454,8 +1497,14 @@
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);
-
+ {
+ 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] <table> with "IN" */
@@ -1638,7 +1687,11 @@
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);
+ {
+ 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)
@@ -2315,6 +2368,71 @@
}
+/* 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
/*
---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to [EMAIL PROTECTED] so that your
message can get through to the mailing list cleanly