--- mysql-6.0-orig/client/mysql.cc 2008-01-10 20:35:49.000000000 +0100 +++ mysql-6.0/client/mysql.cc 2008-01-22 17:17:56.000000000 +0100 @@ -186,6 +186,13 @@ static char *shared_memory_base_name=0; #endif static uint opt_protocol=0; +#ifdef HAVE_READLINE +/* maximum tables we'll allow for table context completion */ +#define MAX_TC_TABLE_CNT 20 +static uint tc_count=0; +static char *tc_tableList[MAX_TC_TABLE_CNT]; +#endif + static CHARSET_INFO *charset_info= &my_charset_latin1; #include "sslopt-vars.h" @@ -336,6 +343,10 @@ extern "C" int read_history(const char *command); extern "C" int write_history(const char *command); extern "C" HIST_ENTRY *history_get(int num); +static char* tc_add_prefix(const char *original, const char* prefix); +static int tc_maybe_change_context(const char *token); +static char *tc_frob_tablename(const char *t_name); +static int tc_get_table_context(const char *data, char** t_array); extern "C" int history_length; static int not_in_history(const char *line); static void initialize_readline (char *name); @@ -1659,6 +1670,7 @@ static void initialize_readline (char *name) { + /* Allow conditional parsing of the ~/.inputrc file. */ rl_readline_name = name; @@ -1672,6 +1684,7 @@ #endif rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion; rl_completion_entry_function= &no_completion; + #else rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion; rl_completion_entry_function= &no_completion; @@ -1689,12 +1702,22 @@ int start __attribute__((unused)), int end __attribute__((unused))) { + uint i; + if (!status.batch && !quick) + { + /* clear old table context if we have it */ + for (i=0; i0) + if (textlen>0 || tc_count>0) { /* lookup in the hash */ if (!state) { uint len; - b = find_all_matches(&ht,text,(uint) strlen(text),&len); - if (!b) + /* use table context if we have it, and there isn't one specified in text */ + if (tc_count && !strstr(text, ".")) + { + for (i=0; ipData; + e= b[0]->pData; } if (e) { + /* possibly strip the table context prefix */ + if (tc_count && (p= strchr(e->str, '.'))) + ptr= strdup(++p); + else ptr= strdup(e->str); - e = e->pNext; + + e= e->pNext; + + /* if we have context, be sure to check each context's bucket entry */ + if (!e && (bi < (b_cnt-1))) + e= b[++bi]->pData; + return ptr; } + } else { /* traverse the entire hash, ugly but works */ if (!state) { + /* find the first used bucket */ for (i=0 ; i < ht.nTableSize ; i++) { if (ht.arBuckets[i]) { - b = ht.arBuckets[i]; - e = b->pData; + b[0] = ht.arBuckets[i]; + e = b[0]->pData; + b_cnt=1; break; } } @@ -1748,27 +1815,27 @@ ptr= NullS; while (e && !ptr) { /* find valid entry in bucket */ - if ((uint) strlen(e->str) == b->nKeyLength) + if ((uint) strlen(e->str) == b[0]->nKeyLength) ptr = strdup(e->str); /* find the next used entry */ e = e->pNext; if (!e) { /* find the next used bucket */ - b = b->pNext; - if (!b) + b[0] = b[0]->pNext; + if (!b[0]) { for (i++ ; ipData; + b[0] = ht.arBuckets[i]; + e = b[0]->pData; break; } } } else - e = b->pData; + e = b[0]->pData; } } if (ptr) @@ -1777,9 +1844,139 @@ return NullS; } +/* table context routines for completion */ +#define TC_KEY_PAIR_COUNT 3 -/* Build up the completion hash */ +const char *tc_table_key_pairs[TC_KEY_PAIR_COUNT][2] = { { "FROM", "WHERE" }, + { "UPDATE", "SET" }, + { "INTO", "SET" } + }; + + +/* prefix original with the table prefix in prefix. always allocates a new + string */ +static char* tc_add_prefix(const char *original, const char* prefix) +{ + + char *tc_text; + + if (!original && !prefix) + return NULL; + + if (prefix) + { + tc_text = (char*)my_malloc((uint) strlen(prefix)+ + (uint) strlen(original)+1, + MYF(MY_WME)); + strcpy(tc_text, prefix); + if (original) + strcat(tc_text,original); + } + else + tc_text = strdup(original); + + return tc_text; + +} + +/* run through key_pairs and see if this token causes us to change context + 0 = no change + 1 = entering table context + 2 = leaving table context +*/ +static int tc_maybe_change_context(const char *token) +{ + int i; + for (i=0; i