Thanks to visit codestin.com
Credit goes to github.com

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

Lines changed: 102 additions & 26 deletions
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)