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/*----------------------------------------------------------------------
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 */
128129static const char * const * completion_charpp ; /* to pass a list of strings */
129130static const char * completion_info_charp ; /* to pass a second string */
131+ static const char * completion_info_charp2 ; /* to pass a third string */
130132static 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