Hello,
A big part of my job is creating simple select statements with a few joins
in them. Unfortunately, the existing autocomplete functionality of pgadmin
was a bit too limited for my use case. A relatively simple query like:
select * from person p join company c on p.company_id = c.id where p.name =
'John' would be enough to completely throw the autocompletion off.
So I started working on a patch to improve the autocompletion a bit and the
result is attached. It doesn't have all the features I would like it to
have (no support for table aliases, for example) but it is already a big
improvement for my use case.
Please comment if I need to change anything to get this patch into pgadmin.
This patch is against pgadmin3-1.14.0.tar.gz
Regards,
Wander Winkelhorst.
diff -U2 -a -r ./old/pgadmin/utils/tab-complete.inc ./new//pgadmin/utils/tab-complete.inc
--- ./old/pgadmin/utils/tab-complete.inc 2011-06-20 21:13:22.000000000 +0200
+++ ./new//pgadmin/utils/tab-complete.inc 2011-10-31 14:41:51.022693279 +0100
@@ -229,4 +229,14 @@
" AND pg_catalog.pg_table_is_visible(c.oid)"
+#define Query_for_list_of_attributes_list \
+"SELECT pg_catalog.quote_ident(attname) "\
+" FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
+" WHERE c.oid = a.attrelid "\
+" AND a.attnum > 0 "\
+" AND NOT a.attisdropped "\
+" AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
+" AND pg_catalog.pg_table_is_visible(c.oid)"\
+" AND pg_catalog.quote_ident(relname) in ("
+
#define Query_for_list_of_databases \
"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
@@ -361,4 +371,22 @@
};
+/*
+A function to get all attributes of a list of tables
+Used for autocompletion.
+*/
+static char * complete_with_attr_for_list(char *tablelist, char *text, void *dbptr)
+{
+ char* attrquery;
+ char* result;
+
+ attrquery = malloc(strlen(Query_for_list_of_attributes_list) + strlen(tablelist) + 1);
+ strcpy(attrquery, Query_for_list_of_attributes_list);
+ strcat(attrquery, tablelist);
+ result = complete_from_query(text, attrquery, NULL, dbptr);
+
+ free(attrquery);
+
+ return result;
+}
/* The completion function. Acc. to readline spec this gets passed the text
@@ -401,4 +429,59 @@
(void) end; /* not used */
+ char *buffer;
+ char *tablelist;
+ char *scratch;
+
+ buffer = malloc(strlen(rl_line_buffer));
+ tablelist = malloc(strlen(rl_line_buffer) + 20); //+20 is for extra chars like quotes and comma's
+ strcpy (tablelist,"");
+ strcpy(buffer, rl_line_buffer);
+ #define START 1
+ #define TABLE 2
+ #define TABLEALIAS 3
+ int grammarState = START;
+ char *p = strtok(buffer, " ");
+ while (p) {
+ if (grammarState == TABLE) {
+ //Add tablename to list of tables
+ strcat(tablelist,"'");
+ scratch = malloc(strlen(p) * 2 + 1);
+ PQescapeString(scratch, p, strlen(p));
+ strcat(tablelist, scratch);
+ free(scratch);
+ strcat(tablelist,"', ");
+
+ if (pg_strcasecmp(p, "JOIN") == 0) {
+ grammarState = TABLE;
+ } else if (pg_strcasecmp(p, "WHERE") == 0) {
+ grammarState = START;
+ } else {
+ //Must be alias :)
+ grammarState = TABLEALIAS;
+ }
+ } else if (grammarState == TABLEALIAS) {
+ if (pg_strcasecmp(p, "JOIN") == 0) {
+ grammarState = TABLE;
+ } else if (pg_strcasecmp(p, "WHERE") == 0) {
+ grammarState = START;
+ } else {
+ //Must be alias :)
+ grammarState = TABLEALIAS;
+ }
+ } else {
+ if (pg_strcasecmp(p, "FROM") == 0) {
+ grammarState = TABLE;
+ } else if (pg_strcasecmp(p, "JOIN") == 0) {
+ grammarState = TABLE;
+ }
+ }
+
+ p = strtok(NULL, " ");
+ }
+
+ free(buffer);
+
+ strcat(tablelist,"' ')"); //Add dummy to mark end-of-list
+
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
rl_completion_append_character = ' ';
@@ -1356,5 +1439,5 @@
pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
pg_strcasecmp(prev_wd, "BY") == 0)
- COMPLETE_WITH_ATTR(prev3_wd);
+ matches = complete_with_attr_for_list(tablelist, text, dbptr);
/* PREPARE xx AS */
@@ -1621,5 +1704,5 @@
/* Simple case of the word before the where being the table name */
else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
- COMPLETE_WITH_ATTR(prev2_wd);
+ matches = complete_with_attr_for_list(tablelist, text, dbptr);
/* ... FROM ... */
@@ -1630,4 +1713,21 @@
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
+/* ... JOIN ... */
+ else if (pg_strcasecmp(prev_wd, "JOIN") == 0 &&
+ pg_strcasecmp(prev3_wd, "COPY") != 0 &&
+ pg_strcasecmp(prev3_wd, "\\copy") != 0)
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
+
+/* ... ON ... */
+ else if (pg_strcasecmp(prev_wd, "ON") == 0)
+ matches = complete_with_attr_for_list(tablelist, text, dbptr);
+
+/* ... = ... */
+ else if (pg_strcasecmp(prev_wd, "=") == 0)
+ matches = complete_with_attr_for_list(tablelist, text, dbptr);
+
+/* ... AND ... */
+ else if (pg_strcasecmp(prev_wd, "AND") == 0)
+ matches = complete_with_attr_for_list(tablelist, text, dbptr);
/* Backslash commands */
@@ -1731,4 +1831,5 @@
free(prev4_wd);
free(prev5_wd);
+ free(tablelist);
/* Return our Grand List O' Matches */
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers