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

Reply via email to