Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5787d50

Browse files
committed
Improve psql's tab completion to handle completing attribute names in cases
where the relation name was schema-qualified, for example UPDATE foo.bar SET <tab> Also support cases where the relation name was quoted unnecessarily, for example UPDATE "foo" SET <tab> Greg Sabino Mullane, slightly simplified by myself.
1 parent 6fc9d42 commit 5787d50

File tree

1 file changed

+102
-26
lines changed

1 file changed

+102
-26
lines changed

src/bin/psql/tab-complete.c

+102-26
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.169 2008/01/01 19:45:56 momjian Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.170 2008/03/29 19:19:14 tgl Exp $
77
*/
88

99
/*----------------------------------------------------------------------
@@ -53,6 +53,7 @@
5353
#include "pqexpbuffer.h"
5454
#include "common.h"
5555
#include "settings.h"
56+
#include "stringutils.h"
5657

5758
#ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
5859
#define filename_completion_function rl_filename_completion_function
@@ -124,29 +125,70 @@ static int completion_max_records;
124125
* Communication variables set by COMPLETE_WITH_FOO macros and then used by
125126
* the completion callback functions. Ugly but there is no better way.
126127
*/
127-
static const char *completion_charp; /* to pass a string */
128+
static const char *completion_charp; /* to pass a string */
128129
static const char *const * completion_charpp; /* to pass a list of strings */
129130
static const char *completion_info_charp; /* to pass a second string */
131+
static const char *completion_info_charp2; /* to pass a third string */
130132
static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
131133

132-
/* A couple of macros to ease typing. You can use these to complete the given
133-
string with
134-
1) The results from a query you pass it. (Perhaps one of those below?)
135-
2) The results from a schema query you pass it.
136-
3) The items from a null-pointer-terminated list.
137-
4) A string constant
138-
5) The list of attributes to the given table.
139-
*/
134+
/*
135+
* A few macros to ease typing. You can use these to complete the given
136+
* string with
137+
* 1) The results from a query you pass it. (Perhaps one of those below?)
138+
* 2) The results from a schema query you pass it.
139+
* 3) The items from a null-pointer-terminated list.
140+
* 4) A string constant.
141+
* 5) The list of attributes of the given table (possibly schema-qualified).
142+
*/
140143
#define COMPLETE_WITH_QUERY(query) \
141-
do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
144+
do { \
145+
completion_charp = query; \
146+
matches = completion_matches(text, complete_from_query); \
147+
} while (0)
148+
142149
#define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
143-
do { completion_squery = &(query); completion_charp = addon; matches = completion_matches(text, complete_from_schema_query); } while(0)
150+
do { \
151+
completion_squery = &(query); \
152+
completion_charp = addon; \
153+
matches = completion_matches(text, complete_from_schema_query); \
154+
} while (0)
155+
144156
#define COMPLETE_WITH_LIST(list) \
145-
do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
157+
do { \
158+
completion_charpp = list; \
159+
matches = completion_matches(text, complete_from_list); \
160+
} while (0)
161+
146162
#define COMPLETE_WITH_CONST(string) \
147-
do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
148-
#define COMPLETE_WITH_ATTR(table, addon) \
149-
do {completion_charp = Query_for_list_of_attributes addon; completion_info_charp = table; matches = completion_matches(text, complete_from_query); } while(0)
163+
do { \
164+
completion_charp = string; \
165+
matches = completion_matches(text, complete_from_const); \
166+
} while (0)
167+
168+
#define COMPLETE_WITH_ATTR(relation, addon) \
169+
do { \
170+
char *_completion_schema; \
171+
char *_completion_table; \
172+
\
173+
_completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
174+
false, false, pset.encoding); \
175+
(void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
176+
false, false, pset.encoding); \
177+
_completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
178+
false, false, pset.encoding); \
179+
if (_completion_table == NULL) \
180+
{ \
181+
completion_charp = Query_for_list_of_attributes addon; \
182+
completion_info_charp = relation; \
183+
} \
184+
else \
185+
{ \
186+
completion_charp = Query_for_list_of_attributes_with_schema addon; \
187+
completion_info_charp = _completion_table; \
188+
completion_info_charp2 = _completion_schema; \
189+
} \
190+
matches = completion_matches(text, complete_from_query); \
191+
} while (0)
150192

151193
/*
152194
* Assembly instructions for schema queries
@@ -308,11 +350,12 @@ static const SchemaQuery Query_for_list_of_views = {
308350
/*
309351
* Queries to get lists of names of various kinds of things, possibly
310352
* restricted to names matching a partially entered name. In these queries,
311-
* %s will be replaced by the text entered so far (suitably escaped to
312-
* become a SQL literal string). %d will be replaced by the length of the
313-
* string (in unescaped form). A second %s, if present, will be replaced
314-
* by a suitably-escaped version of the string provided in
315-
* completion_info_charp.
353+
* the first %s will be replaced by the text entered so far (suitably escaped
354+
* to become a SQL literal string). %d will be replaced by the length of the
355+
* string (in unescaped form). A second and third %s, if present, will be
356+
* replaced by a suitably-escaped version of the string provided in
357+
* completion_info_charp. A fourth and fifth %s are similarly replaced by
358+
* completion_info_charp2.
316359
*
317360
* Beware that the allowed sequences of %s and %d are determined by
318361
* _complete_from_query().
@@ -325,9 +368,23 @@ static const SchemaQuery Query_for_list_of_views = {
325368
" AND a.attnum > 0 "\
326369
" AND NOT a.attisdropped "\
327370
" AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
328-
" AND pg_catalog.quote_ident(relname)='%s' "\
371+
" AND (pg_catalog.quote_ident(relname)='%s' "\
372+
" OR '\"' || relname || '\"'='%s') "\
329373
" AND pg_catalog.pg_table_is_visible(c.oid)"
330374

375+
#define Query_for_list_of_attributes_with_schema \
376+
"SELECT pg_catalog.quote_ident(attname) "\
377+
" FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
378+
" WHERE c.oid = a.attrelid "\
379+
" AND n.oid = c.relnamespace "\
380+
" AND a.attnum > 0 "\
381+
" AND NOT a.attisdropped "\
382+
" AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
383+
" AND (pg_catalog.quote_ident(relname)='%s' "\
384+
" OR '\"' || relname || '\"' ='%s') "\
385+
" AND (pg_catalog.quote_ident(nspname)='%s' "\
386+
" OR '\"' || nspname || '\"' ='%s') "
387+
331388
#define Query_for_list_of_template_databases \
332389
"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
333390
" WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' and datistemplate IS TRUE"
@@ -584,9 +641,10 @@ psql_completion(char *text, int start, int end)
584641
completion_charp = NULL;
585642
completion_charpp = NULL;
586643
completion_info_charp = NULL;
644+
completion_info_charp2 = NULL;
587645

588646
/*
589-
* Scan the input line before our current position for the last four
647+
* Scan the input line before our current position for the last five
590648
* words. According to those we'll make some smart decisions on what the
591649
* user is probably intending to type. TODO: Use strtokx() to do this.
592650
*/
@@ -2225,8 +2283,9 @@ complete_from_schema_query(const char *text, int state)
22252283
The query can be one of two kinds:
22262284
- A simple query which must contain a %d and a %s, which will be replaced
22272285
by the string length of the text and the text itself. The query may also
2228-
have another %s in it, which will be replaced by the value of
2229-
completion_info_charp.
2286+
have up to four more %s in it; the first two such will be replaced by the
2287+
value of completion_info_charp, the next two by the value of
2288+
completion_info_charp2.
22302289
or:
22312290
- A schema query used for completion of both schema and relation names;
22322291
these are more complex and must contain in the following order:
@@ -2255,6 +2314,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
22552314
PQExpBufferData query_buffer;
22562315
char *e_text;
22572316
char *e_info_charp;
2317+
char *e_info_charp2;
22582318

22592319
list_index = 0;
22602320
string_length = strlen(text);
@@ -2279,6 +2339,18 @@ _complete_from_query(int is_schema_query, const char *text, int state)
22792339
else
22802340
e_info_charp = NULL;
22812341

2342+
if (completion_info_charp2)
2343+
{
2344+
size_t charp_len;
2345+
2346+
charp_len = strlen(completion_info_charp2);
2347+
e_info_charp2 = pg_malloc(charp_len * 2 + 1);
2348+
PQescapeString(e_info_charp2, completion_info_charp2,
2349+
charp_len);
2350+
}
2351+
else
2352+
e_info_charp2 = NULL;
2353+
22822354
initPQExpBuffer(&query_buffer);
22832355

22842356
if (is_schema_query)
@@ -2374,7 +2446,9 @@ _complete_from_query(int is_schema_query, const char *text, int state)
23742446
{
23752447
/* completion_charp is an sprintf-style format string */
23762448
appendPQExpBuffer(&query_buffer, completion_charp,
2377-
string_length, e_text, e_info_charp);
2449+
string_length, e_text,
2450+
e_info_charp, e_info_charp,
2451+
e_info_charp2, e_info_charp2);
23782452
}
23792453

23802454
/* Limit the number of records in the result */
@@ -2387,6 +2461,8 @@ _complete_from_query(int is_schema_query, const char *text, int state)
23872461
free(e_text);
23882462
if (e_info_charp)
23892463
free(e_info_charp);
2464+
if (e_info_charp2)
2465+
free(e_info_charp2);
23902466
}
23912467

23922468
/* Find something that matches */

0 commit comments

Comments
 (0)