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