]> granicus.if.org Git - postgresql/blob - src/bin/psql/tab-complete.c
const-ify functions used with completion_matches(), to suppress
[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.76 2003/04/03 20:18:16 tgl 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                 "australian_timezones",
496                 "autocommit",
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_error_statement",
543                 "log_min_messages",
544                 "log_parser_stats",
545                 "log_planner_stats",
546                 "log_statement",
547                 "log_statement_stats",
548                 "max_connections",
549                 "max_expr_depth",
550                 "max_files_per_process",
551                 "max_fsm_pages",
552                 "max_fsm_relations",
553                 "max_locks_per_transaction",
554                 "password_encryption",
555                 "port",
556                 "random_page_cost",
557                 "regex_flavor",
558                 "search_path",
559                 "shared_buffers",
560                 "seed",
561                 "server_encoding",
562                 "sort_mem",
563                 "sql_inheritance",
564                 "ssl",
565                 "statement_timeout",
566                 "stats_block_level",
567                 "stats_command_string",
568                 "stats_reset_on_server_start",
569                 "stats_row_level",
570                 "stats_start_collector",
571                 "superuser_reserved_connections",
572                 "syslog",
573                 "syslog_facility",
574                 "syslog_ident",
575                 "tcpip_socket",
576                 "TimeZone",
577                 "trace_notify",
578                 "transform_null_equals",
579                 "unix_socket_directory",
580                 "unix_socket_group",
581                 "unix_socket_permissions",
582                 "vacuum_mem",
583                 "wal_buffers",
584                 "wal_debug",
585                 "wal_sync_method",
586                 NULL
587         };
588
589         static char *backslash_commands[] = {
590                 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright", 
591                 "\\d",  "\\da", "\\dc", "\\dC", "\\dd", "\\dD", "\\df", "\\di",
592                 "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT", 
593                 "\\dv", "\\du",
594                 "\\e", "\\echo", "\\encoding",
595                 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
596                 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
597                 "\\o", "\\p", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
598                 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
599         };
600
601         (void) end;                                     /* not used */
602
603 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
604         rl_completion_append_character = ' ';
605 #endif
606
607         /* Clear a few things. */
608         completion_charp = NULL;
609         completion_charpp = NULL;
610         completion_info_charp = NULL;
611
612         /*
613          * Scan the input line before our current position for the last four
614          * words. According to those we'll make some smart decisions on what
615          * the user is probably intending to type. TODO: Use strtokx() to do
616          * this.
617          */
618         prev_wd = previous_word(start, 0);
619         prev2_wd = previous_word(start, 1);
620         prev3_wd = previous_word(start, 2);
621         prev4_wd = previous_word(start, 3);
622
623         /* If a backslash command was started, continue */
624         if (text[0] == '\\')
625                 COMPLETE_WITH_LIST(backslash_commands);
626
627         /* If no previous word, suggest one of the basic sql commands */
628         else if (!prev_wd)
629                 COMPLETE_WITH_LIST(sql_commands);
630
631 /* CREATE or DROP but not ALTER TABLE sth DROP */
632         /* complete with something you can create or drop */
633         else if (strcasecmp(prev_wd, "CREATE") == 0 || 
634                          (strcasecmp(prev_wd, "DROP") == 0 &&
635                           strcasecmp(prev3_wd,"TABLE") != 0 ))
636         matches = completion_matches(text, create_command_generator);
637
638 /* ALTER */
639     /* complete with what you can alter (TABLE, GROUP, USER, ...) 
640      * unless we're in ALTER TABLE sth ALTER*/
641     else if (strcasecmp(prev_wd, "ALTER") == 0  &&
642                          strcasecmp(prev3_wd, "TABLE") != 0 )
643         {
644                 char       *list_ALTER[] = {"DATABASE", "GROUP", "SCHEMA", "TABLE",
645                                                                         "TRIGGER", "USER", NULL};
646
647                 COMPLETE_WITH_LIST(list_ALTER);
648         }
649
650         /* ALTER DATABASE <name> */
651         else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
652                          strcasecmp(prev2_wd, "DATABASE") == 0)
653         {
654                 char       *list_ALTERDATABASE[] = {"RESET", "SET", NULL};
655
656                 COMPLETE_WITH_LIST(list_ALTERDATABASE);
657         }
658         /* ALTER TRIGGER <name>, add ON */
659         else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
660                          strcasecmp(prev2_wd, "TRIGGER") == 0)
661                 COMPLETE_WITH_CONST("ON");
662
663         /*
664          * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
665          */
666         else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
667                          strcasecmp(prev3_wd, "TRIGGER") == 0 &&
668                          strcasecmp(prev_wd, "ON") == 0)
669                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
670
671         /*
672          * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
673          * RENAME, or OWNER
674          */
675         else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
676                          strcasecmp(prev2_wd, "TABLE") == 0)
677         {
678                 char       *list_ALTER2[] = {"ADD", "ALTER", "DROP", "RENAME",
679                                                                          "OWNER TO", NULL};
680
681                 COMPLETE_WITH_LIST(list_ALTER2);
682         }
683         /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
684         else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
685                          (strcasecmp(prev_wd, "ALTER") == 0 ||
686                           strcasecmp(prev_wd, "RENAME") == 0))
687                 COMPLETE_WITH_ATTR(prev2_wd);
688
689         /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
690         else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
691                          strcasecmp(prev_wd, "DROP")  == 0)
692         {
693                 char       *list_TABLEDROP[] = {"COLUMN", "CONSTRAINT", NULL};
694                 COMPLETE_WITH_LIST(list_TABLEDROP);
695         }
696         /* If we have TABLE <sth> DROP COLUMN, provide list of columns */
697         else if (strcasecmp(prev4_wd, "TABLE") == 0 &&
698                          strcasecmp(prev2_wd, "DROP") == 0 && 
699                          strcasecmp(prev_wd, "COLUMN") == 0)
700                 COMPLETE_WITH_ATTR(prev3_wd);
701
702         /* complete ALTER GROUP <foo> with ADD or DROP */
703         else if (strcasecmp(prev3_wd, "ALTER") == 0 &&
704                          strcasecmp(prev2_wd, "GROUP") == 0)
705         {
706                 char       *list_ALTERGROUP[] = {"ADD", "DROP", NULL};
707
708                 COMPLETE_WITH_LIST(list_ALTERGROUP);
709         }
710         /* complete ALTER GROUP <foo> ADD|DROP with USER */
711         else if (strcasecmp(prev4_wd, "ALTER") == 0 &&
712                          strcasecmp(prev3_wd, "GROUP") == 0 &&
713                          (strcasecmp(prev_wd, "ADD") == 0 ||
714                           strcasecmp(prev_wd, "DROP") == 0))
715                 COMPLETE_WITH_CONST("USER");
716         /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
717         else if (strcasecmp(prev4_wd, "GROUP") == 0 &&
718                          (strcasecmp(prev2_wd, "ADD") == 0 ||
719                           strcasecmp(prev2_wd, "DROP") == 0) &&
720                          strcasecmp(prev_wd, "USER") == 0)
721                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
722
723 /* ANALYZE */
724         /* If the previous word is ANALYZE, produce list of tables. */
725         else if (strcasecmp(prev_wd, "ANALYZE") == 0)
726                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
727         /* If we have ANALYZE <table>, complete with semicolon. */
728         else if (strcasecmp(prev2_wd, "ANALYZE") == 0)
729                 COMPLETE_WITH_CONST(";");
730
731 /* CLUSTER */
732         /* If the previous word is CLUSTER, produce list of indexes. */
733         else if (strcasecmp(prev_wd, "CLUSTER") == 0)
734                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
735         /* If we have CLUSTER <sth>, then add "ON" */
736         else if (strcasecmp(prev2_wd, "CLUSTER") == 0)
737                 COMPLETE_WITH_CONST("ON");
738
739         /*
740          * If we have CLUSTER <sth> ON, then add the correct tablename as
741          * well.
742          */
743         else if (strcasecmp(prev3_wd, "CLUSTER") == 0 &&
744                          strcasecmp(prev_wd, "ON") == 0)
745         {
746                 char            query_buffer[BUF_SIZE];         /* Some room to build
747                                                                                                  * queries. */
748
749                 if (snprintf(query_buffer, BUF_SIZE,
750                                          "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)",
751                                          prev2_wd) == -1)
752                         ERROR_QUERY_TOO_LONG;
753                 else
754                         COMPLETE_WITH_QUERY(query_buffer);
755         }
756
757 /* COMMENT */
758         else if (strcasecmp(prev_wd, "COMMENT") == 0)
759                 COMPLETE_WITH_CONST("ON");
760         else if (strcasecmp(prev2_wd, "COMMENT") == 0 &&
761                          strcasecmp(prev_wd, "ON") == 0)
762         {
763                 char       *list_COMMENT[] =
764                 {"DATABASE", "INDEX", "RULE", "SCHEMA", "SEQUENCE", "TABLE",
765                  "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR",
766                  "TRIGGER", "CONSTRAINT", "DOMAIN", NULL};
767
768                 COMPLETE_WITH_LIST(list_COMMENT);
769         }
770         else if (strcasecmp(prev4_wd, "COMMENT") == 0 &&
771                          strcasecmp(prev3_wd, "ON") == 0)
772                 COMPLETE_WITH_CONST("IS");
773
774 /* COPY */
775
776         /*
777          * If we have COPY [BINARY] (which you'd have to type yourself), offer
778          * list of tables (Also cover the analogous backslash command)
779          */
780         else if (strcasecmp(prev_wd, "COPY") == 0 ||
781                          strcasecmp(prev_wd, "\\copy") == 0 ||
782                          (strcasecmp(prev2_wd, "COPY") == 0 &&
783                           strcasecmp(prev_wd, "BINARY") == 0))
784                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
785         /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
786         else if (strcasecmp(prev2_wd, "COPY") == 0 ||
787                          strcasecmp(prev2_wd, "\\copy") == 0 ||
788                          strcasecmp(prev2_wd, "BINARY") == 0)
789         {
790                 char       *list_FROMTO[] = {"FROM", "TO", NULL};
791
792                 COMPLETE_WITH_LIST(list_FROMTO);
793         }
794
795 /* CREATE INDEX */
796         /* First off we complete CREATE UNIQUE with "INDEX" */
797         else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
798                          strcasecmp(prev_wd, "UNIQUE") == 0)
799                 COMPLETE_WITH_CONST("INDEX");
800         /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
801         else if (strcasecmp(prev2_wd, "INDEX") == 0 &&
802                          (strcasecmp(prev3_wd, "CREATE") == 0 ||
803                           strcasecmp(prev3_wd, "UNIQUE") == 0))
804                 COMPLETE_WITH_CONST("ON");
805         /* Complete ... INDEX <name> ON with a list of tables  */
806         else if (strcasecmp(prev3_wd, "INDEX") == 0 &&
807                          strcasecmp(prev_wd, "ON") == 0)
808                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
809
810         /*
811          * Complete INDEX <name> ON <table> with a list of table columns
812          * (which should really be in parens)
813          */
814         else if (strcasecmp(prev4_wd, "INDEX") == 0 &&
815                          strcasecmp(prev2_wd, "ON") == 0)
816                 COMPLETE_WITH_ATTR(prev_wd);
817         /* same if you put in USING */
818         else if (strcasecmp(prev4_wd, "ON") == 0 &&
819                          strcasecmp(prev2_wd, "USING") == 0)
820                 COMPLETE_WITH_ATTR(prev3_wd);
821         /* Complete USING with an index method */
822         else if (strcasecmp(prev_wd, "USING") == 0)
823         {
824                 char       *index_mth[] = {"BTREE", "RTREE", "HASH", "GIST", NULL};
825
826                 COMPLETE_WITH_LIST(index_mth);
827         }
828
829 /* CREATE RULE */
830         /* Complete "CREATE RULE <sth>" with "AS" */
831         else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
832                          strcasecmp(prev2_wd, "RULE") == 0)
833                 COMPLETE_WITH_CONST("AS");
834         /* Complete "CREATE RULE <sth> AS with "ON" */
835         else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
836                          strcasecmp(prev3_wd, "RULE") == 0 &&
837                          strcasecmp(prev_wd, "AS") == 0)
838                 COMPLETE_WITH_CONST("ON");
839         /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
840         else if (strcasecmp(prev4_wd, "RULE") == 0 &&
841                          strcasecmp(prev2_wd, "AS") == 0 &&
842                          strcasecmp(prev_wd, "ON") == 0)
843         {
844                 char       *rule_events[] = {"SELECT", "UPDATE", "INSERT",
845                                                                          "DELETE", NULL};
846
847                 COMPLETE_WITH_LIST(rule_events);
848         }
849         /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
850         else if (strcasecmp(prev3_wd, "AS") == 0 &&
851                          strcasecmp(prev2_wd, "ON") == 0 &&
852                          (toupper((unsigned char) prev_wd[4]) == 'T' ||
853                           toupper((unsigned char) prev_wd[5]) == 'T'))
854                 COMPLETE_WITH_CONST("TO");
855         /* Complete "AS ON <sth> TO" with a table name */
856         else if (strcasecmp(prev4_wd, "AS") == 0 &&
857                          strcasecmp(prev3_wd, "ON") == 0 &&
858                          strcasecmp(prev_wd, "TO") == 0)
859                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
860
861 /* CREATE TABLE */
862         /* Complete CREATE TEMP with "TABLE" */
863         else if (strcasecmp(prev2_wd, "CREATE") == 0 &&
864                          strcasecmp(prev_wd, "TEMP") == 0)
865                 COMPLETE_WITH_CONST("TABLE");
866
867 /* CREATE TRIGGER */
868         /* is on the agenda . . . */
869
870 /* CREATE VIEW */
871         /* Complete "CREATE VIEW <name>" with "AS" */
872         else if (strcasecmp(prev3_wd, "CREATE") == 0 &&
873                          strcasecmp(prev2_wd, "VIEW") == 0)
874                 COMPLETE_WITH_CONST("AS");
875         /* Complete "CREATE VIEW <sth> AS with "SELECT" */
876         else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
877                          strcasecmp(prev3_wd, "VIEW") == 0 &&
878                          strcasecmp(prev_wd, "AS") == 0)
879                 COMPLETE_WITH_CONST("SELECT");
880
881 /* DELETE */
882
883         /*
884          * Complete DELETE with FROM (only if the word before that is not "ON"
885          * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
886          */
887         else if (strcasecmp(prev_wd, "DELETE") == 0 &&
888                          !(strcasecmp(prev2_wd, "ON") == 0 ||
889                            strcasecmp(prev2_wd, "GRANT") == 0 ||
890                            strcasecmp(prev2_wd, "BEFORE") == 0 ||
891                            strcasecmp(prev2_wd, "AFTER") == 0))
892                 COMPLETE_WITH_CONST("FROM");
893         /* Complete DELETE FROM with a list of tables */
894         else if (strcasecmp(prev2_wd, "DELETE") == 0 &&
895                          strcasecmp(prev_wd, "FROM") == 0)
896                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
897         /* Complete DELETE FROM <table> with "WHERE" (perhaps a safe idea?) */
898         else if (strcasecmp(prev3_wd, "DELETE") == 0 &&
899                          strcasecmp(prev2_wd, "FROM") == 0)
900                 COMPLETE_WITH_CONST("WHERE");
901
902 /* EXPLAIN */
903
904         /*
905          * Complete EXPLAIN [VERBOSE] (which you'd have to type yourself) with
906          * the list of SQL commands
907          */
908         else if (strcasecmp(prev_wd, "EXPLAIN") == 0 ||
909                          (strcasecmp(prev2_wd, "EXPLAIN") == 0 &&
910                           strcasecmp(prev_wd, "VERBOSE") == 0))
911                 COMPLETE_WITH_LIST(sql_commands);
912
913 /* FETCH && MOVE */
914         /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
915         else if (strcasecmp(prev_wd, "FETCH") == 0 ||
916                          strcasecmp(prev_wd, "MOVE") == 0)
917         {
918                 char       *list_FETCH1[] = {"FORWARD", "BACKWARD", "RELATIVE", NULL};
919
920                 COMPLETE_WITH_LIST(list_FETCH1);
921         }
922         /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
923         else if (strcasecmp(prev2_wd, "FETCH") == 0 ||
924                          strcasecmp(prev2_wd, "MOVE") == 0)
925         {
926                 char       *list_FETCH2[] = {"ALL", "NEXT", "PRIOR", NULL};
927
928                 COMPLETE_WITH_LIST(list_FETCH2);
929         }
930
931         /*
932          * Complete FETCH <sth1> <sth2> with "FROM" or "TO". (Is there a
933          * difference? If not, remove one.)
934          */
935         else if (strcasecmp(prev3_wd, "FETCH") == 0 ||
936                          strcasecmp(prev3_wd, "MOVE") == 0)
937         {
938                 char       *list_FROMTO[] = {"FROM", "TO", NULL};
939
940                 COMPLETE_WITH_LIST(list_FROMTO);
941         }
942
943 /* GRANT && REVOKE*/
944         /* Complete GRANT/REVOKE with a list of privileges */
945         else if (strcasecmp(prev_wd, "GRANT") == 0 ||
946                          strcasecmp(prev_wd, "REVOKE") == 0)
947         {
948                 char       *list_privileg[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES", "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
949
950                 COMPLETE_WITH_LIST(list_privileg);
951         }
952         /* Complete GRANT/REVOKE <sth> with "ON" */
953         else if (strcasecmp(prev2_wd, "GRANT") == 0 ||
954                          strcasecmp(prev2_wd, "REVOKE") == 0)
955                 COMPLETE_WITH_CONST("ON");
956
957         /*
958          * Complete GRANT/REVOKE <sth> ON with a list of tables, views,
959          * sequences, and indexes
960          *
961          * keywords DATABASE, FUNCTION, LANGUAGE, SCHEMA added to query result
962      * via UNION; seems to work intuitively
963      *
964      * Note: GRANT/REVOKE can get quite complex; tab-completion as implemented
965      * here will only work if the privilege list contains exactly one privilege
966          */
967         else if ((strcasecmp(prev3_wd, "GRANT") == 0 ||
968                           strcasecmp(prev3_wd, "REVOKE") == 0) &&
969                          strcasecmp(prev_wd, "ON") == 0)
970                 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
971                                                         " WHERE relkind in ('r','S','v')  "
972                                                         "   AND substr(relname,1,%d)='%s' "
973                             "   AND pg_catalog.pg_table_is_visible(c.oid) "
974                                                         "   AND relnamespace = n.oid "
975                                                         "   AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
976                             " UNION "
977                             "SELECT 'DATABASE' AS relname "
978                             " UNION "
979                             "SELECT 'FUNCTION' AS relname "
980                             " UNION "
981                             "SELECT 'LANGUAGE' AS relname "
982                             " UNION "
983                             "SELECT 'SCHEMA' AS relname ");
984
985         /* Complete "GRANT/REVOKE * ON * " with "TO" */
986         else if ((strcasecmp(prev4_wd, "GRANT") == 0 || 
987                           strcasecmp(prev4_wd, "REVOKE") == 0) &&
988                          strcasecmp(prev2_wd, "ON") == 0)
989         {
990                 if(strcasecmp(prev_wd, "DATABASE") == 0)
991                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
992                 else if(strcasecmp(prev_wd, "FUNCTION") == 0)
993                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
994                 else if(strcasecmp(prev_wd, "LANGUAGE") == 0)
995                         COMPLETE_WITH_QUERY(Query_for_list_of_languages);
996                 else if(strcasecmp(prev_wd, "SCHEMA") == 0)
997                         COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
998                 else
999                         COMPLETE_WITH_CONST("TO");
1000         }
1001
1002         /*
1003          * TODO: to complete with user name we need prev5_wd -- wait for a
1004          * more general solution there
1005      * same for GRANT <sth> ON { DATABASE | FUNCTION | LANGUAGE | SCHEMA } xxx TO
1006          */
1007
1008 /* INSERT */
1009         /* Complete INSERT with "INTO" */
1010         else if (strcasecmp(prev_wd, "INSERT") == 0)
1011                 COMPLETE_WITH_CONST("INTO");
1012         /* Complete INSERT INTO with table names */
1013         else if (strcasecmp(prev2_wd, "INSERT") == 0 &&
1014                          strcasecmp(prev_wd, "INTO") == 0)
1015                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1016         /* Complete "INSERT INTO <table> (" with attribute names */
1017         else if (rl_line_buffer[start - 1] == '(' &&
1018                          strcasecmp(prev3_wd, "INSERT") == 0 &&
1019                          strcasecmp(prev2_wd, "INTO") == 0)
1020                 COMPLETE_WITH_ATTR(prev_wd);
1021
1022         /*
1023          * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
1024          * VALUES"
1025          */
1026         else if (strcasecmp(prev3_wd, "INSERT") == 0 &&
1027                          strcasecmp(prev2_wd, "INTO") == 0)
1028         {
1029                 char       *list_INSERT[] = {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
1030
1031                 COMPLETE_WITH_LIST(list_INSERT);
1032         }
1033         /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
1034         else if (strcasecmp(prev4_wd, "INSERT") == 0 &&
1035                          strcasecmp(prev3_wd, "INTO") == 0 &&
1036                          prev_wd[strlen(prev_wd) - 1] == ')')
1037         {
1038                 char       *list_INSERT[] = {"SELECT", "VALUES", NULL};
1039
1040                 COMPLETE_WITH_LIST(list_INSERT);
1041         }
1042
1043         /* Insert an open parenthesis after "VALUES" */
1044         else if (strcasecmp(prev_wd, "VALUES") == 0 &&
1045                          strcasecmp(prev2_wd, "DEFAULT") != 0)
1046                 COMPLETE_WITH_CONST("(");
1047
1048 /* LOCK */
1049         /* Complete LOCK [TABLE] with a list of tables */
1050         else if (strcasecmp(prev_wd, "LOCK") == 0 ||
1051                          (strcasecmp(prev_wd, "TABLE") == 0 &&
1052                           strcasecmp(prev2_wd, "LOCK") == 0))
1053                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1054
1055         /* For the following, handle the case of a single table only for now */
1056
1057         /* Complete LOCK [TABLE] <table> with "IN" */
1058         else if ((strcasecmp(prev2_wd, "LOCK") == 0 &&
1059                           strcasecmp(prev_wd, "TABLE")) ||
1060                          (strcasecmp(prev2_wd, "TABLE") == 0 &&
1061                           strcasecmp(prev3_wd, "LOCK") == 0))
1062                 COMPLETE_WITH_CONST("IN");
1063
1064         /* Complete LOCK [TABLE] <table> IN with a lock mode */
1065         else if (strcasecmp(prev_wd, "IN") == 0 &&
1066                          (strcasecmp(prev3_wd, "LOCK") == 0 ||
1067                           (strcasecmp(prev3_wd, "TABLE") == 0 &&
1068                            strcasecmp(prev4_wd, "LOCK") == 0)))
1069         {
1070                 char       *lock_modes[] = {"ACCESS SHARE MODE",
1071                         "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
1072                         "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE",
1073                         "SHARE ROW EXCLUSIVE MODE",
1074                         "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
1075
1076                 COMPLETE_WITH_LIST(lock_modes);
1077         }
1078
1079 /* NOTIFY */
1080         else if (strcasecmp(prev_wd, "NOTIFY") == 0)
1081                 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s'");
1082
1083 /* REINDEX */
1084         else if (strcasecmp(prev_wd, "REINDEX") == 0)
1085         {
1086                 char       *list_REINDEX[] = {"TABLE", "DATABASE", "INDEX", NULL};
1087
1088                 COMPLETE_WITH_LIST(list_REINDEX);
1089         }
1090         else if (strcasecmp(prev2_wd, "REINDEX") == 0)
1091         {
1092                 if (strcasecmp(prev_wd, "TABLE") == 0)
1093                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1094                 else if (strcasecmp(prev_wd, "DATABASE") == 0)
1095                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1096                 else if (strcasecmp(prev_wd, "INDEX") == 0)
1097                         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1098         }
1099
1100 /* SELECT */
1101         /* naah . . . */
1102
1103 /* SET, RESET, SHOW */
1104         /* Complete with a variable name */
1105         else if ((strcasecmp(prev_wd, "SET") == 0 &&
1106                           strcasecmp(prev3_wd, "UPDATE") != 0) ||
1107                          strcasecmp(prev_wd, "RESET") == 0 ||
1108                          strcasecmp(prev_wd, "SHOW") == 0)
1109                 COMPLETE_WITH_LIST(pgsql_variables);
1110         /* Complete "SET TRANSACTION" */
1111         else if ((strcasecmp(prev2_wd, "SET") == 0 &&
1112                           strcasecmp(prev_wd, "TRANSACTION") == 0) ||
1113                          (strcasecmp(prev4_wd, "SESSION") == 0 &&
1114                           strcasecmp(prev3_wd, "CHARACTERISTICS") == 0 &&
1115                           strcasecmp(prev2_wd, "AS") == 0 &&
1116                           strcasecmp(prev_wd, "TRANSACTION") == 0))
1117         {
1118                 char       *my_list[] = {"ISOLATION", "READ", NULL};
1119
1120                 COMPLETE_WITH_LIST(my_list);
1121         }
1122         else if (strcasecmp(prev3_wd, "SET") == 0 &&
1123                          strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1124                          strcasecmp(prev_wd, "ISOLATION") == 0)
1125                 COMPLETE_WITH_CONST("LEVEL");
1126         else if ((strcasecmp(prev4_wd, "SET") == 0 ||
1127                           strcasecmp(prev4_wd, "AS") == 0) &&
1128                          strcasecmp(prev3_wd, "TRANSACTION") == 0 &&
1129                          strcasecmp(prev2_wd, "ISOLATION") == 0 &&
1130                          strcasecmp(prev_wd, "LEVEL") == 0)
1131         {
1132                 char       *my_list[] = {"READ", "SERIALIZABLE", NULL};
1133
1134                 COMPLETE_WITH_LIST(my_list);
1135         }
1136         else if (strcasecmp(prev4_wd, "TRANSACTION") == 0 &&
1137                          strcasecmp(prev3_wd, "ISOLATION") == 0 &&
1138                          strcasecmp(prev2_wd, "LEVEL") == 0 &&
1139                          strcasecmp(prev_wd, "READ") == 0)
1140                 COMPLETE_WITH_CONST("COMMITTED");
1141         else if ((strcasecmp(prev3_wd, "SET") == 0 ||
1142                           strcasecmp(prev3_wd, "AS") == 0) &&
1143                          strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
1144                          strcasecmp(prev_wd, "READ") == 0)
1145         {
1146                 char       *my_list[] = {"ONLY", "WRITE", NULL};
1147
1148                 COMPLETE_WITH_LIST(my_list);
1149         }
1150         /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
1151         else if (strcasecmp(prev3_wd, "SET") == 0 &&
1152                          strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
1153         {
1154                 char       *constraint_list[] = {"DEFERRED", "IMMEDIATE", NULL};
1155
1156                 COMPLETE_WITH_LIST(constraint_list);
1157         }
1158         /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
1159         else if (strcasecmp(prev2_wd, "SET") == 0 &&
1160                          strcasecmp(prev_wd, "SESSION") == 0)
1161         {
1162                 char       *my_list[] = {"AUTHORIZATION",
1163                         "CHARACTERISTICS AS TRANSACTION",
1164                 NULL};
1165
1166                 COMPLETE_WITH_LIST(my_list);
1167         }
1168         /* Complete SET SESSION AUTHORIZATION with username */
1169         else if (strcasecmp(prev3_wd, "SET") == 0
1170                          && strcasecmp(prev2_wd, "SESSION") == 0
1171                          && strcasecmp(prev_wd, "AUTHORIZATION") == 0)
1172                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1173         /* Complete SET <var> with "TO" */
1174         else if (strcasecmp(prev2_wd, "SET") == 0 &&
1175                          strcasecmp(prev4_wd, "UPDATE") != 0)
1176                 COMPLETE_WITH_CONST("TO");
1177         /* Suggest possible variable values */
1178         else if (strcasecmp(prev3_wd, "SET") == 0 &&
1179                    (strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
1180         {
1181                 if (strcasecmp(prev2_wd, "DateStyle") == 0)
1182                 {
1183                         char       *my_list[] = {"'ISO'", "'SQL'", "'Postgres'",
1184                         "'European'", "'NonEuropean'", "'German'", "DEFAULT", NULL};
1185
1186                         COMPLETE_WITH_LIST(my_list);
1187                 }
1188                 else if (strcasecmp(prev2_wd, "GEQO") == 0)
1189                 {
1190                         char       *my_list[] = {"ON", "OFF", "DEFAULT", NULL};
1191
1192                         COMPLETE_WITH_LIST(my_list);
1193                 }
1194                 else
1195                 {
1196                         char       *my_list[] = {"DEFAULT", NULL};
1197
1198                         COMPLETE_WITH_LIST(my_list);
1199                 }
1200         }
1201
1202 /* TRUNCATE */
1203         else if (strcasecmp(prev_wd, "TRUNCATE") == 0)
1204                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1205
1206 /* UNLISTEN */
1207         else if (strcasecmp(prev_wd, "UNLISTEN") == 0)
1208                 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s' UNION SELECT '*'::name");
1209
1210 /* UPDATE */
1211         /* If prev. word is UPDATE suggest a list of tables */
1212         else if (strcasecmp(prev_wd, "UPDATE") == 0)
1213                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1214         /* Complete UPDATE <table> with "SET" */
1215         else if (strcasecmp(prev2_wd, "UPDATE") == 0)
1216                 COMPLETE_WITH_CONST("SET");
1217
1218         /*
1219          * If the previous word is SET (and it wasn't caught above as the
1220          * _first_ word) the word before it was (hopefully) a table name and
1221          * we'll now make a list of attributes.
1222          */
1223         else if (strcasecmp(prev_wd, "SET") == 0)
1224                 COMPLETE_WITH_ATTR(prev2_wd);
1225
1226 /* VACUUM */
1227         else if (strcasecmp(prev_wd, "VACUUM") == 0)
1228                 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");
1229         else if (strcasecmp(prev2_wd, "VACUUM") == 0 &&
1230                          (strcasecmp(prev_wd, "FULL") == 0 ||
1231                           strcasecmp(prev_wd, "ANALYZE") == 0))
1232                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1233
1234 /* WHERE */
1235         /* Simple case of the word before the where being the table name */
1236         else if (strcasecmp(prev_wd, "WHERE") == 0)
1237                 COMPLETE_WITH_ATTR(prev2_wd);
1238
1239 /* ... FROM ... */
1240 /* TODO: also include SRF ? */
1241         else if (strcasecmp(prev_wd, "FROM") == 0)
1242                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1243
1244
1245 /* Backslash commands */
1246 /* TODO:  \dc \dd \dl */
1247         else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
1248                 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
1249         else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0)
1250                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv);
1251         else if (strcmp(prev_wd, "\\da") == 0)
1252                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates);
1253         else if (strcmp(prev_wd, "\\dD") == 0)
1254                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains);
1255         else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
1256                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions);
1257         else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0)
1258                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
1259         else if (strcmp(prev_wd, "\\dn") == 0)
1260                 COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
1261         else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0)
1262                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv);
1263         else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0)
1264                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences);
1265         else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0)
1266                 COMPLETE_WITH_QUERY(Query_for_list_of_system_relations);
1267         else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0)
1268                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
1269         else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
1270                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes);
1271         else if (strcmp(prev_wd, "\\du") == 0)
1272                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
1273         else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
1274                 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
1275         else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
1276                 COMPLETE_WITH_LIST(sql_commands);
1277         else if (strcmp(prev_wd, "\\pset") == 0)
1278         {
1279                 char       *my_list[] = {"format", "border", "expanded",
1280                         "null", "fieldsep", "tuples_only", "title", "tableattr", "pager",
1281                         "recordsep", NULL};
1282
1283                 COMPLETE_WITH_LIST(my_list);
1284         }
1285         else if (strcmp(prev_wd, "\\cd") == 0 ||
1286                  strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
1287                          strcmp(prev_wd, "\\g") == 0 ||
1288                          strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
1289                   strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
1290                          strcmp(prev_wd, "\\s") == 0 ||
1291                    strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
1292                 )
1293                 matches = completion_matches(text, filename_completion_function);
1294
1295
1296         /*
1297          * Finally, we look through the list of "things", such as TABLE, INDEX
1298          * and check if that was the previous word. If so, execute the query
1299          * to get a list of them.
1300          */
1301         else
1302         {
1303                 int                     i;
1304
1305                 for (i = 0; words_after_create[i].name; i++)
1306                         if (strcasecmp(prev_wd, words_after_create[i].name) == 0)
1307                         {
1308                                 if(words_after_create[i].with_schema == WITH_SCHEMA)
1309                                         COMPLETE_WITH_SCHEMA_QUERY(words_after_create[i].query);
1310                                 else
1311                                         COMPLETE_WITH_QUERY(words_after_create[i].query);
1312                                 break;
1313                         }
1314         }
1315
1316
1317         /*
1318          * If we still don't have anything to match we have to fabricate some
1319          * sort of default list. If we were to just return NULL, readline
1320          * automatically attempts filename completion, and that's usually no
1321          * good.
1322          */
1323         if (matches == NULL)
1324         {
1325                 COMPLETE_WITH_CONST("");
1326 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
1327                 rl_completion_append_character = '\0';
1328 #endif
1329         }
1330
1331
1332         /* free storage */
1333         free(prev_wd);
1334         free(prev2_wd);
1335         free(prev3_wd);
1336         free(prev4_wd);
1337
1338         /* Return our Grand List O' Matches */
1339         return matches;
1340 }
1341
1342
1343
1344 /* GENERATOR FUNCTIONS
1345
1346    These functions do all the actual work of completing the input. They get
1347    passed the text so far and the count how many times they have been called so
1348    far with the same text.
1349    If you read the above carefully, you'll see that these don't get called
1350    directly but through the readline interface.
1351    The return value is expected to be the full completion of the text, going
1352    through a list each time, or NULL if there are no more matches. The string
1353    will be free()'d be readline, so you must run it through strdup() or
1354    something of that sort.
1355 */
1356
1357 /* This one gives you one from a list of things you can put after CREATE or DROP
1358    as defined above.
1359 */
1360 static char *
1361 create_command_generator(const char *text, int state)
1362 {
1363         static int      list_index,
1364                                 string_length;
1365         char       *name;
1366
1367         /* If this is the first time for this completion, init some values */
1368         if (state == 0)
1369         {
1370                 list_index = 0;
1371                 string_length = strlen(text);
1372         }
1373
1374         /* find something that matches */
1375         while ((name = words_after_create[list_index++].name))
1376                 if (strncasecmp(name, text, string_length) == 0)
1377                         return xstrdup(name);
1378
1379         /* if nothing matches, return NULL */
1380         return NULL;
1381 }
1382
1383
1384 /* The following two functions are wrappers for _complete_from_query */
1385
1386 static char *
1387 complete_from_query(const char *text, int state)
1388 {
1389   return _complete_from_query(0, text, state);
1390 }
1391
1392 static char *
1393 complete_from_schema_query(const char *text, int state)
1394 {
1395   return _complete_from_query(1, text, state);
1396 }
1397
1398
1399 /* This creates a list of matching things, according to a query pointed to
1400    by completion_charp.
1401    The query can be one of two kinds:
1402    - A simple query which must contain a %d and a %s, which will be replaced 
1403    by the string length of the text and the text itself. The query may also
1404    have another %s in it, which will be replaced by the value of 
1405    completion_info_charp.
1406      or:
1407    - A schema query used for completion of both schema and relation names;
1408    these are more complex and must contain in the following order:
1409      %d %s %d %s %d %s %s %d %s
1410    where %d is the string length of the text and %s the text itself.
1411
1412    See top of file for examples of both kinds of query.
1413 */
1414
1415 static char *
1416 _complete_from_query(int is_schema_query, const char *text, int state)
1417 {
1418         static int      list_index,
1419                                 string_length;
1420         static PGresult *result = NULL;
1421         char            query_buffer[BUF_SIZE];
1422         const char *item;
1423
1424         /*
1425          * If this is the first time for this completion, we fetch a list of
1426          * our "things" from the backend.
1427          */
1428         if (state == 0)
1429         {
1430                 list_index = 0;
1431                 string_length = strlen(text);
1432
1433                 /* Need to have a query */
1434                 if (completion_charp == NULL)
1435                         return NULL;
1436
1437                 if(is_schema_query)
1438                 {
1439                   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)
1440                   {
1441                       ERROR_QUERY_TOO_LONG;
1442                       return NULL;
1443                   }
1444                 }
1445                 else {
1446                   if (snprintf(query_buffer, BUF_SIZE, completion_charp, string_length, text, completion_info_charp) == -1)
1447                     {
1448                       ERROR_QUERY_TOO_LONG;
1449                       return NULL;
1450                     }
1451                 }
1452
1453                 result = exec_query(query_buffer);
1454         }
1455
1456         /* Find something that matches */
1457         if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
1458                 while (list_index < PQntuples(result) &&
1459                            (item = PQgetvalue(result, list_index++, 0)))
1460                         if (strncasecmp(text, item, string_length) == 0)
1461                                 return xstrdup(item);
1462
1463         /* If nothing matches, free the db structure and return null */
1464         PQclear(result);
1465         result = NULL;
1466         return NULL;
1467 }
1468
1469
1470 /* This function returns in order one of a fixed, NULL pointer terminated list
1471    of strings (if matching). This can be used if there are only a fixed number
1472    SQL words that can appear at certain spot.
1473 */
1474 static char *
1475 complete_from_list(const char *text, int state)
1476 {
1477         static int      string_length,
1478                                 list_index,
1479                                 matches;
1480         static bool     casesensitive;
1481         char       *item;
1482
1483         /* need to have a list */
1484 #ifdef USE_ASSERT_CHECKING
1485         assert(completion_charpp);
1486 #endif
1487
1488         /* Initialization */
1489         if (state == 0)
1490         {
1491                 list_index = 0;
1492                 string_length = strlen(text);
1493                 casesensitive = true;
1494                 matches = 0;
1495         }
1496
1497         while ((item = completion_charpp[list_index++]))
1498         {
1499                 /* First pass is case sensitive */
1500                 if (casesensitive && strncmp(text, item, string_length) == 0)
1501                 {
1502                         matches++;
1503                         return xstrdup(item);
1504                 }
1505
1506                 /* Second pass is case insensitive, don't bother counting matches */
1507                 if (!casesensitive && strncasecmp(text, item, string_length) == 0)
1508                         return xstrdup(item);
1509         }
1510
1511         /*
1512          * No matches found. If we're not case insensitive already, lets switch
1513          * to being case insensitive and try again
1514          */
1515         if (casesensitive && matches == 0)
1516         {
1517                 casesensitive = false;
1518                 list_index = 0;
1519                 state++;
1520                 return (complete_from_list(text, state));
1521         }
1522
1523         /* If no more matches, return null. */
1524         return NULL;
1525 }
1526
1527
1528 /* This function returns one fixed string the first time even if it doesn't
1529    match what's there, and nothing the second time. This should be used if there
1530    is only one possibility that can appear at a certain spot, so misspellings
1531    will be overwritten.
1532    The string to be passed must be in completion_charp.
1533 */
1534 static char *
1535 complete_from_const(const char *text, int state)
1536 {
1537         (void) text;                            /* We don't care about what was entered
1538                                                                  * already. */
1539
1540 #ifdef USE_ASSERT_CHECKING
1541         assert(completion_charp);
1542 #endif
1543         if (state == 0)
1544                 return xstrdup(completion_charp);
1545         else
1546                 return NULL;
1547 }
1548
1549
1550
1551 /* HELPER FUNCTIONS */
1552
1553
1554 /* Execute a query and report any errors. This should be the preferred way of
1555    talking to the database in this file.
1556    Note that the query passed in here must not have a semicolon at the end
1557    because we need to append LIMIT xxx.
1558 */
1559 static PGresult *
1560 exec_query(char *query)
1561 {
1562         PGresult   *result;
1563         char            query_buffer[BUF_SIZE];
1564
1565         if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
1566                 return NULL;
1567 #ifdef USE_ASSERT_CHECKING
1568         assert(query[strlen(query) - 1] != ';');
1569 #endif
1570
1571         if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d;", query, completion_max_records) == -1)
1572         {
1573                 ERROR_QUERY_TOO_LONG;
1574                 return NULL;
1575         }
1576
1577         result = PQexec(pset.db, query);
1578
1579         if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
1580         {
1581 #if 0
1582                 psql_error("tab completion: %s failed - %s\n",
1583                                    query, PQresStatus(PQresultStatus(result)));
1584 #endif
1585                 PQclear(result);
1586                 result = NULL;
1587         }
1588
1589         return result;
1590 }
1591
1592
1593
1594 /* Return the word (space delimited) before point. Set skip > 0 to skip that
1595    many words; e.g. skip=1 finds the word before the previous one.
1596 */
1597 static char *
1598 previous_word(int point, int skip)
1599 {
1600         int                     i,
1601                                 start = 0,
1602                                 end = -1,
1603                                 inquotes = 0;
1604         char       *s;
1605
1606         while (skip-- >= 0)
1607         {
1608                 /* first we look for a space before the current word */
1609                 for (i = point; i >= 0; i--)
1610                         if (rl_line_buffer[i] == ' ')
1611                                 break;
1612
1613                 /* now find the first non-space which then constitutes the end */
1614                 for (; i >= 0; i--)
1615                         if (rl_line_buffer[i] != ' ')
1616                         {
1617                                 end = i;
1618                                 break;
1619                         }
1620
1621                 /*
1622                  * If no end found we return null, because there is no word before
1623                  * the point
1624                  */
1625                 if (end == -1)
1626                         return NULL;
1627
1628                 /*
1629                  * Otherwise we now look for the start. The start is either the
1630                  * last character before any space going backwards from the end,
1631                  * or it's simply character 0
1632                  */
1633                 for (start = end; start > 0; start--)
1634                 {
1635                         if (rl_line_buffer[start] == '"')
1636                                 inquotes = !inquotes;
1637                         if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
1638                                 break;
1639                 }
1640
1641                 point = start;
1642         }
1643
1644         /* make a copy */
1645         s = (char *) malloc(end - start + 2);
1646         if (!s)
1647         {
1648                 psql_error("out of memory\n");
1649                 if (!pset.cur_cmd_interactive)
1650                         exit(EXIT_FAILURE);
1651                 else
1652                         return NULL;
1653         }
1654
1655         strncpy(s, &rl_line_buffer[start], end - start + 1);
1656         s[end - start + 1] = '\0';
1657
1658         return s;
1659 }
1660
1661
1662
1663 #if 0
1664
1665 /*
1666  * Surround a string with single quotes. This works for both SQL and
1667  * psql internal. Currently disable because it is reported not to
1668  * cooperate with certain versions of readline.
1669  */
1670 char *
1671 quote_file_name(char *text, int match_type, char *quote_pointer)
1672 {
1673         char       *s;
1674         size_t          length;
1675
1676         (void) quote_pointer;           /* not used */
1677
1678         length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
1679         s = malloc(length);
1680         s[0] = '\'';
1681         strcpy(s + 1, text);
1682         if (match_type == SINGLE_MATCH)
1683                 s[length - 2] = '\'';
1684         s[length - 1] = '\0';
1685         return s;
1686 }
1687
1688
1689
1690 static char *
1691 dequote_file_name(char *text, char quote_char)
1692 {
1693         char       *s;
1694         size_t          length;
1695
1696         if (!quote_char)
1697                 return xstrdup(text);
1698
1699         length = strlen(text);
1700         s = malloc(length - 2 + 1);
1701         strncpy(s, text +1, length - 2);
1702         s[length] = '\0';
1703
1704         return s;
1705 }
1706 #endif   /* 0 */
1707
1708 #endif   /* USE_READLINE */