]> granicus.if.org Git - postgresql/blob - src/bin/psql/tab-complete.c
Remove automatic '()' in other branch of UNION as well.
[postgresql] / src / bin / psql / tab-complete.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2003, PostgreSQL Global Development Group
5  *
6  * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.89 2003/10/17 11:52:06 petere Exp $
7  */
8
9 /*----------------------------------------------------------------------
10  * This file implements a somewhat more sophisticated readline "TAB
11  * completion" in psql. It is not intended to be AI, to replace
12  * learning SQL, or to relieve you from thinking about what you're
13  * doing. Also it does not always give you all the syntactically legal
14  * completions, only those that are the most common or the ones that
15  * the programmer felt most like implementing.
16  *
17  * CAVEAT: Tab completion causes queries to be sent to the backend.
18  * The number of tuples returned gets limited, in most default
19  * installations to 1000, but if you still don't like this prospect,
20  * you can turn off tab completion in your ~/.inputrc (or else
21  * ${INPUTRC}) file so:
22  *
23  *       $if psql
24  *       set disable-completion on
25  *       $endif
26  *
27  * See `man 3 readline' or `info readline' for the full details. Also,
28  * hence the
29  *
30  * BUGS:
31  *
32  * - If you split your queries across lines, this whole thing gets
33  *       confused. (To fix this, one would have to read psql's query
34  *       buffer rather than readline's line buffer, which would require
35  *       some major revisions of things.)
36  *
37  * - Table or attribute names with spaces in it may confuse it.
38  *
39  * - Quotes, parenthesis, and other funny characters are not handled
40  *       all that gracefully.
41  *----------------------------------------------------------------------
42  */
43
44 #include "postgres_fe.h"
45 #include "tab-complete.h"
46
47 #include "input.h"
48
49 /* If we don't have this, we might as well forget about the whole thing: */
50 #ifdef USE_READLINE
51
52 #include <ctype.h>
53 #ifdef USE_ASSERT_CHECKING
54 #include <assert.h>
55 #endif
56
57 #include "libpq-fe.h"
58
59 #include "common.h"
60 #include "settings.h"
61
62 #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
63 #define filename_completion_function rl_filename_completion_function
64 #else
65 /* missing in some header files */
66 extern char *filename_completion_function();
67 #endif
68
69 #ifdef HAVE_RL_COMPLETION_MATCHES
70 #define completion_matches rl_completion_matches
71 #endif
72
73 #define BUF_SIZE 2048
74 #define ERROR_QUERY_TOO_LONG    /* empty */
75
76
77 /* Forward declaration of functions */
78 static char **psql_completion(char *text, int start, int end);
79 static char *create_command_generator(const char *text, int state);
80 static char *complete_from_query(const char *text, int state);
81 static char *complete_from_schema_query(const char *text, int state);
82 static char *_complete_from_query(int is_schema_query,
83                                          const char *text, int state);
84 static char *complete_from_const(const char *text, int state);
85 static char *complete_from_list(const char *text, int state);
86
87 static PGresult *exec_query(char *query);
88
89 static char *previous_word(int point, int skip);
90
91 #if 0
92 static char *quote_file_name(char *text, int match_type, char *quote_pointer);
93 static char *dequote_file_name(char *text, char quote_char);
94 #endif
95
96 /* These variables are used to pass information into the completion functions.
97    Realizing that this is the cardinal sin of programming, I don't see a better
98    way. */
99 static char     *completion_charp;              /* if you need to pass a string */
100 static char     **completion_charpp;    /* if you need to pass a list of strings */
101 static char *completion_info_charp;             /* if you need to pass another
102                                                                                  * string */
103
104 /* Store how many records from a database query we want to return at most
105 (implemented via SELECT ... LIMIT xx). */
106 static int      completion_max_records;
107
108
109 /* Initialize the readline library for our purposes. */
110 void
111 initialize_readline(void)
112 {
113         rl_readline_name = pset.progname;
114         rl_attempted_completion_function = (void *) psql_completion;
115
116         rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
117
118         completion_max_records = 1000;
119
120         /*
121          * There is a variable rl_completion_query_items for this but
122          * apparently it's not defined everywhere.
123          */
124 }
125
126
127 /*
128  * Queries to get lists of names of various kinds of things, possibly
129  * restricted to names matching a partially entered name.  In these queries,
130  * %s will be replaced by the text entered so far (suitably escaped to
131  * become a SQL literal string).  %d will be replaced by the length of the
132  * string (in unescaped form).  Beware that the allowed sequences of %s and
133  * %d are determined by _complete_from_query().
134  */
135
136 #define Query_for_list_of_aggregates \
137 " SELECT pg_catalog.quote_ident(proname) " \
138 "   FROM pg_catalog.pg_proc p" \
139 "  WHERE proisagg " \
140 "    AND substring(pg_catalog.quote_ident(proname),1,%d)='%s'" \
141 "    AND pg_catalog.pg_function_is_visible(p.oid) "\
142 "        UNION" \
143 " SELECT pg_catalog.quote_ident(nspname) || '.'" \
144 "   FROM pg_catalog.pg_namespace" \
145 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s'" \
146 "        UNION" \
147 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname)" \
148 "   FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n" \
149 "  WHERE proisagg  " \
150 "    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname),1,%d)='%s'" \
151 "    AND pronamespace = n.oid" \
152 "    AND ('%s' ~ '\\\\.' "\
153 "     OR (SELECT TRUE "\
154 "           FROM pg_catalog.pg_namespace "\
155 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
156 "         HAVING COUNT(nspname)=1))"
157
158 #define Query_for_list_of_attributes \
159 "SELECT pg_catalog.quote_ident(attname) "\
160 "  FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
161 " WHERE c.oid = a.attrelid "\
162 "   AND a.attnum > 0 "\
163 "   AND NOT a.attisdropped "\
164 "   AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
165 "   AND pg_catalog.quote_ident(relname)='%s' "\
166 "   AND pg_catalog.pg_table_is_visible(c.oid)"
167
168 #define Query_for_list_of_databases \
169 "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
170 " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
171
172 #define Query_for_list_of_datatypes \
173 " SELECT pg_catalog.format_type(t.oid, NULL) "\
174 "   FROM pg_catalog.pg_type t "\
175 "  WHERE (t.typrelid = 0 "\
176 "     OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "\
177 "    AND t.typname !~ '^_' "\
178 "    AND substring(pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
179 "    AND pg_catalog.pg_type_is_visible(t.oid) "\
180 "        UNION "\
181 " SELECT pg_catalog.quote_ident(nspname) || '.'"\
182 "   FROM pg_catalog.pg_namespace "\
183 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
184 "        UNION "\
185 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.format_type(t.oid, NULL)"\
186 "   FROM pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
187 "  WHERE(t.typrelid = 0 "\
188 "     OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "\
189 "    AND t.typname !~ '^_' "\
190 "    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.format_type(t.oid, NULL),1,%d)='%s' "\
191 "    AND typnamespace = n.oid "\
192 "    AND ('%s' ~ '\\\\.' "\
193 "     OR (SELECT TRUE "\
194 "           FROM pg_catalog.pg_namespace "\
195 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
196 "         HAVING COUNT(nspname)=1))"
197
198 #define Query_for_list_of_domains \
199 " SELECT pg_catalog.quote_ident(typname) "\
200 "   FROM pg_catalog.pg_type t "\
201 "  WHERE typtype = 'd' "\
202 "    AND substring(pg_catalog.quote_ident(typname),1,%d)='%s' "\
203 "    AND pg_catalog.pg_type_is_visible(t.oid) "\
204 "        UNION" \
205 " SELECT pg_catalog.quote_ident(nspname) || '.'"\
206 "   FROM pg_catalog.pg_namespace "\
207 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
208 "        UNION "\
209 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(typname)"\
210 "   FROM pg_catalog.pg_type t, pg_catalog.pg_namespace n "\
211 "  WHERE typtype = 'd' "\
212 "    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(typname),1,%d)='%s' "\
213 "    AND typnamespace = n.oid "\
214 "    AND ('%s' ~ '\\\\.' "\
215 "     OR (SELECT TRUE "\
216 "           FROM pg_catalog.pg_namespace "\
217 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
218 "         HAVING COUNT(nspname)=1))"
219
220 #define Query_for_list_of_encodings \
221 " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
222 "   FROM pg_catalog.pg_conversion "\
223 "  WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
224
225 #define Query_for_list_of_functions \
226 " SELECT pg_catalog.quote_ident(proname) "\
227 "   FROM pg_catalog.pg_proc p "\
228 "  WHERE substring(pg_catalog.quote_ident(proname),1,%d)='%s'"\
229 "    AND pg_catalog.pg_function_is_visible(p.oid) "\
230 "        UNION "\
231 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
232 "   FROM pg_catalog.pg_namespace "\
233 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
234 "        UNION "\
235 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname) "\
236 "   FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
237 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(proname),1,%d)='%s' "\
238 "    AND pronamespace = n.oid "\
239 "    AND ('%s' ~ '\\\\.' "\
240 "     OR (SELECT TRUE "\
241 "           FROM pg_catalog.pg_namespace "\
242 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
243 "         HAVING COUNT(nspname)=1))"
244
245 #define Query_for_list_of_indexes \
246 " SELECT pg_catalog.quote_ident(relname) "\
247 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
248 "  WHERE relkind='i' "\
249 "    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
250 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
251 "    AND relnamespace = n.oid "\
252 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
253 "        UNION "\
254 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
255 "   FROM pg_catalog.pg_namespace "\
256 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
257 "        UNION "\
258 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
259 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
260 "  WHERE relkind='i' "\
261 "    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
262 "    AND relnamespace = n.oid "\
263 "    AND ('%s' ~ '\\\\.' "\
264 "     OR (SELECT TRUE "\
265 "           FROM pg_catalog.pg_namespace "\
266 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
267 "         HAVING COUNT(nspname)=1))"
268
269
270 #define Query_for_list_of_languages \
271 "SELECT pg_catalog.quote_ident(lanname) "\
272 "  FROM pg_language "\
273 " WHERE lanname != 'internal' "\
274 "   AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s' "
275
276 #define Query_for_list_of_schemas \
277 "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
278 " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
279
280 #define Query_for_list_of_sequences \
281 " SELECT pg_catalog.quote_ident(relname) "\
282 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
283 "  WHERE relkind='S' "\
284 "    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
285 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
286 "    AND relnamespace = n.oid "\
287 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
288 "        UNION "\
289 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
290 "   FROM pg_catalog.pg_namespace "\
291 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
292 "        UNION "\
293 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
294 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
295 "  WHERE relkind='S' "\
296 "    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
297 "    AND relnamespace = n.oid "\
298 "    AND ('%s' ~ '\\\\.' "\
299 "     OR (SELECT TRUE "\
300 "           FROM pg_catalog.pg_namespace "\
301 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
302 "         HAVING COUNT(nspname)=1))"
303
304 #define Query_for_list_of_system_relations \
305 "SELECT pg_catalog.quote_ident(relname) "\
306 "  FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
307 " WHERE (c.relkind='r' OR c.relkind='v' OR c.relkind='s' OR c.relkind='S') "\
308 "   AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
309 "   AND pg_catalog.pg_table_is_visible(c.oid)"\
310 "   AND relnamespace = n.oid "\
311 "   AND n.nspname = 'pg_catalog'"
312
313 #define Query_for_list_of_tables \
314 " SELECT pg_catalog.quote_ident(relname) "\
315 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
316 "  WHERE relkind='r' "\
317 "    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
318 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
319 "    AND relnamespace = n.oid "\
320 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
321 "        UNION "\
322 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
323 "   FROM pg_catalog.pg_namespace "\
324 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
325 "        UNION "\
326 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
327 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
328 "  WHERE relkind='r' "\
329 "    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
330 "    AND relnamespace = n.oid "\
331 "    AND ('%s' ~ '\\\\.' "\
332 "     OR (SELECT TRUE "\
333 "           FROM pg_catalog.pg_namespace "\
334 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
335 "         HAVING COUNT(nspname)=1))"
336
337 #define Query_for_list_of_tisv \
338 " SELECT pg_catalog.quote_ident(relname) "\
339 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
340 "  WHERE (relkind='r' OR relkind='i' OR relkind='S' OR relkind='v') "\
341 "    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
342 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
343 "    AND relnamespace = n.oid "\
344 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
345 "        UNION "\
346 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
347 "   FROM pg_catalog.pg_namespace "\
348 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
349 "        UNION "\
350 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
351 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
352 "  WHERE (relkind='r' OR relkind='i' OR relkind='S' OR relkind='v') "\
353 "    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
354 "    AND relnamespace = n.oid "\
355 "    AND ('%s' ~ '\\\\.' "\
356 "     OR (SELECT TRUE "\
357 "           FROM pg_catalog.pg_namespace "\
358 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
359 "         HAVING COUNT(nspname)=1))"
360
361 #define Query_for_list_of_tsv \
362 " SELECT pg_catalog.quote_ident(relname) "\
363 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
364 "  WHERE (relkind='r' OR relkind='S' OR relkind='v') "\
365 "    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
366 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
367 "    AND relnamespace = n.oid "\
368 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
369 "        UNION "\
370 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
371 "   FROM pg_catalog.pg_namespace "\
372 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
373 "        UNION "\
374 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
375 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
376 "  WHERE (relkind='r' OR relkind='S' OR relkind='v') "\
377 "    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
378 "    AND relnamespace = n.oid "\
379 "    AND ('%s' ~ '\\\\.' "\
380 "     OR (SELECT TRUE "\
381 "           FROM pg_catalog.pg_namespace "\
382 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
383 "         HAVING COUNT(nspname)=1))"
384
385 #define Query_for_list_of_views \
386 " SELECT pg_catalog.quote_ident(relname) "\
387 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
388 "  WHERE relkind='v'"\
389 "    AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "\
390 "    AND pg_catalog.pg_table_is_visible(c.oid) "\
391 "    AND relnamespace = n.oid "\
392 "    AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "\
393 "        UNION "\
394 " SELECT pg_catalog.quote_ident(nspname) || '.' "\
395 "   FROM pg_catalog.pg_namespace "\
396 "  WHERE substring(pg_catalog.quote_ident(nspname) || '.',1,%d)='%s' "\
397 "        UNION "\
398 " SELECT pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname) "\
399 "   FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
400 "  WHERE relkind='v' "\
401 "    AND substring(pg_catalog.quote_ident(nspname) || '.' || pg_catalog.quote_ident(relname),1,%d)='%s' "\
402 "    AND relnamespace = n.oid "\
403 "    AND ('%s' ~ '\\\\.' "\
404 "     OR (SELECT TRUE "\
405 "           FROM pg_catalog.pg_namespace "\
406 "          WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s' "\
407 "         HAVING COUNT(nspname)=1))"
408
409 #define Query_for_list_of_users \
410 " SELECT pg_catalog.quote_ident(usename) "\
411 "   FROM pg_catalog.pg_user "\
412 "  WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
413
414 /* the silly-looking length condition is just to eat up the current word */
415 #define Query_for_table_owning_index \
416 "SELECT pg_catalog.quote_ident(c1.relname) "\
417 "  FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
418 " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
419 "       and (%d = length('%s'))"\
420 "       and pg_catalog.quote_ident(c2.relname)='%s'"\
421 "       and pg_catalog.pg_table_is_visible(c2.oid)"
422
423 /* This is a list of all "things" in Pgsql, which can show up after CREATE or
424    DROP; and there is also a query to get a list of them.
425 */
426
427 #define WITH_SCHEMA 1
428 #define NO_SCHEMA 0
429
430 typedef struct
431 {
432         char       *name;
433         int                     with_schema;
434         char       *query;
435 } pgsql_thing_t;
436
437 pgsql_thing_t words_after_create[] = {
438         {"AGGREGATE", WITH_SCHEMA, Query_for_list_of_aggregates},
439         {"CAST", NO_SCHEMA, NULL},      /* Casts have complex structures for
440                                                                  * namees, so skip it */
441         {"CONVERSION", NO_SCHEMA, "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
442         {"DATABASE", NO_SCHEMA, Query_for_list_of_databases},
443         {"DOMAIN", WITH_SCHEMA, Query_for_list_of_domains},
444         {"FUNCTION", WITH_SCHEMA, Query_for_list_of_functions},
445         {"GROUP", NO_SCHEMA, "SELECT pg_catalog.quote_ident(groname) FROM pg_catalog.pg_group WHERE substring(pg_catalog.quote_ident(groname),1,%d)='%s'"},
446         {"LANGUAGE", NO_SCHEMA, Query_for_list_of_languages},
447         {"INDEX", WITH_SCHEMA, Query_for_list_of_indexes},
448         {"OPERATOR", NO_SCHEMA, NULL},          /* Querying for this is probably
449                                                                                  * not such a good idea. */
450         {"RULE", NO_SCHEMA, "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
451         {"SCHEMA", NO_SCHEMA, Query_for_list_of_schemas},
452         {"SEQUENCE", WITH_SCHEMA, Query_for_list_of_sequences},
453         {"TABLE", WITH_SCHEMA, Query_for_list_of_tables},
454         {"TEMP", NO_SCHEMA, NULL},      /* for CREATE TEMP TABLE ... */
455         {"TRIGGER", NO_SCHEMA, "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
456         {"TYPE", WITH_SCHEMA, Query_for_list_of_datatypes},
457         {"UNIQUE", NO_SCHEMA, NULL},    /* for CREATE UNIQUE INDEX ... */
458         {"USER", NO_SCHEMA, Query_for_list_of_users},
459         {"VIEW", WITH_SCHEMA, Query_for_list_of_views},
460         {NULL, NO_SCHEMA, NULL}         /* end of list */
461 };
462
463
464 /* A couple of macros to ease typing. You can use these to complete the given
465    string with
466    1) The results from a query you pass it. (Perhaps one of those above?)
467    2) The results from a schema query you pass it.
468    3) The items from a null-pointer-terminated list.
469    4) A string constant
470    5) The list of attributes to the given table.
471 */
472 #define COMPLETE_WITH_QUERY(query) \
473 do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
474 #define COMPLETE_WITH_SCHEMA_QUERY(query) \
475 do { completion_charp = query; matches = completion_matches(text, complete_from_schema_query); } while(0)
476 #define COMPLETE_WITH_LIST(list) \
477 do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
478 #define COMPLETE_WITH_CONST(string) \
479 do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
480 #define COMPLETE_WITH_ATTR(table) \
481 do {completion_charp = Query_for_list_of_attributes; completion_info_charp = table; matches = completion_matches(text, complete_from_query); } while(0)
482
483
484 /* The completion function. Acc. to readline spec this gets passed the text
485    entered to far and its start and end in the readline buffer. The return value
486    is some partially obscure list format that can be generated by the readline
487    libraries completion_matches() function, so we don't have to worry about it.
488 */
489 static char **
490 psql_completion(char *text, int start, int end)
491 {
492         /* This is the variable we'll return. */
493         char      **matches = NULL;
494
495         /* These are going to contain some scannage of the input line. */
496         char       *prev_wd,
497                            *prev2_wd,
498                            *prev3_wd,
499                            *prev4_wd;
500
501         static char *sql_commands[] = {
502                 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
503                 "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE", "DROP", "EXECUTE",
504                 "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY",
505                 "PREPARE", "REINDEX", "RESET", "REVOKE", "ROLLBACK", "SELECT", "SET", "SHOW",
506                 "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL
507         };
508
509         static char *pgsql_variables[] = {
510                 /* these SET arguments are known in gram.y */
511                 "CONSTRAINTS",
512                 "NAMES",
513                 "SESSION",
514                 "TRANSACTION",
515
516                 /*
517                  * the rest should match USERSET and possibly SUSET entries in
518                  * backend/utils/misc/guc.c.
519                  */
520                 "add_missing_from",
521                 "australian_timezones",
522                 "client_encoding",
523                 "client_min_messages",
524                 "commit_delay",
525                 "commit_siblings",
526                 "cpu_index_tuple_cost",
527                 "cpu_operator_cost",
528                 "cpu_tuple_cost",
529                 "DateStyle",
530                 "deadlock_timeout",
531                 "debug_pretty_print",
532                 "debug_print_parse",
533                 "debug_print_plan",
534                 "debug_print_rewritten",
535                 "default_statistics_target",
536                 "default_transaction_isolation",
537                 "default_transaction_read_only",
538                 "dynamic_library_path",
539                 "effective_cache_size",
540                 "enable_hashagg",
541                 "enable_hashjoin",
542                 "enable_indexscan",
543                 "enable_mergejoin",
544                 "enable_nestloop",
545                 "enable_seqscan",
546                 "enable_sort",
547                 "enable_tidscan",
548                 "explain_pretty_print",
549                 "extra_float_digits",
550                 "from_collapse_limit",
551                 "fsync",
552                 "geqo",
553                 "geqo_effort",
554                 "geqo_generations",
555                 "geqo_pool_size",
556                 "geqo_selection_bias",
557                 "geqo_threshold",
558                 "join_collapse_limit",
559                 "krb_server_keyfile",
560                 "lc_messages",
561                 "lc_monetary",
562                 "lc_numeric",
563                 "lc_time",
564                 "log_duration",
565                 "log_error_verbosity",
566                 "log_executor_stats",
567                 "log_min_duration_statement",
568                 "log_min_error_statement",
569                 "log_min_messages",
570                 "log_parser_stats",
571                 "log_planner_stats",
572                 "log_statement",
573                 "log_statement_stats",
574                 "max_connections",
575                 "max_expr_depth",
576                 "max_files_per_process",
577                 "max_fsm_pages",
578                 "max_fsm_relations",
579                 "max_locks_per_transaction",
580                 "password_encryption",
581                 "port",
582                 "random_page_cost",
583                 "regex_flavor",
584                 "search_path",
585                 "shared_buffers",
586                 "seed",
587                 "server_encoding",
588                 "sort_mem",
589                 "sql_inheritance",
590                 "ssl",
591                 "statement_timeout",
592                 "stats_block_level",
593                 "stats_command_string",
594                 "stats_reset_on_server_start",
595                 "stats_row_level",
596                 "stats_start_collector",
597                 "superuser_reserved_connections",
598                 "syslog",
599                 "syslog_facility",
600                 "syslog_ident",
601                 "tcpip_socket",
602                 "TimeZone",
603                 "trace_notify",
604                 "transform_null_equals",
605                 "unix_socket_directory",
606                 "unix_socket_group",
607                 "unix_socket_permissions",
608                 "vacuum_mem",
609                 "wal_buffers",
610                 "wal_debug",
611                 "wal_sync_method",
612                 NULL
613         };
614
615         static char *backslash_commands[] = {
616                 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
617                 "\\d", "\\da", "\\dc", "\\dC", "\\dd", "\\dD", "\\df", "\\di",
618                 "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT",
619                 "\\dv", "\\du",
620                 "\\e", "\\echo", "\\encoding",
621                 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
622                 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
623                 "\\o", "\\p", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
624                 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
625         };
626
627         (void) end;                                     /* not used */
628
629 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
630         rl_completion_append_character = ' ';
631 #endif
632
633         /* Clear a few things. */
634         completion_charp = NULL;
635         completion_charpp = NULL;
636         completion_info_charp = NULL;
637
638         /*
639          * Scan the input line before our current position for the last four
640          * words. According to those we'll make some smart decisions on what
641          * the user is probably intending to type. TODO: Use strtokx() to do
642          * this.
643          */
644         prev_wd = previous_word(start, 0);
645         prev2_wd = previous_word(start, 1);
646         prev3_wd = previous_word(start, 2);
647         prev4_wd = previous_word(start, 3);
648
649         /* If a backslash command was started, continue */
650         if (text[0] == '\\')
651                 COMPLETE_WITH_LIST(backslash_commands);
652
653         /* If no previous word, suggest one of the basic sql commands */
654         else if (!prev_wd)
655                 COMPLETE_WITH_LIST(sql_commands);
656
657 /* CREATE or DROP but not ALTER TABLE sth DROP */
658         /* complete with something you can create or drop */
659         else if (strcasecmp(prev_wd, "CREATE") == 0 ||
660                          (strcasecmp(prev_wd, "DROP") == 0 &&
661                           strcasecmp(prev3_wd, "TABLE") != 0))
662                 matches = completion_matches(text, create_command_generator);
663
664 /* ALTER */
665
666         /*
667          * complete with what you can alter (TABLE, GROUP, USER, ...) unless
668          * we're in ALTER TABLE sth ALTER
669          */
670         else if (strcasecmp(prev_wd, "ALTER") == 0 &&
671                          strcasecmp(prev3_wd, "TABLE") != 0)
672         {
673                 char       *list_ALTER[] = {"DATABASE", "GROUP", "SCHEMA", "TABLE",
674                 "TRIGGER", "USER", NULL};
675
676                 COMPLETE_WITH_LIST(list_ALTER);
677         }
678
679         /* ALTER DATABASE <name> */
680         else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
681                          strcasecmp(prev2_wd, "DATABASE") == 0)
682         {
683                 char       *list_ALTERDATABASE[] = {"RESET", "SET", NULL};
684
685                 COMPLETE_WITH_LIST(list_ALTERDATABASE);
686         }
687         /* ALTER TRIGGER <name>, add ON */
688         else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
689                          strcasecmp(prev2_wd, "TRIGGER") == 0)
690                 COMPLETE_WITH_CONST("ON");
691
692         /*
693          * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
694          */
695         else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
696                          strcasecmp(prev3_wd, "TRIGGER") == 0 &&
697                          strcasecmp(prev_wd, "ON") == 0)
698                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
699
700         /*
701          * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
702          * RENAME, or OWNER
703          */
704         else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
705                          strcasecmp(prev2_wd, "TABLE") == 0)
706         {
707                 char       *list_ALTER2[] = {"ADD", "ALTER", "DROP", "RENAME",
708                 "OWNER TO", NULL};
709
710                 COMPLETE_WITH_LIST(list_ALTER2);
711         }
712         /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
713         else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
714                          (strcasecmp(prev_wd, "ALTER") == 0 ||
715                           strcasecmp(prev_wd, "RENAME") == 0))
716                 COMPLETE_WITH_ATTR(prev2_wd);
717
718         /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
719         else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
720                          strcasecmp(prev_wd, "DROP") == 0)
721         {
722                 char       *list_TABLEDROP[] = {"COLUMN", "CONSTRAINT", NULL};
723
724                 COMPLETE_WITH_LIST(list_TABLEDROP);
725         }
726         /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
727         else if (strcasecmp(prev4_wd, "TABLE") == 0 &&
728                          strcasecmp(prev2_wd, "DROP") == 0 &&
729                          strcasecmp(prev_wd, "COLUMN") == 0)
730                 COMPLETE_WITH_ATTR(prev3_wd);
731
732         /* complete ALTER GROUP <foo> with ADD or DROP */
733         else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
734                          strcasecmp(prev2_wd, "GROUP") == 0)
735         {
736                 char       *list_ALTERGROUP[] = {"ADD", "DROP", NULL};
737
738                 COMPLETE_WITH_LIST(list_ALTERGROUP);
739         }
740         /* complete ALTER GROUP <foo> ADD|DROP with USER */
741         else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
742                          strcasecmp(prev3_wd, "GROUP") == 0 &&
743                          (strcasecmp(prev_wd, "ADD") == 0 ||
744                           strcasecmp(prev_wd, "DROP") == 0))
745                 COMPLETE_WITH_CONST("USER");
746         /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
747         else if (strcasecmp(prev4_wd, "GROUP") == 0 &&
748                          (strcasecmp(prev2_wd, "ADD") == 0 ||
749                           strcasecmp(prev2_wd, "DROP") == 0) &&
750                          strcasecmp(prev_wd, "USER") == 0)
751                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
752
753 /* ANALYZE */
754         /* If the previous word is ANALYZE, produce list of tables. */
755         else if (strcasecmp(prev_wd, "ANALYZE") == 0)
756                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
757         /* If we have ANALYZE <table>, complete with semicolon. */
758         else if (strcasecmp(prev2_wd, "ANALYZE") == 0)
759                 COMPLETE_WITH_CONST(";");
760
761 /* CLUSTER */
762         /* If the previous word is CLUSTER, produce list of indexes. */
763         else if (strcasecmp(prev_wd, "CLUSTER") == 0)
764                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
765         /* If we have CLUSTER <sth>, then add "ON" */
766         else if (strcasecmp(prev2_wd, "CLUSTER") == 0)
767                 COMPLETE_WITH_CONST("ON");
768
769         /*
770          * If we have CLUSTER <sth> ON, then add the correct tablename as
771          * well.
772          */
773         else if (strcasecmp(prev3_wd, "CLUSTER") == 0 &&
774                          strcasecmp(prev_wd, "ON") == 0)
775         {
776                 completion_info_charp = prev2_wd;
777                 COMPLETE_WITH_QUERY(Query_for_table_owning_index);
778         }
779
780 /* COMMENT */
781         else if (strcasecmp(prev_wd, "COMMENT") == 0)
782                 COMPLETE_WITH_CONST("ON");
783         else if (strcasecmp(prev2_wd, "COMMENT") == 0 &&
784                          strcasecmp(prev_wd, "ON") == 0)
785         {
786                 char       *list_COMMENT[] =
787                 {"DATABASE", "INDEX", "RULE", "SCHEMA", "SEQUENCE", "TABLE",
788                         "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR",
789                 "TRIGGER", "CONSTRAINT", "DOMAIN", NULL};
790
791                 COMPLETE_WITH_LIST(list_COMMENT);
792         }
793         else if (strcasecmp(prev4_wd, "COMMENT") == 0 &&
794                          strcasecmp(prev3_wd, "ON") == 0)
795                 COMPLETE_WITH_CONST("IS");
796
797 /* COPY */
798
799         /*
800          * If we have COPY [BINARY] (which you'd have to type yourself), offer
801          * list of tables (Also cover the analogous backslash command)
802          */
803         else if (strcasecmp(prev_wd, "COPY") == 0 ||
804                          strcasecmp(prev_wd, "\\copy") == 0 ||
805                          (strcasecmp(prev2_wd, "COPY") == 0 &&
806                           strcasecmp(prev_wd, "BINARY") == 0))
807                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
808         /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
809         else if (strcasecmp(prev2_wd, "COPY") == 0 ||
810                          strcasecmp(prev2_wd, "\\copy") == 0 ||
811                          strcasecmp(prev2_wd, "BINARY") == 0)
812         {
813                 char       *list_FROMTO[] = {"FROM", "TO", NULL};
814
815                 COMPLETE_WITH_LIST(list_FROMTO);
816         }
817
818 /* CREATE INDEX */
819         /* First off we complete CREATE UNIQUE with "INDEX" */
820         else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
821                          strcasecmp(prev_wd, "UNIQUE") == 0)
822                 COMPLETE_WITH_CONST("INDEX");
823         /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
824         else if (strcasecmp(prev2_wd, "INDEX") == 0 &&
825                          (strcasecmp(prev3_wd, "CREATE") == 0 ||
826                           strcasecmp(prev3_wd, "UNIQUE") == 0))
827                 COMPLETE_WITH_CONST("ON");
828         /* Complete ... INDEX <name> ON with a list of tables  */
829         else if (strcasecmp(prev3_wd, "INDEX") == 0 &&
830                          strcasecmp(prev_wd, "ON") == 0)
831                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
832
833         /*
834          * Complete INDEX <name> ON <table> with a list of table columns
835          * (which should really be in parens)
836          */
837         else if (strcasecmp(prev4_wd, "INDEX") == 0 &&
838                          strcasecmp(prev2_wd, "ON") == 0)
839                 COMPLETE_WITH_ATTR(prev_wd);
840         /* same if you put in USING */
841         else if (strcasecmp(prev4_wd, "ON") == 0 &&
842                          strcasecmp(prev2_wd, "USING") == 0)
843                 COMPLETE_WITH_ATTR(prev3_wd);
844         /* Complete USING with an index method */
845         else if (strcasecmp(prev_wd, "USING") == 0)
846         {
847                 char       *index_mth[] = {"BTREE", "RTREE", "HASH", "GIST", NULL};
848
849                 COMPLETE_WITH_LIST(index_mth);
850         }
851
852 /* CREATE RULE */
853         /* Complete "CREATE RULE <sth>" with "AS" */
854         else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
855                          strcasecmp(prev2_wd, "RULE") == 0)
856                 COMPLETE_WITH_CONST("AS");
857         /* Complete "CREATE RULE <sth> AS with "ON" */
858         else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
859                          strcasecmp(prev3_wd, "RULE") == 0 &&
860                          strcasecmp(prev_wd, "AS") == 0)
861                 COMPLETE_WITH_CONST("ON");
862         /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
863         else if (strcasecmp(prev4_wd, "RULE") == 0 &&
864                          strcasecmp(prev2_wd, "AS") == 0 &&
865                          strcasecmp(prev_wd, "ON") == 0)
866         {
867                 char       *rule_events[] = {"SELECT", "UPDATE", "INSERT",
868                 "DELETE", NULL};
869
870                 COMPLETE_WITH_LIST(rule_events);
871         }
872         /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
873         else if (strcasecmp(prev3_wd, "AS") == 0 &&
874                          strcasecmp(prev2_wd, "ON") == 0 &&
875                          (toupper((unsigned char) prev_wd[4]) == 'T' ||
876                           toupper((unsigned char) prev_wd[5]) == 'T'))
877                 COMPLETE_WITH_CONST("TO");
878         /* Complete "AS ON <sth> TO" with a table name */
879         else if (strcasecmp(prev4_wd, "AS") == 0 &&
880                          strcasecmp(prev3_wd, "ON") == 0 &&
881                          strcasecmp(prev_wd, "TO") == 0)
882                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
883
884 /* CREATE TABLE */
885         /* Complete CREATE TEMP with "TABLE" */
886         else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
887                          strcasecmp(prev_wd, "TEMP") == 0)
888                 COMPLETE_WITH_CONST("TABLE");
889
890 /* CREATE TRIGGER */
891         /* is on the agenda . . . */
892
893 /* CREATE VIEW */
894         /* Complete "CREATE VIEW <name>" with "AS" */
895         else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
896                          strcasecmp(prev2_wd, "VIEW") == 0)
897                 COMPLETE_WITH_CONST("AS");
898         /* Complete "CREATE VIEW <sth> AS with "SELECT" */
899         else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
900                          strcasecmp(prev3_wd, "VIEW") == 0 &&
901                          strcasecmp(prev_wd, "AS") == 0)
902                 COMPLETE_WITH_CONST("SELECT");
903
904 /* DELETE */
905
906         /*
907          * Complete DELETE with FROM (only if the word before that is not "ON"
908          * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
909          */
910         else if (strcasecmp(prev_wd, "DELETE") == 0 &&
911                          !(strcasecmp(prev2_wd, "ON") == 0 ||
912                            strcasecmp(prev2_wd, "GRANT") == 0 ||
913                            strcasecmp(prev2_wd, "BEFORE") == 0 ||
914                            strcasecmp(prev2_wd, "AFTER") == 0))
915                 COMPLETE_WITH_CONST("FROM");
916         /* Complete DELETE FROM with a list of tables */
917         else if (strcasecmp(prev2_wd, "DELETE") == 0 &&
918                          strcasecmp(prev_wd, "FROM") == 0)
919                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
920         /* Complete DELETE FROM <table> with "WHERE" (perhaps a safe idea?) */
921         else if (strcasecmp(prev3_wd, "DELETE") == 0 &&
922                          strcasecmp(prev2_wd, "FROM") == 0)
923                 COMPLETE_WITH_CONST("WHERE");
924
925 /* EXPLAIN */
926
927         /*
928          * Complete EXPLAIN [VERBOSE] (which you'd have to type yourself) with
929          * the list of SQL commands
930          */
931         else if (strcasecmp(prev_wd, "EXPLAIN") == 0 ||
932                          (strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
933                           strcasecmp(prev_wd, "VERBOSE") == 0))
934                 COMPLETE_WITH_LIST(sql_commands);
935
936 /* FETCH && MOVE */
937         /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
938         else if (strcasecmp(prev_wd, "FETCH") == 0 ||
939                          strcasecmp(prev_wd, "MOVE") == 0)
940         {
941                 char       *list_FETCH1[] = {"FORWARD", "BACKWARD", "RELATIVE", NULL};
942
943                 COMPLETE_WITH_LIST(list_FETCH1);
944         }
945         /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
946         else if (strcasecmp(prev2_wd, "FETCH") == 0 ||
947                          strcasecmp(prev2_wd, "MOVE") == 0)
948         {
949                 char       *list_FETCH2[] = {"ALL", "NEXT", "PRIOR", NULL};
950
951                 COMPLETE_WITH_LIST(list_FETCH2);
952         }
953
954         /*
955          * Complete FETCH <sth1> <sth2> with "FROM" or "TO". (Is there a
956          * difference? If not, remove one.)
957          */
958         else if (strcasecmp(prev3_wd, "FETCH") == 0 ||
959                          strcasecmp(prev3_wd, "MOVE") == 0)
960         {
961                 char       *list_FROMTO[] = {"FROM", "TO", NULL};
962
963                 COMPLETE_WITH_LIST(list_FROMTO);
964         }
965
966 /* GRANT && REVOKE*/
967         /* Complete GRANT/REVOKE with a list of privileges */
968         else if (strcasecmp(prev_wd, "GRANT") == 0 ||
969                          strcasecmp(prev_wd, "REVOKE") == 0)
970         {
971                 char       *list_privileg[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES", "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
972
973                 COMPLETE_WITH_LIST(list_privileg);
974         }
975         /* Complete GRANT/REVOKE <sth> with "ON" */
976         else if (strcasecmp(prev2_wd, "GRANT") == 0 ||
977                          strcasecmp(prev2_wd, "REVOKE") == 0)
978                 COMPLETE_WITH_CONST("ON");
979
980         /*
981          * Complete GRANT/REVOKE <sth> ON with a list of tables, views,
982          * sequences, and indexes
983          *
984          * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result
985          * via UNION; seems to work intuitively
986          *
987          * Note: GRANT/REVOKE can get quite complex; tab-completion as
988          * implemented here will only work if the privilege list contains
989          * exactly one privilege
990          */
991         else if ((strcasecmp(prev3_wd, "GRANT") == 0 ||
992                           strcasecmp(prev3_wd, "REVOKE") == 0) &&
993                          strcasecmp(prev_wd, "ON") == 0)
994                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
995                                                         " WHERE relkind in ('r','S','v')  "
996                                                         "   AND substring(pg_catalog.quote_ident(relname),1,%d)='%s' "
997                                                   "   AND pg_catalog.pg_table_is_visible(c.oid) "
998                                                         "   AND relnamespace = n.oid "
999                                         "   AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
1000                                                         " UNION "
1001                                                         "SELECT 'DATABASE' "
1002                                                         " UNION "
1003                                                         "SELECT 'FUNCTION' "
1004                                                         " UNION "
1005                                                         "SELECT 'LANGUAGE' "
1006                                                         " UNION "
1007                                                         "SELECT 'SCHEMA' ");
1008
1009         /* Complete "GRANT/REVOKE * ON * " with "TO" */
1010         else if ((strcasecmp(prev4_wd, "GRANT") == 0 ||
1011                           strcasecmp(prev4_wd, "REVOKE") == 0) &&
1012                          strcasecmp(prev2_wd, "ON") == 0)
1013         {
1014                 if (strcasecmp(prev_wd, "DATABASE") == 0)
1015                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1016                 else if (strcasecmp(prev_wd, "FUNCTION") == 0)
1017                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
1018                 else if (strcasecmp(prev_wd, "LANGUAGE") == 0)
1019                         COMPLETE_WITH_QUERY(Query_for_list_of_languages);
1020                 else if (strcasecmp(prev_wd, "SCHEMA") == 0)
1021                         COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1022                 else
1023                         COMPLETE_WITH_CONST("TO");
1024         }
1025
1026         /*
1027          * TODO: to complete with user name we need prev5_wd -- wait for a
1028          * more general solution there same for GRANT <sth> ON { DATABASE |
1029          * FUNCTION | LANGUAGE | SCHEMA } xxx TO
1030          */
1031
1032 /* INSERT */
1033         /* Complete INSERT with "INTO" */
1034         else if (strcasecmp(prev_wd, "INSERT") == 0)
1035                 COMPLETE_WITH_CONST("INTO");
1036         /* Complete INSERT INTO with table names */
1037         else if (strcasecmp(prev2_wd, "INSERT") == 0 &&
1038                          strcasecmp(prev_wd, "INTO") == 0)
1039                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1040         /* Complete "INSERT INTO <table> (" with attribute names */
1041         else if (rl_line_buffer[start - 1] == '(' &&
1042                          strcasecmp(prev3_wd, "INSERT") == 0 &&
1043                          strcasecmp(prev2_wd, "INTO") == 0)
1044                 COMPLETE_WITH_ATTR(prev_wd);
1045
1046         /*
1047          * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1048          * VALUES"
1049          */
1050         else if (strcasecmp(prev3_wd, "INSERT") == 0 &&
1051                          strcasecmp(prev2_wd, "INTO") == 0)
1052         {
1053                 char       *list_INSERT[] = {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1054
1055                 COMPLETE_WITH_LIST(list_INSERT);
1056         }
1057         /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1058         else if (strcasecmp(prev4_wd, "INSERT") == 0 &&
1059                          strcasecmp(prev3_wd, "INTO") == 0 &&
1060                          prev_wd[strlen(prev_wd) - 1] == ')')
1061         {
1062                 char       *list_INSERT[] = {"SELECT", "VALUES", NULL};
1063
1064                 COMPLETE_WITH_LIST(list_INSERT);
1065         }
1066
1067         /* Insert an open parenthesis after "VALUES" */
1068         else if (strcasecmp(prev_wd, "VALUES") == 0 &&
1069                          strcasecmp(prev2_wd, "DEFAULT") != 0)
1070                 COMPLETE_WITH_CONST("(");
1071
1072 /* LOCK */
1073         /* Complete LOCK [TABLE] with a list of tables */
1074         else if (strcasecmp(prev_wd, "LOCK") == 0 ||
1075                          (strcasecmp(prev_wd, "TABLE") == 0 &&
1076                           strcasecmp(prev2_wd, "LOCK") == 0))
1077                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1078
1079         /* For the following, handle the case of a single table only for now */
1080
1081         /* Complete LOCK [TABLE] <table> with "IN" */
1082         else if ((strcasecmp(prev2_wd, "LOCK") == 0 &&
1083                           strcasecmp(prev_wd, "TABLE")) ||
1084                          (strcasecmp(prev2_wd, "TABLE") == 0 &&
1085                           strcasecmp(prev3_wd, "LOCK") == 0))
1086                 COMPLETE_WITH_CONST("IN");
1087
1088         /* Complete LOCK [TABLE] <table> IN with a lock mode */
1089         else if (strcasecmp(prev_wd, "IN") == 0 &&
1090                          (strcasecmp(prev3_wd, "LOCK") == 0 ||
1091                           (strcasecmp(prev3_wd, "TABLE") == 0 &&
1092                            strcasecmp(prev4_wd, "LOCK") == 0)))
1093         {
1094                 char       *lock_modes[] = {"ACCESS SHARE MODE",
1095                         "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1096                         "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1097                         "SHARE ROW EXCLUSIVE MODE",
1098                 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1099
1100                 COMPLETE_WITH_LIST(lock_modes);
1101         }
1102
1103 /* NOTIFY */
1104         else if (strcasecmp(prev_wd, "NOTIFY") == 0)
1105                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
1106
1107 /* REINDEX */
1108         else if (strcasecmp(prev_wd, "REINDEX") == 0)
1109         {
1110                 char       *list_REINDEX[] = {"TABLE", "DATABASE", "INDEX", NULL};
1111
1112                 COMPLETE_WITH_LIST(list_REINDEX);
1113         }
1114         else if (strcasecmp(prev2_wd, "REINDEX") == 0)
1115         {
1116                 if (strcasecmp(prev_wd, "TABLE") == 0)
1117                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1118                 else if (strcasecmp(prev_wd, "DATABASE") == 0)
1119                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1120                 else if (strcasecmp(prev_wd, "INDEX") == 0)
1121                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1122         }
1123
1124 /* SELECT */
1125         /* naah . . . */
1126
1127 /* SET, RESET, SHOW */
1128         /* Complete with a variable name */
1129         else if ((strcasecmp(prev_wd, "SET") == 0 &&
1130                           strcasecmp(prev3_wd, "UPDATE") != 0) ||
1131                          strcasecmp(prev_wd, "RESET") == 0 ||
1132                          strcasecmp(prev_wd, "SHOW") == 0)
1133                 COMPLETE_WITH_LIST(pgsql_variables);
1134         /* Complete "SET TRANSACTION" */
1135         else if ((strcasecmp(prev2_wd, "SET") == 0 &&
1136                           strcasecmp(prev_wd, "TRANSACTION") == 0) ||
1137                          (strcasecmp(prev4_wd, "SESSION") == 0 &&
1138                           strcasecmp(prev3_wd, "CHARACTERISTICS") == 0 &&
1139                           strcasecmp(prev2_wd, "AS") == 0 &&
1140                           strcasecmp(prev_wd, "TRANSACTION") == 0))
1141         {
1142                 char       *my_list[] = {"ISOLATION", "READ", NULL};
1143
1144                 COMPLETE_WITH_LIST(my_list);
1145         }
1146         else if (strcasecmp(prev3_wd, "SET") == 0 &&
1147                          strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1148                          strcasecmp(prev_wd, "ISOLATION") == 0)
1149                 COMPLETE_WITH_CONST("LEVEL");
1150         else if ((strcasecmp(prev4_wd, "SET") == 0 ||
1151                           strcasecmp(prev4_wd, "AS") == 0) &&
1152                          strcasecmp(prev3_wd, "TRANSACTION") == 0 &&
1153                          strcasecmp(prev2_wd, "ISOLATION") == 0 &&
1154                          strcasecmp(prev_wd, "LEVEL") == 0)
1155         {
1156                 char       *my_list[] = {"READ", "SERIALIZABLE", NULL};
1157
1158                 COMPLETE_WITH_LIST(my_list);
1159         }
1160         else if (strcasecmp(prev4_wd, "TRANSACTION") == 0 &&
1161                          strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1162                          strcasecmp(prev2_wd, "LEVEL") == 0 &&
1163                          strcasecmp(prev_wd, "READ") == 0)
1164                 COMPLETE_WITH_CONST("COMMITTED");
1165         else if ((strcasecmp(prev3_wd, "SET") == 0 ||
1166                           strcasecmp(prev3_wd, "AS") == 0) &&
1167                          strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1168                          strcasecmp(prev_wd, "READ") == 0)
1169         {
1170                 char       *my_list[] = {"ONLY", "WRITE", NULL};
1171
1172                 COMPLETE_WITH_LIST(my_list);
1173         }
1174         /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1175         else if (strcasecmp(prev3_wd, "SET") == 0 &&
1176                          strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1177         {
1178                 char       *constraint_list[] = {"DEFERRED", "IMMEDIATE", NULL};
1179
1180                 COMPLETE_WITH_LIST(constraint_list);
1181         }
1182         /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1183         else if (strcasecmp(prev2_wd, "SET") == 0 &&
1184                          strcasecmp(prev_wd, "SESSION") == 0)
1185         {
1186                 char       *my_list[] = {"AUTHORIZATION",
1187                         "CHARACTERISTICS AS TRANSACTION",
1188                 NULL};
1189
1190                 COMPLETE_WITH_LIST(my_list);
1191         }
1192         /* Complete SET SESSION AUTHORIZATION with username */
1193         else if (strcasecmp(prev3_wd, "SET") == 0
1194                          && strcasecmp(prev2_wd, "SESSION") == 0
1195                          && strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1196                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1197         /* Complete SET <var> with "TO" */
1198         else if (strcasecmp(prev2_wd, "SET") == 0 &&
1199                          strcasecmp(prev4_wd, "UPDATE") != 0)
1200                 COMPLETE_WITH_CONST("TO");
1201         /* Suggest possible variable values */
1202         else if (strcasecmp(prev3_wd, "SET") == 0 &&
1203                    (strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1204         {
1205                 if (strcasecmp(prev2_wd, "DateStyle") == 0)
1206                 {
1207                         char       *my_list[] = {"ISO", "SQL", "Postgres", "German",
1208                                 "YMD", "DMY", "MDY",
1209                                 "US", "European", "NonEuropean",
1210                         "DEFAULT", NULL};
1211
1212                         COMPLETE_WITH_LIST(my_list);
1213                 }
1214                 else if (strcasecmp(prev2_wd, "GEQO") == 0)
1215                 {
1216                         char       *my_list[] = {"ON", "OFF", "DEFAULT", NULL};
1217
1218                         COMPLETE_WITH_LIST(my_list);
1219                 }
1220                 else
1221                 {
1222                         char       *my_list[] = {"DEFAULT", NULL};
1223
1224                         COMPLETE_WITH_LIST(my_list);
1225                 }
1226         }
1227
1228 /* TRUNCATE */
1229         else if (strcasecmp(prev_wd, "TRUNCATE") == 0)
1230                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1231
1232 /* UNLISTEN */
1233         else if (strcasecmp(prev_wd, "UNLISTEN") == 0)
1234                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s' UNION SELECT '*'");
1235
1236 /* UPDATE */
1237         /* If prev. word is UPDATE suggest a list of tables */
1238         else if (strcasecmp(prev_wd, "UPDATE") == 0)
1239                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1240         /* Complete UPDATE <table> with "SET" */
1241         else if (strcasecmp(prev2_wd, "UPDATE") == 0)
1242                 COMPLETE_WITH_CONST("SET");
1243
1244         /*
1245          * If the previous word is SET (and it wasn't caught above as the
1246          * _first_ word) the word before it was (hopefully) a table name and
1247          * we'll now make a list of attributes.
1248          */
1249         else if (strcasecmp(prev_wd, "SET") == 0)
1250                 COMPLETE_WITH_ATTR(prev2_wd);
1251
1252 /* VACUUM */
1253         else if (strcasecmp(prev_wd, "VACUUM") == 0)
1254                 COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_class WHERE relkind='r' and substring(pg_catalog.quote_ident(relname),1,%d)='%s' and pg_catalog.pg_table_is_visible(oid) UNION SELECT 'FULL' UNION SELECT 'ANALYZE' UNION SELECT 'VERBOSE'");
1255         else if (strcasecmp(prev2_wd, "VACUUM") == 0 &&
1256                          (strcasecmp(prev_wd, "FULL") == 0 ||
1257                           strcasecmp(prev_wd, "ANALYZE") == 0 ||
1258                           strcasecmp(prev_wd, "VERBOSE") == 0))
1259                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1260
1261 /* WHERE */
1262         /* Simple case of the word before the where being the table name */
1263         else if (strcasecmp(prev_wd, "WHERE") == 0)
1264                 COMPLETE_WITH_ATTR(prev2_wd);
1265
1266 /* ... FROM ... */
1267 /* TODO: also include SRF ? */
1268         else if (strcasecmp(prev_wd, "FROM") == 0)
1269                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1270
1271
1272 /* Backslash commands */
1273 /* TODO:  \dc \dd \dl */
1274         else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1275                 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1276         else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1277                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv);
1278         else if (strcmp(prev_wd, "\\da") == 0)
1279                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates);
1280         else if (strcmp(prev_wd, "\\dD") == 0)
1281                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains);
1282         else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1283                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
1284         else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1285                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1286         else if (strcmp(prev_wd, "\\dn") == 0)
1287                 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1288         else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1289                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1290         else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1291                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences);
1292         else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1293                 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1294         else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1295                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1296         else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1297                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes);
1298         else if (strcmp(prev_wd, "\\du") == 0)
1299                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1300         else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1301                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
1302         else if (strcmp(prev_wd, "\\encoding") == 0)
1303                 COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
1304         else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1305                 COMPLETE_WITH_LIST(sql_commands);
1306         else if (strcmp(prev_wd, "\\pset") == 0)
1307         {
1308                 char       *my_list[] = {"format", "border", "expanded",
1309                         "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1310                 "recordsep", NULL};
1311
1312                 COMPLETE_WITH_LIST(my_list);
1313         }
1314         else if (strcmp(prev_wd, "\\cd") == 0 ||
1315                  strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1316                          strcmp(prev_wd, "\\g") == 0 ||
1317                          strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1318                   strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1319                          strcmp(prev_wd, "\\s") == 0 ||
1320                    strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1321                 )
1322                 matches = completion_matches(text, filename_completion_function);
1323
1324
1325         /*
1326          * Finally, we look through the list of "things", such as TABLE, INDEX
1327          * and check if that was the previous word. If so, execute the query
1328          * to get a list of them.
1329          */
1330         else
1331         {
1332                 int                     i;
1333
1334                 for (i = 0; words_after_create[i].name; i++)
1335                         if (strcasecmp(prev_wd, words_after_create[i].name) == 0)
1336                         {
1337                                 if (words_after_create[i].with_schema == WITH_SCHEMA)
1338                                         COMPLETE_WITH_SCHEMA_QUERY(words_after_create[i].query);
1339                                 else
1340                                         COMPLETE_WITH_QUERY(words_after_create[i].query);
1341                                 break;
1342                         }
1343         }
1344
1345
1346         /*
1347          * If we still don't have anything to match we have to fabricate some
1348          * sort of default list. If we were to just return NULL, readline
1349          * automatically attempts filename completion, and that's usually no
1350          * good.
1351          */
1352         if (matches == NULL)
1353         {
1354                 COMPLETE_WITH_CONST("");
1355 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1356                 rl_completion_append_character = '\0';
1357 #endif
1358         }
1359
1360
1361         /* free storage */
1362         free(prev_wd);
1363         free(prev2_wd);
1364         free(prev3_wd);
1365         free(prev4_wd);
1366
1367         /* Return our Grand List O' Matches */
1368         return matches;
1369 }
1370
1371
1372
1373 /* GENERATOR FUNCTIONS
1374
1375    These functions do all the actual work of completing the input. They get
1376    passed the text so far and the count how many times they have been called so
1377    far with the same text.
1378    If you read the above carefully, you'll see that these don't get called
1379    directly but through the readline interface.
1380    The return value is expected to be the full completion of the text, going
1381    through a list each time, or NULL if there are no more matches. The string
1382    will be free()'d be readline, so you must run it through strdup() or
1383    something of that sort.
1384 */
1385
1386 /* This one gives you one from a list of things you can put after CREATE or DROP
1387    as defined above.
1388 */
1389 static char *
1390 create_command_generator(const char *text, int state)
1391 {
1392         static int      list_index,
1393                                 string_length;
1394         char       *name;
1395
1396         /* If this is the first time for this completion, init some values */
1397         if (state == 0)
1398         {
1399                 list_index = 0;
1400                 string_length = strlen(text);
1401         }
1402
1403         /* find something that matches */
1404         while ((name = words_after_create[list_index++].name))
1405                 if (strncasecmp(name, text, string_length) == 0)
1406                         return xstrdup(name);
1407
1408         /* if nothing matches, return NULL */
1409         return NULL;
1410 }
1411
1412
1413 /* The following two functions are wrappers for _complete_from_query */
1414
1415 static char *
1416 complete_from_query(const char *text, int state)
1417 {
1418         return _complete_from_query(0, text, state);
1419 }
1420
1421 static char *
1422 complete_from_schema_query(const char *text, int state)
1423 {
1424         return _complete_from_query(1, text, state);
1425 }
1426
1427
1428 /* This creates a list of matching things, according to a query pointed to
1429    by completion_charp.
1430    The query can be one of two kinds:
1431    - A simple query which must contain a %d and a %s, which will be replaced
1432    by the string length of the text and the text itself. The query may also
1433    have another %s in it, which will be replaced by the value of
1434    completion_info_charp.
1435          or:
1436    - A schema query used for completion of both schema and relation names;
1437    these are more complex and must contain in the following order:
1438          %d %s %d %s %d %s %s %d %s
1439    where %d is the string length of the text and %s the text itself.
1440
1441    It is assumed that strings should be escaped to become SQL literals
1442    (that is, what is in the query is actually ... '%s' ...)
1443
1444    See top of file for examples of both kinds of query.
1445 */
1446
1447 static char *
1448 _complete_from_query(int is_schema_query, const char *text, int state)
1449 {
1450         static int      list_index,
1451                                 string_length;
1452         static PGresult *result = NULL;
1453
1454         /*
1455          * If this is the first time for this completion, we fetch a list of
1456          * our "things" from the backend.
1457          */
1458         if (state == 0)
1459         {
1460                 char            query_buffer[BUF_SIZE];
1461                 char       *e_text;
1462                 char       *e_info_charp;
1463
1464                 list_index = 0;
1465                 string_length = strlen(text);
1466
1467                 /* Free any prior result */
1468                 PQclear(result);
1469                 result = NULL;
1470
1471                 /* Need to have a query */
1472                 if (completion_charp == NULL)
1473                         return NULL;
1474
1475                 /* Set up suitably-escaped copies of textual inputs */
1476                 if (text)
1477                 {
1478                         e_text = (char *) malloc(strlen(text) * 2 + 1);
1479                         if (!e_text)
1480                                 return NULL;
1481                         PQescapeString(e_text, text, strlen(text));
1482                 }
1483                 else
1484                         e_text = NULL;
1485
1486                 if (completion_info_charp)
1487                 {
1488                         e_info_charp = (char *)
1489                                 malloc(strlen(completion_info_charp) * 2 + 1);
1490                         if (!e_info_charp)
1491                         {
1492                                 if (e_text)
1493                                         free(e_text);
1494                                 return NULL;
1495                         }
1496                         PQescapeString(e_info_charp, completion_info_charp,
1497                                                    strlen(completion_info_charp));
1498                 }
1499                 else
1500                         e_info_charp = NULL;
1501
1502                 if (is_schema_query)
1503                 {
1504                         if (snprintf(query_buffer, BUF_SIZE, completion_charp,
1505                                                  string_length, e_text,
1506                                                  string_length, e_text,
1507                                                  string_length, e_text,
1508                                                  e_text,
1509                                                  string_length, e_text,
1510                                                  string_length, e_text) == -1)
1511                                 ERROR_QUERY_TOO_LONG;
1512                         else
1513                                 result = exec_query(query_buffer);
1514                 }
1515                 else
1516                 {
1517                         if (snprintf(query_buffer, BUF_SIZE, completion_charp,
1518                                                  string_length, e_text, e_info_charp) == -1)
1519                                 ERROR_QUERY_TOO_LONG;
1520                         else
1521                                 result = exec_query(query_buffer);
1522                 }
1523
1524                 if (e_text)
1525                         free(e_text);
1526                 if (e_info_charp)
1527                         free(e_info_charp);
1528         }
1529
1530         /* Find something that matches */
1531         if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
1532         {
1533                 const char *item;
1534
1535                 while (list_index < PQntuples(result) &&
1536                            (item = PQgetvalue(result, list_index++, 0)))
1537                         if (strncasecmp(text, item, string_length) == 0)
1538                                 return xstrdup(item);
1539         }
1540
1541         /* If nothing matches, free the db structure and return null */
1542         PQclear(result);
1543         result = NULL;
1544         return NULL;
1545 }
1546
1547
1548 /* This function returns in order one of a fixed, NULL pointer terminated list
1549    of strings (if matching). This can be used if there are only a fixed number
1550    SQL words that can appear at certain spot.
1551 */
1552 static char *
1553 complete_from_list(const char *text, int state)
1554 {
1555         static int      string_length,
1556                                 list_index,
1557                                 matches;
1558         static bool casesensitive;
1559         char       *item;
1560
1561         /* need to have a list */
1562 #ifdef USE_ASSERT_CHECKING
1563         assert(completion_charpp);
1564 #endif
1565
1566         /* Initialization */
1567         if (state == 0)
1568         {
1569                 list_index = 0;
1570                 string_length = strlen(text);
1571                 casesensitive = true;
1572                 matches = 0;
1573         }
1574
1575         while ((item = completion_charpp[list_index++]))
1576         {
1577                 /* First pass is case sensitive */
1578                 if (casesensitive && strncmp(text, item, string_length) == 0)
1579                 {
1580                         matches++;
1581                         return xstrdup(item);
1582                 }
1583
1584                 /* Second pass is case insensitive, don't bother counting matches */
1585                 if (!casesensitive && strncasecmp(text, item, string_length) == 0)
1586                         return xstrdup(item);
1587         }
1588
1589         /*
1590          * No matches found. If we're not case insensitive already, lets
1591          * switch to being case insensitive and try again
1592          */
1593         if (casesensitive && matches == 0)
1594         {
1595                 casesensitive = false;
1596                 list_index = 0;
1597                 state++;
1598                 return (complete_from_list(text, state));
1599         }
1600
1601         /* If no more matches, return null. */
1602         return NULL;
1603 }
1604
1605
1606 /* This function returns one fixed string the first time even if it doesn't
1607    match what's there, and nothing the second time. This should be used if there
1608    is only one possibility that can appear at a certain spot, so misspellings
1609    will be overwritten.
1610    The string to be passed must be in completion_charp.
1611 */
1612 static char *
1613 complete_from_const(const char *text, int state)
1614 {
1615         (void) text;                            /* We don't care about what was entered
1616                                                                  * already. */
1617
1618 #ifdef USE_ASSERT_CHECKING
1619         assert(completion_charp);
1620 #endif
1621         if (state == 0)
1622                 return xstrdup(completion_charp);
1623         else
1624                 return NULL;
1625 }
1626
1627
1628
1629 /* HELPER FUNCTIONS */
1630
1631
1632 /* Execute a query and report any errors. This should be the preferred way of
1633    talking to the database in this file.
1634    Note that the query passed in here must not have a semicolon at the end
1635    because we need to append LIMIT xxx.
1636 */
1637 static PGresult *
1638 exec_query(char *query)
1639 {
1640         PGresult   *result;
1641         char            query_buffer[BUF_SIZE];
1642
1643         if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
1644                 return NULL;
1645 #ifdef USE_ASSERT_CHECKING
1646         assert(query[strlen(query) - 1] != ';');
1647 #endif
1648
1649         if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d",
1650                                  query, completion_max_records) == -1)
1651         {
1652                 ERROR_QUERY_TOO_LONG;
1653                 return NULL;
1654         }
1655
1656         result = PQexec(pset.db, query_buffer);
1657
1658         if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
1659         {
1660 #if 0
1661                 psql_error("tab completion: %s failed - %s\n",
1662                                    query_buffer, PQresStatus(PQresultStatus(result)));
1663 #endif
1664                 PQclear(result);
1665                 result = NULL;
1666         }
1667
1668         return result;
1669 }
1670
1671
1672
1673 /* Return the word (space delimited) before point. Set skip > 0 to skip that
1674    many words; e.g. skip=1 finds the word before the previous one.
1675 */
1676 static char *
1677 previous_word(int point, int skip)
1678 {
1679         int                     i,
1680                                 start = 0,
1681                                 end = -1,
1682                                 inquotes = 0;
1683         char       *s;
1684
1685         while (skip-- >= 0)
1686         {
1687                 /* first we look for a space before the current word */
1688                 for (i = point; i >= 0; i--)
1689                         if (rl_line_buffer[i] == ' ')
1690                                 break;
1691
1692                 /* now find the first non-space which then constitutes the end */
1693                 for (; i >= 0; i--)
1694                         if (rl_line_buffer[i] != ' ')
1695                         {
1696                                 end = i;
1697                                 break;
1698                         }
1699
1700                 /*
1701                  * If no end found we return null, because there is no word before
1702                  * the point
1703                  */
1704                 if (end == -1)
1705                         return NULL;
1706
1707                 /*
1708                  * Otherwise we now look for the start. The start is either the
1709                  * last character before any space going backwards from the end,
1710                  * or it's simply character 0
1711                  */
1712                 for (start = end; start > 0; start--)
1713                 {
1714                         if (rl_line_buffer[start] == '"')
1715                                 inquotes = !inquotes;
1716                         if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
1717                                 break;
1718                 }
1719
1720                 point = start;
1721         }
1722
1723         /* make a copy */
1724         s = (char *) malloc(end - start + 2);
1725         if (!s)
1726         {
1727                 psql_error("out of memory\n");
1728                 if (!pset.cur_cmd_interactive)
1729                         exit(EXIT_FAILURE);
1730                 else
1731                         return NULL;
1732         }
1733
1734         strncpy(s, &rl_line_buffer[start], end - start + 1);
1735         s[end - start + 1] = '\0';
1736
1737         return s;
1738 }
1739
1740
1741
1742 #if 0
1743
1744 /*
1745  * Surround a string with single quotes. This works for both SQL and
1746  * psql internal. Currently disable because it is reported not to
1747  * cooperate with certain versions of readline.
1748  */
1749 static char *
1750 quote_file_name(char *text, int match_type, char *quote_pointer)
1751 {
1752         char       *s;
1753         size_t          length;
1754
1755         (void) quote_pointer;           /* not used */
1756
1757         length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
1758         s = malloc(length);
1759         s[0] = '\'';
1760         strcpy(s + 1, text);
1761         if (match_type == SINGLE_MATCH)
1762                 s[length - 2] = '\'';
1763         s[length - 1] = '\0';
1764         return s;
1765 }
1766
1767
1768
1769 static char *
1770 dequote_file_name(char *text, char quote_char)
1771 {
1772         char       *s;
1773         size_t          length;
1774
1775         if (!quote_char)
1776                 return xstrdup(text);
1777
1778         length = strlen(text);
1779         s = malloc(length - 2 + 1);
1780         strncpy(s, text +1, length - 2);
1781         s[length] = '\0';
1782
1783         return s;
1784 }
1785 #endif   /* 0 */
1786
1787 #endif   /* USE_READLINE */