]> granicus.if.org Git - postgresql/blob - src/bin/psql/tab-complete.c
Finish implementation of hashed aggregation. Add enable_hashagg GUC
[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.69 2002/11/21 00:42:19 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(x, y) rl_completion_matches((x), ((rl_compentry_func_t *)(y)))
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(char *text, int state);
80 static char *complete_from_query(char *text, int state);
81 static char *complete_from_const(char *text, int state);
82 static char *complete_from_list(char *text, int state);
83
84 static PGresult *exec_query(char *query);
85 char       *quote_file_name(char *text, int match_type, char *quote_pointer);
86
87 /*static char * dequote_file_name(char *text, char quote_char);*/
88 static char *previous_word(int point, int skip);
89
90 /* These variables are used to pass information into the completion functions.
91    Realizing that this is the cardinal sin of programming, I don't see a better
92    way. */
93 char       *completion_charp;   /* if you need to pass a string */
94 char      **completion_charpp;  /* if you need to pass a list of strings */
95 char       *completion_info_charp;              /* if you need to pass another
96                                                                                  * string */
97
98 /* Store how many records from a database query we want to return at most
99 (implemented via SELECT ... LIMIT xx). */
100 static int      completion_max_records;
101
102
103 /* Initialize the readline library for our purposes. */
104 void
105 initialize_readline(void)
106 {
107         rl_readline_name = pset.progname;
108         rl_attempted_completion_function = (void *) psql_completion;
109
110         rl_basic_word_break_characters = "\t\n@$><=;|&{( ";
111
112         completion_max_records = 100;
113
114         /*
115          * There is a variable rl_completion_query_items for this but
116          * apparently it's not defined everywhere.
117          */
118 }
119
120
121 /*
122  * Queries to get lists of names of various kinds of things, possibly
123  * restricted to names matching a partially entered name.  In these queries,
124  * the %s will be replaced by the text entered so far, the %d by its length.
125  */
126
127 #define Query_for_list_of_tables "SELECT relname FROM pg_catalog.pg_class WHERE (relkind='r' or relkind='v') and substr(relname,1,%d)='%s' and pg_catalog.pg_table_is_visible(oid)"
128 #define Query_for_list_of_indexes "SELECT relname FROM pg_catalog.pg_class WHERE relkind='i' and substr(relname,1,%d)='%s' and pg_catalog.pg_table_is_visible(oid)"
129 #define Query_for_list_of_databases "SELECT datname FROM pg_catalog.pg_database WHERE substr(datname,1,%d)='%s'"
130 #define Query_for_list_of_attributes "SELECT a.attname FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c WHERE c.oid = a.attrelid and a.attnum>0 and not a.attisdropped and substr(a.attname,1,%d)='%s' and c.relname='%s' and pg_catalog.pg_table_is_visible(c.oid)"
131 #define Query_for_list_of_users "SELECT usename FROM pg_catalog.pg_user WHERE substr(usename,1,%d)='%s'"
132
133 /* This is a list of all "things" in Pgsql, which can show up after CREATE or
134    DROP; and there is also a query to get a list of them.
135 */
136 typedef struct
137 {
138         char       *name;
139         char       *query;
140 } pgsql_thing_t;
141
142 pgsql_thing_t words_after_create[] = {
143         {"AGGREGATE", "SELECT DISTINCT proname FROM pg_catalog.pg_proc WHERE proisagg AND substr(proname,1,%d)='%s'"},
144         {"CAST", NULL},                         /* Casts have complex structures for namees, so skip it */
145         {"CONVERSION", "SELECT conname FROM pg_catalog.pg_conversion WHERE substr(conname,1,%d)='%s'"},
146         {"DATABASE", Query_for_list_of_databases},
147         {"DOMAIN", "SELECT typname FROM pg_catalog.pg_type WHERE typtype = 'd' AND substr(typname,1,%d)='%s'"},
148         {"FUNCTION", "SELECT DISTINCT proname FROM pg_catalog.pg_proc WHERE substr(proname,1,%d)='%s'"},
149         {"GROUP", "SELECT groname FROM pg_catalog.pg_group WHERE substr(groname,1,%d)='%s'"},
150         {"LANGUAGE", "SELECT lanname FROM pg_catalog.pg_language WHERE substr(lanname,1,%d)='%s'"},
151         {"INDEX", Query_for_list_of_indexes},
152         {"OPERATOR", NULL},                     /* Querying for this is probably not such
153                                                                  * a good idea. */
154         {"RULE", "SELECT rulename FROM pg_catalog.pg_rules WHERE substr(rulename,1,%d)='%s'"},
155         {"SCHEMA", "SELECT nspname FROM pg_catalog.pg_namespace WHERE substr(nspname,1,%d)='%s'"},
156         {"SEQUENCE", "SELECT relname FROM pg_catalog.pg_class WHERE relkind='S' and substr(relname,1,%d)='%s'"},
157         {"TABLE", Query_for_list_of_tables},
158         {"TEMP", NULL},                         /* for CREATE TEMP TABLE ... */
159         {"TRIGGER", "SELECT tgname FROM pg_catalog.pg_trigger WHERE substr(tgname,1,%d)='%s'"},
160         {"TYPE", "SELECT typname FROM pg_catalog.pg_type WHERE substr(typname,1,%d)='%s'"},
161         {"UNIQUE", NULL},                       /* for CREATE UNIQUE INDEX ... */
162         {"USER", Query_for_list_of_users},
163         {"VIEW", "SELECT viewname FROM pg_catalog.pg_views WHERE substr(viewname,1,%d)='%s'"},
164         {NULL, NULL}                            /* end of list */
165 };
166
167
168 /* A couple of macros to ease typing. You can use these to complete the given
169    string with
170    1) The results from a query you pass it. (Perhaps one of those above?)
171    2) The items from a null-pointer-terminated list.
172    3) A string constant
173    4) The list of attributes to the given table.
174 */
175 #define COMPLETE_WITH_QUERY(query) \
176 do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
177 #define COMPLETE_WITH_LIST(list) \
178 do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
179 #define COMPLETE_WITH_CONST(string) \
180 do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
181 #define COMPLETE_WITH_ATTR(table) \
182 do {completion_charp = Query_for_list_of_attributes; completion_info_charp = table; matches = completion_matches(text, complete_from_query); } while(0)
183
184
185 /* The completion function. Acc. to readline spec this gets passed the text
186    entered to far and its start and end in the readline buffer. The return value
187    is some partially obscure list format that can be generated by the readline
188    libraries completion_matches() function, so we don't have to worry about it.
189 */
190 static char **
191 psql_completion(char *text, int start, int end)
192 {
193         /* This is the variable we'll return. */
194         char      **matches = NULL;
195
196         /* These are going to contain some scannage of the input line. */
197         char       *prev_wd,
198                            *prev2_wd,
199                            *prev3_wd,
200                            *prev4_wd;
201
202         static char *sql_commands[] = {
203                 "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
204                 "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE", "DROP", "EXECUTE",
205                 "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY",
206                 "PREPARE", "REINDEX", "RESET", "REVOKE", "ROLLBACK", "SELECT", "SET", "SHOW",
207                 "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL
208         };
209
210         static char *pgsql_variables[] = {
211                 /* these SET arguments are known in gram.y */
212                 "CONSTRAINTS",
213                 "NAMES",
214                 "SESSION",
215                 "TRANSACTION ISOLATION LEVEL",
216                 /* these are treated in backend/commands/variable.c */
217                 "DateStyle",
218                 "TimeZone",
219                 "client_encoding",
220                 "server_encoding",
221                 "seed",
222
223                 /*
224                  * the rest should match USERSET entries in
225                  * backend/utils/misc/guc.c
226                  */
227                 "australian_timezones",
228                 "authentication_timeout",
229                 "autocommit",
230                 "checkpoint_segments",
231                 "checkpoint_timeout",
232                 "client_min_messages",
233                 "commit_delay",
234                 "commit_siblings",
235                 "cpu_index_tuple_cost",
236                 "cpu_operator_cost",
237                 "cpu_tuple_cost",
238                 "db_user_namespace",
239                 "deadlock_timeout",
240                 "debug_pretty_print",
241                 "debug_print_parse",
242                 "debug_print_plan",
243                 "debug_print_rewritten",
244                 "default_statistics_target",
245                 "default_transaction_isolation",
246                 "dynamic_library_path",
247                 "effective_cache_size",
248                 "enable_hashjoin",
249                 "enable_indexscan",
250                 "enable_mergejoin",
251                 "enable_nestloop",
252                 "enable_seqscan",
253                 "enable_sort",
254                 "enable_hashagg",
255                 "enable_tidscan",
256                 "explain_pretty_print",
257                 "extra_float_digits",
258                 "fixbtree",
259                 "fsync",
260                 "geqo",
261                 "geqo_effort",
262                 "geqo_generations",
263                 "geqo_pool_size",
264                 "geqo_random_seed",
265                 "geqo_selection_bias",
266                 "geqo_threshold",
267                 "log_hostname",
268                 "krb_server_keyfile",
269                 "lc_messages",
270                 "lc_monetary",
271                 "lc_numeric",
272                 "lc_timeC",
273                 "log_connections",
274                 "log_duration",
275                 "log_min_error_statement",
276                 "log_pid",
277                 "log_statement",
278                 "log_timestamp",
279                 "max_connections",
280                 "max_expr_depth",
281                 "max_files_per_process",
282                 "max_fsm_pages",
283                 "max_fsm_relations",
284                 "max_locks_per_transaction",
285                 "password_encryption",
286                 "port",
287                 "pre_auth_delay",
288                 "random_page_cost",
289                 "search_path",
290                 "log_min_messages",
291                 "shared_buffers",
292                 "log_executor_stats",
293                 "log_parser_stats",
294                 "log_planner_stats",
295                 "log_source_port",
296                 "log_statement_stats",
297                 "silent_mode",
298                 "sort_mem",
299                 "sql_inheritance",
300                 "ssl",
301                 "statement_timeout",
302                 "stats_block_level",
303                 "stats_command_string",
304                 "stats_reset_on_server_start",
305                 "stats_row_level",
306                 "stats_start_collector",
307                 "superuser_reserved_connections",
308                 "syslog",
309                 "syslog_facility",
310                 "syslog_ident",
311                 "tcpip_socket",
312                 "trace_notify",
313                 "transform_null_equals",
314                 "unix_socket_directory",
315                 "unix_socket_group",
316                 "unix_socket_permissions",
317                 "vacuum_mem",
318                 "virtual_hostt",
319                 "wal_buffers",
320                 "wal_debug",
321                 "wal_sync_method",
322                 NULL
323         };
324
325         static char *backslash_commands[] = {
326                 "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright", 
327                 "\\d", "\\da", "\\dd", "\\dD", "\\df", "\\di", "\\dl", "\\do",
328                 "\\dp", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv","\\du",
329                 "\\e", "\\echo", "\\encoding",
330                 "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
331                 "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
332                 "\\o", "\\p", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T",
333                 "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
334         };
335
336         (void) end;                                     /* not used */
337
338 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
339         rl_completion_append_character = ' ';
340 #endif
341
342         /* Clear a few things. */
343         completion_charp = NULL;
344         completion_charpp = NULL;
345         completion_info_charp = NULL;
346
347         /*
348          * Scan the input line before our current position for the last four
349          * words. According to those we'll make some smart decisions on what
350          * the user is probably intending to type. TODO: Use strtokx() to do
351          * this.
352          */
353         prev_wd = previous_word(start, 0);
354         prev2_wd = previous_word(start, 1);
355         prev3_wd = previous_word(start, 2);
356         prev4_wd = previous_word(start, 3);
357
358         /* If a backslash command was started, continue */
359         if (text[0] == '\\')
360                 COMPLETE_WITH_LIST(backslash_commands);
361
362         /* If no previous word, suggest one of the basic sql commands */
363         else if (!prev_wd)
364                 COMPLETE_WITH_LIST(sql_commands);
365
366 /* CREATE or DROP */
367         /* complete with something you can create or drop */
368         else if (strcasecmp(prev_wd, "CREATE") == 0 || strcasecmp(prev_wd, "DROP") == 0)
369                 matches = completion_matches(text, create_command_generator);
370
371 /* ALTER */
372         /* complete with what you can alter (TABLE, GROUP, USER, ...) */
373         else if (strcasecmp(prev_wd, "ALTER") == 0)
374         {
375                 char       *list_ALTER[] = {"DATABASE", "GROUP", "SCHEMA", "TABLE", "TRIGGER", "USER", NULL};
376
377                 COMPLETE_WITH_LIST(list_ALTER);
378         }
379
380         /* ALTER DATABASE <name> */
381         else if (strcasecmp(prev3_wd, "ALTER") == 0 && strcasecmp(prev2_wd, "DATABASE") == 0)
382         {
383                 char       *list_ALTERDATABASE[] = {"RESET", "SET", NULL};
384
385                 COMPLETE_WITH_LIST(list_ALTERDATABASE);
386         }
387         /* ALTER TRIGGER <name>, add ON */
388         else if (strcasecmp(prev3_wd, "ALTER") == 0 && strcasecmp(prev2_wd, "TRIGGER") == 0)
389                 COMPLETE_WITH_CONST("ON");
390
391         /*
392          * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
393          */
394         else if (strcasecmp(prev4_wd, "ALTER") == 0 && strcasecmp(prev3_wd, "TRIGGER") == 0
395           && strcasecmp(prev_wd, "ON") == 0)
396                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
397
398         /*
399          * If we detect ALTER TABLE <name>, suggest either ADD, ALTER, or
400          * RENAME
401          */
402         else if (strcasecmp(prev3_wd, "ALTER") == 0 && strcasecmp(prev2_wd, "TABLE") == 0)
403         {
404                 char       *list_ALTER2[] = {"ADD", "ALTER", "RENAME", NULL};
405
406                 COMPLETE_WITH_LIST(list_ALTER2);
407         }
408         /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
409         else if (strcasecmp(prev3_wd, "TABLE") == 0 &&
410                          (strcasecmp(prev_wd, "ALTER") == 0 || strcasecmp(prev_wd, "RENAME") == 0))
411                 COMPLETE_WITH_ATTR(prev2_wd);
412
413         /* complete ALTER GROUP <foo> with ADD or DROP */
414         else if (strcasecmp(prev3_wd, "ALTER") == 0 && strcasecmp(prev2_wd, "GROUP") == 0)
415         {
416                 char       *list_ALTERGROUP[] = {"ADD", "DROP", NULL};
417
418                 COMPLETE_WITH_LIST(list_ALTERGROUP);
419         }
420         /* complete ALTER GROUP <foo> ADD|DROP with USER */
421         else if (strcasecmp(prev4_wd, "ALTER") == 0 && strcasecmp(prev3_wd, "GROUP") == 0
422                          && (strcasecmp(prev_wd, "ADD") == 0 || strcasecmp(prev_wd, "DROP") == 0))
423                 COMPLETE_WITH_CONST("USER");
424         /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
425         else if (strcasecmp(prev4_wd, "GROUP") == 0
426                          && (strcasecmp(prev2_wd, "ADD") == 0 || strcasecmp(prev2_wd, "DROP") == 0)
427                          && strcasecmp(prev_wd, "USER") == 0)
428                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
429
430 /* ANALYZE */
431         /* If the previous word is ANALYZE, produce list of tables. */
432         else if (strcasecmp(prev_wd, "ANALYZE") == 0)
433                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
434         /* If we have ANALYZE <table>, complete with semicolon. */
435         else if (strcasecmp(prev2_wd, "ANALYZE") == 0)
436                 COMPLETE_WITH_CONST(";");
437
438 /* CLUSTER */
439         /* If the previous word is CLUSTER, produce list of indexes. */
440         else if (strcasecmp(prev_wd, "CLUSTER") == 0)
441                 COMPLETE_WITH_QUERY(Query_for_list_of_indexes);
442         /* If we have CLUSTER <sth>, then add "ON" */
443         else if (strcasecmp(prev2_wd, "CLUSTER") == 0)
444                 COMPLETE_WITH_CONST("ON");
445
446         /*
447          * If we have CLUSTER <sth> ON, then add the correct tablename as
448          * well.
449          */
450         else if (strcasecmp(prev3_wd, "CLUSTER") == 0 && strcasecmp(prev_wd, "ON") == 0)
451         {
452                 char            query_buffer[BUF_SIZE];         /* Some room to build
453                                                                                                  * queries. */
454
455                 if (snprintf(query_buffer, BUF_SIZE,
456                                          "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)",
457                                          prev2_wd) == -1)
458                         ERROR_QUERY_TOO_LONG;
459                 else
460                         COMPLETE_WITH_QUERY(query_buffer);
461         }
462
463 /* COMMENT */
464         else if (strcasecmp(prev_wd, "COMMENT") == 0)
465                 COMPLETE_WITH_CONST("ON");
466         else if (strcasecmp(prev2_wd, "COMMENT") == 0 && strcasecmp(prev_wd, "ON") == 0)
467         {
468                 char       *list_COMMENT[] =
469                 {"DATABASE", "INDEX", "RULE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW",
470                         "COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR", "TRIGGER", "CONSTRAINT",
471                 "DOMAIN", NULL};
472
473                 COMPLETE_WITH_LIST(list_COMMENT);
474         }
475         else if (strcasecmp(prev4_wd, "COMMENT") == 0 && strcasecmp(prev3_wd, "ON") == 0)
476                 COMPLETE_WITH_CONST("IS");
477
478 /* COPY */
479
480         /*
481          * If we have COPY [BINARY] (which you'd have to type yourself), offer
482          * list of tables (Also cover the analogous backslash command)
483          */
484         else if (strcasecmp(prev_wd, "COPY") == 0 ||
485                          strcasecmp(prev_wd, "\\copy") == 0 ||
486                          (strcasecmp(prev2_wd, "COPY") == 0 && strcasecmp(prev_wd, "BINARY") == 0))
487                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
488         /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */
489         else if (strcasecmp(prev2_wd, "COPY") == 0 ||
490                          strcasecmp(prev2_wd, "\\copy") == 0 ||
491                          strcasecmp(prev2_wd, "BINARY") == 0)
492         {
493                 char       *list_FROMTO[] = {"FROM", "TO", NULL};
494
495                 COMPLETE_WITH_LIST(list_FROMTO);
496         }
497
498 /* CREATE INDEX */
499         /* First off we complete CREATE UNIQUE with "INDEX" */
500         else if (strcasecmp(prev2_wd, "CREATE") == 0 && strcasecmp(prev_wd, "UNIQUE") == 0)
501                 COMPLETE_WITH_CONST("INDEX");
502         /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */
503         else if (strcasecmp(prev2_wd, "INDEX") == 0 &&
504                          (strcasecmp(prev3_wd, "CREATE") == 0 || strcasecmp(prev3_wd, "UNIQUE") == 0))
505                 COMPLETE_WITH_CONST("ON");
506         /* Complete ... INDEX <name> ON with a list of tables  */
507         else if ((strcasecmp(prev3_wd, "INDEX") == 0 && strcasecmp(prev_wd, "ON") == 0) || (0))
508                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
509
510         /*
511          * Complete INDEX <name> ON <table> with a list of table columns
512          * (which should really be in parens)
513          */
514         else if (strcasecmp(prev4_wd, "INDEX") == 0 && strcasecmp(prev2_wd, "ON") == 0)
515                 COMPLETE_WITH_ATTR(prev_wd);
516         /* same if you put in USING */
517         else if ((strcasecmp(prev4_wd, "ON") == 0 && strcasecmp(prev2_wd, "USING") == 0))
518                 COMPLETE_WITH_ATTR(prev3_wd);
519         /* Complete USING with an index method */
520         else if (strcasecmp(prev_wd, "USING") == 0)
521         {
522                 char       *index_mth[] = {"BTREE", "RTREE", "HASH", "GIST", NULL};
523
524                 COMPLETE_WITH_LIST(index_mth);
525         }
526
527 /* CREATE RULE */
528         /* Complete "CREATE RULE <sth>" with "AS" */
529         else if (strcasecmp(prev3_wd, "CREATE") == 0 && strcasecmp(prev2_wd, "RULE") == 0)
530                 COMPLETE_WITH_CONST("AS");
531         /* Complete "CREATE RULE <sth> AS with "ON" */
532         else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
533                          strcasecmp(prev3_wd, "RULE") == 0 &&
534                          strcasecmp(prev_wd, "AS") == 0)
535                 COMPLETE_WITH_CONST("ON");
536         /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */
537         else if (strcasecmp(prev4_wd, "RULE") == 0 &&
538                          strcasecmp(prev2_wd, "AS") == 0 &&
539                          strcasecmp(prev_wd, "ON") == 0)
540         {
541                 char       *rule_events[] = {"SELECT", "UPDATE", "INSERT", "DELETE", NULL};
542
543                 COMPLETE_WITH_LIST(rule_events);
544         }
545         /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
546         else if (strcasecmp(prev3_wd, "AS") == 0 &&
547                          strcasecmp(prev2_wd, "ON") == 0 &&
548                          (toupper((unsigned char) prev_wd[4]) == 'T' ||
549                           toupper((unsigned char) prev_wd[5]) == 'T'))
550                 COMPLETE_WITH_CONST("TO");
551         /* Complete "AS ON <sth> TO" with a table name */
552         else if (strcasecmp(prev4_wd, "AS") == 0 &&
553                          strcasecmp(prev3_wd, "ON") == 0 &&
554                          strcasecmp(prev_wd, "TO") == 0)
555                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
556
557 /* CREATE TABLE */
558         /* Complete CREATE TEMP with "TABLE" */
559         else if (strcasecmp(prev2_wd, "CREATE") == 0 && strcasecmp(prev_wd, "TEMP") == 0)
560                 COMPLETE_WITH_CONST("TABLE");
561
562 /* CREATE TRIGGER */
563         /* is on the agenda . . . */
564
565 /* CREATE VIEW */
566         /* Complete "CREATE VIEW <name>" with "AS" */
567         else if (strcasecmp(prev3_wd, "CREATE") == 0 && strcasecmp(prev2_wd, "VIEW") == 0)
568                 COMPLETE_WITH_CONST("AS");
569         /* Complete "CREATE VIEW <sth> AS with "SELECT" */
570         else if (strcasecmp(prev4_wd, "CREATE") == 0 &&
571                          strcasecmp(prev3_wd, "VIEW") == 0 &&
572                          strcasecmp(prev_wd, "AS") == 0)
573                 COMPLETE_WITH_CONST("SELECT");
574
575 /* DELETE */
576
577         /*
578          * Complete DELETE with FROM (only if the word before that is not "ON"
579          * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
580          */
581         else if (strcasecmp(prev_wd, "DELETE") == 0 &&
582                          !(strcasecmp(prev2_wd, "ON") == 0 ||
583                            strcasecmp(prev2_wd, "GRANT") == 0 ||
584                            strcasecmp(prev2_wd, "BEFORE") == 0 ||
585                            strcasecmp(prev2_wd, "AFTER") == 0))
586                 COMPLETE_WITH_CONST("FROM");
587         /* Complete DELETE FROM with a list of tables */
588         else if (strcasecmp(prev2_wd, "DELETE") == 0 && strcasecmp(prev_wd, "FROM") == 0)
589                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
590         /* Complete DELETE FROM <table> with "WHERE" (perhaps a safe idea?) */
591         else if (strcasecmp(prev3_wd, "DELETE") == 0 && strcasecmp(prev2_wd, "FROM") == 0)
592                 COMPLETE_WITH_CONST("WHERE");
593
594 /* EXPLAIN */
595
596         /*
597          * Complete EXPLAIN [VERBOSE] (which you'd have to type yourself) with
598          * the list of SQL commands
599          */
600         else if (strcasecmp(prev_wd, "EXPLAIN") == 0 ||
601                          (strcasecmp(prev2_wd, "EXPLAIN") == 0 && strcasecmp(prev_wd, "VERBOSE") == 0))
602                 COMPLETE_WITH_LIST(sql_commands);
603
604 /* FETCH && MOVE */
605         /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
606         else if (strcasecmp(prev_wd, "FETCH") == 0 || strcasecmp(prev_wd, "MOVE") == 0)
607         {
608                 char       *list_FETCH1[] = {"FORWARD", "BACKWARD", "RELATIVE", NULL};
609
610                 COMPLETE_WITH_LIST(list_FETCH1);
611         }
612         /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */
613         else if (strcasecmp(prev2_wd, "FETCH") == 0 || strcasecmp(prev2_wd, "MOVE") == 0)
614         {
615                 char       *list_FETCH2[] = {"ALL", "NEXT", "PRIOR", NULL};
616
617                 COMPLETE_WITH_LIST(list_FETCH2);
618         }
619
620         /*
621          * Complete FETCH <sth1> <sth2> with "FROM" or "TO". (Is there a
622          * difference? If not, remove one.)
623          */
624         else if (strcasecmp(prev3_wd, "FETCH") == 0 || strcasecmp(prev3_wd, "MOVE") == 0)
625         {
626                 char       *list_FROMTO[] = {"FROM", "TO", NULL};
627
628                 COMPLETE_WITH_LIST(list_FROMTO);
629         }
630
631 /* GRANT && REVOKE*/
632         /* Complete GRANT/REVOKE with a list of privileges */
633         else if (strcasecmp(prev_wd, "GRANT") == 0 || strcasecmp(prev_wd, "REVOKE") == 0)
634         {
635                 char       *list_privileg[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES", "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
636
637                 COMPLETE_WITH_LIST(list_privileg);
638         }
639         /* Complete GRANT/REVOKE <sth> with "ON" */
640         else if (strcasecmp(prev2_wd, "GRANT") == 0 || strcasecmp(prev2_wd, "REVOKE") == 0)
641                 COMPLETE_WITH_CONST("ON");
642
643         /*
644          * Complete GRANT/REVOKE <sth> ON with a list of tables, views,
645          * sequences, and indexes
646          *
647          * XXX should also offer DATABASE, FUNCTION, LANGUAGE, SCHEMA here
648          */
649         else if ((strcasecmp(prev3_wd, "GRANT") == 0 || strcasecmp(prev3_wd, "REVOKE") == 0) &&
650                          strcasecmp(prev_wd, "ON") == 0)
651                 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class "
652                                                         "WHERE relkind in ('r','i','S','v') AND "
653                                                         "substr(relname,1,%d)='%s' AND pg_catalog.pg_table_is_visible(oid)");
654         /* Complete "GRANT * ON * " with "TO" */
655         else if (strcasecmp(prev4_wd, "GRANT") == 0 && strcasecmp(prev2_wd, "ON") == 0)
656                 COMPLETE_WITH_CONST("TO");
657         /* Complete "REVOKE * ON * " with "FROM" */
658         else if (strcasecmp(prev4_wd, "REVOKE") == 0 && strcasecmp(prev2_wd, "ON") == 0)
659                 COMPLETE_WITH_CONST("FROM");
660
661         /*
662          * TODO: to complete with user name we need prev5_wd -- wait for a
663          * more general solution there
664          */
665
666 /* INSERT */
667         /* Complete INSERT with "INTO" */
668         else if (strcasecmp(prev_wd, "INSERT") == 0)
669                 COMPLETE_WITH_CONST("INTO");
670         /* Complete INSERT INTO with table names */
671         else if (strcasecmp(prev2_wd, "INSERT") == 0 && strcasecmp(prev_wd, "INTO") == 0)
672                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
673         /* Complete "INSERT INTO <table> (" with attribute names */
674         else if (rl_line_buffer[start - 1] == '(' && strcasecmp(prev3_wd, "INSERT") == 0 && strcasecmp(prev2_wd, "INTO") == 0)
675                 COMPLETE_WITH_ATTR(prev_wd);
676
677         /*
678          * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
679          * VALUES"
680          */
681         else if (strcasecmp(prev3_wd, "INSERT") == 0 && strcasecmp(prev2_wd, "INTO") == 0)
682         {
683                 char       *list_INSERT[] = {"DEFAULT VALUES", "SELECT", "VALUES", NULL};
684
685                 COMPLETE_WITH_LIST(list_INSERT);
686         }
687         /* Complete INSERT INTO <table> (attribs) with "VALUES" or "SELECT" */
688         else if (strcasecmp(prev4_wd, "INSERT") == 0 && strcasecmp(prev3_wd, "INTO") == 0 &&
689                          prev_wd[strlen(prev_wd) - 1] == ')')
690         {
691                 char       *list_INSERT[] = {"SELECT", "VALUES", NULL};
692
693                 COMPLETE_WITH_LIST(list_INSERT);
694         }
695
696         /* Insert an open parenthesis after "VALUES" */
697         else if (strcasecmp(prev_wd, "VALUES") == 0 && strcasecmp(prev2_wd, "DEFAULT") != 0)
698                 COMPLETE_WITH_CONST("(");
699
700 /* LOCK */
701         /* Complete LOCK [TABLE] with a list of tables */
702         else if ((strcasecmp(prev_wd, "LOCK") == 0) ||
703          (strcasecmp(prev_wd, "TABLE") == 0 && strcasecmp(prev2_wd, "LOCK")))
704                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
705
706         /* For the following, handle the case of a single table only for now */
707
708         /* Complete LOCK [TABLE] <table> with "IN" */
709         else if ((strcasecmp(prev2_wd, "LOCK") == 0 && strcasecmp(prev_wd, "TABLE")) ||
710                          (strcasecmp(prev2_wd, "TABLE") == 0 && strcasecmp(prev3_wd, "LOCK") == 0))
711                 COMPLETE_WITH_CONST("IN");
712
713         /* Complete LOCK [TABLE] <table> IN with a lock mode */
714         else if (strcasecmp(prev_wd, "IN") == 0 &&
715                          (strcasecmp(prev3_wd, "LOCK") == 0 ||
716         (strcasecmp(prev3_wd, "TABLE") == 0 && strcasecmp(prev3_wd, "LOCK"))))
717         {
718                 char       *lock_modes[] = {"ACCESS SHARE MODE", "ROW SHARE MODE", "ROW EXCLUSIVE MODE",
719                         "SHARE UPDATE EXCLUSIVE MODE", "SHARE MODE", "SHARE ROW EXCLUSIVE MODE",
720                 "EXCLUSIVE MODE", "ACCESS EXCLUSIVE MODE", NULL};
721
722                 COMPLETE_WITH_LIST(lock_modes);
723         }
724
725 /* NOTIFY */
726         else if (strcasecmp(prev_wd, "NOTIFY") == 0)
727                 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s'");
728
729 /* REINDEX */
730         else if (strcasecmp(prev_wd, "REINDEX") == 0)
731         {
732                 char       *list_REINDEX[] = {"TABLE", "DATABASE", "INDEX", NULL};
733
734                 COMPLETE_WITH_LIST(list_REINDEX);
735         }
736         else if (strcasecmp(prev2_wd, "REINDEX") == 0)
737         {
738                 if (strcasecmp(prev_wd, "TABLE") == 0)
739                         COMPLETE_WITH_QUERY(Query_for_list_of_tables);
740                 else if (strcasecmp(prev_wd, "DATABASE") == 0)
741                         COMPLETE_WITH_QUERY(Query_for_list_of_databases);
742                 else if (strcasecmp(prev_wd, "INDEX") == 0)
743                         COMPLETE_WITH_QUERY(Query_for_list_of_indexes);
744         }
745
746 /* SELECT */
747         /* naah . . . */
748
749 /* SET, RESET, SHOW */
750         /* Complete with a variable name */
751         else if ((strcasecmp(prev_wd, "SET") == 0 && strcasecmp(prev3_wd, "UPDATE") != 0) ||
752                          strcasecmp(prev_wd, "RESET") == 0 ||
753                          strcasecmp(prev_wd, "SHOW") == 0)
754                 COMPLETE_WITH_LIST(pgsql_variables);
755         /* Complete "SET TRANSACTION ISOLOLATION LEVEL" */
756         else if (strcasecmp(prev2_wd, "SET") == 0 && strcasecmp(prev_wd, "TRANSACTION") == 0)
757                 COMPLETE_WITH_CONST("ISOLATION");
758         else if (strcasecmp(prev3_wd, "SET") == 0 &&
759                          strcasecmp(prev2_wd, "TRANSACTION") == 0 &&
760                          strcasecmp(prev_wd, "ISOLATION") == 0)
761                 COMPLETE_WITH_CONST("LEVEL");
762         else if ((strcasecmp(prev4_wd, "SET") == 0 || strcasecmp(prev4_wd, "AS") == 0) &&
763                          strcasecmp(prev3_wd, "TRANSACTION") == 0 &&
764                          strcasecmp(prev2_wd, "ISOLATION") == 0 &&
765                          strcasecmp(prev_wd, "LEVEL") == 0)
766         {
767                 char       *my_list[] = {"READ", "SERIALIZABLE", NULL};
768
769                 COMPLETE_WITH_LIST(my_list);
770         }
771         else if (strcasecmp(prev4_wd, "TRANSACTION") == 0 &&
772                          strcasecmp(prev3_wd, "ISOLATION") == 0 &&
773                          strcasecmp(prev2_wd, "LEVEL") == 0 &&
774                          strcasecmp(prev_wd, "READ") == 0)
775                 COMPLETE_WITH_CONST("COMMITTED");
776         /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
777         else if (strcasecmp(prev3_wd, "SET") == 0 && strcasecmp(prev2_wd, "CONSTRAINTS") == 0)
778         {
779                 char       *constraint_list[] = {"DEFERRED", "IMMEDIATE", NULL};
780
781                 COMPLETE_WITH_LIST(constraint_list);
782         }
783         /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
784         else if (strcasecmp(prev2_wd, "SET") == 0 && strcasecmp(prev_wd, "SESSION") == 0)
785         {
786                 char       *my_list[] = {"AUTHORIZATION",
787                         "CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL",
788                 NULL};
789
790                 COMPLETE_WITH_LIST(my_list);
791         }
792         /* Complete SET SESSION AUTHORIZATION with username */
793         else if (strcasecmp(prev3_wd, "SET") == 0
794                          && strcasecmp(prev2_wd, "SESSION") == 0
795                          && strcasecmp(prev_wd, "AUTHORIZATION") == 0)
796                 COMPLETE_WITH_QUERY(Query_for_list_of_users);
797         /* Complete SET <var> with "TO" */
798         else if (strcasecmp(prev2_wd, "SET") == 0 &&
799                          strcasecmp(prev4_wd, "UPDATE") != 0)
800                 COMPLETE_WITH_CONST("TO");
801         /* Suggest possible variable values */
802         else if (strcasecmp(prev3_wd, "SET") == 0 &&
803                    (strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0))
804         {
805                 if (strcasecmp(prev2_wd, "DateStyle") == 0)
806                 {
807                         char       *my_list[] = {"'ISO'", "'SQL'", "'Postgres'", "'European'", "'NonEuropean'", "'German'", "DEFAULT", NULL};
808
809                         COMPLETE_WITH_LIST(my_list);
810                 }
811                 else if (strcasecmp(prev2_wd, "GEQO") == 0)
812                 {
813                         char       *my_list[] = {"ON", "OFF", "DEFAULT", NULL};
814
815                         COMPLETE_WITH_LIST(my_list);
816                 }
817                 else
818                 {
819                         char       *my_list[] = {"DEFAULT", NULL};
820
821                         COMPLETE_WITH_LIST(my_list);
822                 }
823         }
824
825 /* TRUNCATE */
826         else if (strcasecmp(prev_wd, "TRUNCATE") == 0)
827                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
828
829 /* UNLISTEN */
830         else if (strcasecmp(prev_wd, "UNLISTEN") == 0)
831                 COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s' UNION SELECT '*'::name");
832
833 /* UPDATE */
834         /* If prev. word is UPDATE suggest a list of tables */
835         else if (strcasecmp(prev_wd, "UPDATE") == 0)
836                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
837         /* Complete UPDATE <table> with "SET" */
838         else if (strcasecmp(prev2_wd, "UPDATE") == 0)
839                 COMPLETE_WITH_CONST("SET");
840
841         /*
842          * If the previous word is SET (and it wasn't caught above as the
843          * _first_ word) the word before it was (hopefully) a table name and
844          * we'll now make a list of attributes.
845          */
846         else if (strcasecmp(prev_wd, "SET") == 0)
847                 COMPLETE_WITH_ATTR(prev2_wd);
848
849 /* VACUUM */
850         else if (strcasecmp(prev_wd, "VACUUM") == 0)
851                 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");
852         else if (strcasecmp(prev2_wd, "VACUUM") == 0 && (strcasecmp(prev_wd, "FULL") == 0 || strcasecmp(prev_wd, "ANALYZE") == 0))
853                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
854
855 /* WHERE */
856         /* Simple case of the word before the where being the table name */
857         else if (strcasecmp(prev_wd, "WHERE") == 0)
858                 COMPLETE_WITH_ATTR(prev2_wd);
859
860 /* ... FROM ... */
861         else if (strcasecmp(prev_wd, "FROM") == 0)
862                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
863
864
865 /* Backslash commands */
866         else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0)
867                 COMPLETE_WITH_QUERY(Query_for_list_of_databases);
868         else if (strcmp(prev_wd, "\\d") == 0)
869                 COMPLETE_WITH_QUERY(Query_for_list_of_tables);
870         else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0)
871                 COMPLETE_WITH_LIST(sql_commands);
872         else if (strcmp(prev_wd, "\\pset") == 0)
873         {
874                 char       *my_list[] = {"format", "border", "expanded", "null", "fieldsep",
875                         "tuples_only", "title", "tableattr", "pager",
876                 "recordsep", NULL};
877
878                 COMPLETE_WITH_LIST(my_list);
879         }
880         else if (strcmp(prev_wd, "\\cd") == 0 ||
881                  strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 ||
882                          strcmp(prev_wd, "\\g") == 0 ||
883                          strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 ||
884                   strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 ||
885                          strcmp(prev_wd, "\\s") == 0 ||
886                    strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0
887                 )
888                 matches = completion_matches(text, filename_completion_function);
889
890
891         /*
892          * Finally, we look through the list of "things", such as TABLE, INDEX
893          * and check if that was the previous word. If so, execute the query
894          * to get a list of them.
895          */
896         else
897         {
898                 int                     i;
899
900                 for (i = 0; words_after_create[i].name; i++)
901                         if (strcasecmp(prev_wd, words_after_create[i].name) == 0)
902                         {
903                                 COMPLETE_WITH_QUERY(words_after_create[i].query);
904                                 break;
905                         }
906         }
907
908
909         /*
910          * If we still don't have anything to match we have to fabricate some
911          * sort of default list. If we were to just return NULL, readline
912          * automatically attempts filename completion, and that's usually no
913          * good.
914          */
915         if (matches == NULL)
916         {
917                 COMPLETE_WITH_CONST("");
918 #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
919                 rl_completion_append_character = '\0';
920 #endif
921         }
922
923
924         /* free storage */
925         free(prev_wd);
926         free(prev2_wd);
927         free(prev3_wd);
928         free(prev4_wd);
929
930         /* Return our Grand List O' Matches */
931         return matches;
932 }
933
934
935
936 /* GENERATOR FUNCTIONS
937
938    These functions do all the actual work of completing the input. They get
939    passed the text so far and the count how many times they have been called so
940    far with the same text.
941    If you read the above carefully, you'll see that these don't get called
942    directly but through the readline interface.
943    The return value is expected to be the full completion of the text, going
944    through a list each time, or NULL if there are no more matches. The string
945    will be free()'d be readline, so you must run it through strdup() or
946    something of that sort.
947 */
948
949 /* This one gives you one from a list of things you can put after CREATE or DROP
950    as defined above.
951 */
952 static char *
953 create_command_generator(char *text, int state)
954 {
955         static int      list_index,
956                                 string_length;
957         char       *name;
958
959         /* If this is the first time for this completion, init some values */
960         if (state == 0)
961         {
962                 list_index = 0;
963                 string_length = strlen(text);
964         }
965
966         /* find something that matches */
967         while ((name = words_after_create[list_index++].name))
968                 if (strncasecmp(name, text, string_length) == 0)
969                         return xstrdup(name);
970
971         /* if nothing matches, return NULL */
972         return NULL;
973 }
974
975
976 /* This creates a list of matching things, according to a query pointed to
977    by completion_charp. The query needs to have a %d and a %s in it, which will
978    be replaced by the string length of the text and the text itself. See some
979    example queries at the top.
980    The query may also have another %s in it, which will be replaced by the value
981    of completion_info_charp.
982    Ordinarily this would be used to get a list of matching tables or functions,
983    etc.
984 */
985 static char *
986 complete_from_query(char *text, int state)
987 {
988         static int      list_index,
989                                 string_length;
990         static PGresult *result = NULL;
991         char            query_buffer[BUF_SIZE];
992         const char *item;
993
994         /*
995          * If this ist the first time for this completion, we fetch a list of
996          * our "things" from the backend.
997          */
998         if (state == 0)
999         {
1000                 list_index = 0;
1001                 string_length = strlen(text);
1002
1003                 /* Need to have a query */
1004                 if (completion_charp == NULL)
1005                         return NULL;
1006
1007                 if (snprintf(query_buffer, BUF_SIZE, completion_charp, string_length, text, completion_info_charp) == -1)
1008                 {
1009                         ERROR_QUERY_TOO_LONG;
1010                         return NULL;
1011                 }
1012
1013                 result = exec_query(query_buffer);
1014         }
1015
1016         /* Find something that matches */
1017         if (result && PQresultStatus(result) == PGRES_TUPLES_OK)
1018                 while (list_index < PQntuples(result) && (item = PQgetvalue(result, list_index++, 0)))
1019                         if (strncasecmp(text, item, string_length) == 0)
1020                                 return xstrdup(item);
1021
1022         /* If nothing matches, free the db structure and return null */
1023         PQclear(result);
1024         result = NULL;
1025         return NULL;
1026 }
1027
1028
1029 /* This function returns in order one of a fixed, NULL pointer terminated list
1030    of strings (if matching). This can be used if there are only a fixed number
1031    SQL words that can appear at certain spot.
1032 */
1033 static char *
1034 complete_from_list(char *text, int state)
1035 {
1036         static int      string_length,
1037                                 list_index,
1038                                 matches;
1039         static bool     casesensitive;
1040         char       *item;
1041
1042         /* need to have a list */
1043 #ifdef USE_ASSERT_CHECKING
1044         assert(completion_charpp);
1045 #endif
1046
1047         /* Initialization */
1048         if (state == 0)
1049         {
1050                 list_index = 0;
1051                 string_length = strlen(text);
1052                 casesensitive = true;
1053                 matches = 0;
1054         }
1055
1056         while ((item = completion_charpp[list_index++]))
1057         {
1058                 /* First pass is case sensitive */
1059                 if (casesensitive && strncmp(text, item, string_length) == 0)
1060                 {
1061                         matches++;
1062                         return xstrdup(item);
1063                 }
1064
1065                 /* Second pass is case insensitive, don't bother counting matches */
1066                 if (!casesensitive && strncasecmp(text, item, string_length) == 0)
1067                         return xstrdup(item);
1068         }
1069
1070         /*
1071          * No matches found. If we're not case insensitive already, lets switch
1072          * to being case insensitive and try again
1073          */
1074         if (casesensitive && matches == 0)
1075         {
1076                 casesensitive = false;
1077                 list_index = 0;
1078                 state++;
1079                 return (complete_from_list(text, state));
1080         }
1081
1082         /* If no more matches, return null. */
1083         return NULL;
1084 }
1085
1086
1087 /* This function returns one fixed string the first time even if it doesn't
1088    match what's there, and nothing the second time. This should be used if there
1089    is only one possibility that can appear at a certain spot, so misspellings
1090    will be overwritten.
1091    The string to be passed must be in completion_charp.
1092 */
1093 static char *
1094 complete_from_const(char *text, int state)
1095 {
1096         (void) text;                            /* We don't care about what was entered
1097                                                                  * already. */
1098
1099 #ifdef USE_ASSERT_CHECKING
1100         assert(completion_charp);
1101 #endif
1102         if (state == 0)
1103                 return xstrdup(completion_charp);
1104         else
1105                 return NULL;
1106 }
1107
1108
1109
1110 /* HELPER FUNCTIONS */
1111
1112
1113 /* Execute a query and report any errors. This should be the preferred way of
1114    talking to the database in this file.
1115    Note that the query passed in here must not have a semicolon at the end
1116    because we need to append LIMIT xxx.
1117 */
1118 static PGresult *
1119 exec_query(char *query)
1120 {
1121         PGresult   *result;
1122         char            query_buffer[BUF_SIZE];
1123
1124         if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK)
1125                 return NULL;
1126 #ifdef USE_ASSERT_CHECKING
1127         assert(query[strlen(query) - 1] != ';');
1128 #endif
1129
1130         if (snprintf(query_buffer, BUF_SIZE, "%s LIMIT %d;", query, completion_max_records) == -1)
1131         {
1132                 ERROR_QUERY_TOO_LONG;
1133                 return NULL;
1134         }
1135
1136         result = PQexec(pset.db, query);
1137
1138         if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK)
1139         {
1140 #if 0
1141                 psql_error("tab completion: %s failed - %s\n",
1142                                    query, PQresStatus(PQresultStatus(result)));
1143 #endif
1144                 PQclear(result);
1145                 result = NULL;
1146         }
1147
1148         return result;
1149 }
1150
1151
1152
1153 /* Return the word (space delimited) before point. Set skip > 0 to skip that
1154    many words; e.g. skip=1 finds the word before the previous one.
1155 */
1156 static char *
1157 previous_word(int point, int skip)
1158 {
1159         int                     i,
1160                                 start = 0,
1161                                 end = -1,
1162                                 inquotes = 0;
1163         char       *s;
1164
1165         while (skip-- >= 0)
1166         {
1167                 /* first we look for a space before the current word */
1168                 for (i = point; i >= 0; i--)
1169                         if (rl_line_buffer[i] == ' ')
1170                                 break;
1171
1172                 /* now find the first non-space which then constitutes the end */
1173                 for (; i >= 0; i--)
1174                         if (rl_line_buffer[i] != ' ')
1175                         {
1176                                 end = i;
1177                                 break;
1178                         }
1179
1180                 /*
1181                  * If no end found we return null, because there is no word before
1182                  * the point
1183                  */
1184                 if (end == -1)
1185                         return NULL;
1186
1187                 /*
1188                  * Otherwise we now look for the start. The start is either the
1189                  * last character before any space going backwards from the end,
1190                  * or it's simply character 0
1191                  */
1192                 for (start = end; start > 0; start--)
1193                 {
1194                         if (rl_line_buffer[start] == '"')
1195                                 inquotes = !inquotes;
1196                         if ((rl_line_buffer[start - 1] == ' ') && inquotes == 0)
1197                                 break;
1198                 }
1199
1200                 point = start;
1201         }
1202
1203         /* make a copy */
1204         s = (char *) malloc(end - start + 2);
1205         if (!s)
1206         {
1207                 psql_error("out of memory\n");
1208                 if (!pset.cur_cmd_interactive)
1209                         exit(EXIT_FAILURE);
1210                 else
1211                         return NULL;
1212         }
1213
1214         strncpy(s, &rl_line_buffer[start], end - start + 1);
1215         s[end - start + 1] = '\0';
1216
1217         return s;
1218 }
1219
1220
1221
1222 #if 0
1223
1224 /*
1225  * Surround a string with single quotes. This works for both SQL and
1226  * psql internal. Currently disable because it is reported not to
1227  * cooperate with certain versions of readline.
1228  */
1229 char *
1230 quote_file_name(char *text, int match_type, char *quote_pointer)
1231 {
1232         char       *s;
1233         size_t          length;
1234
1235         (void) quote_pointer;           /* not used */
1236
1237         length = strlen(text) +(match_type == SINGLE_MATCH ? 3 : 2);
1238         s = malloc(length);
1239         s[0] = '\'';
1240         strcpy(s + 1, text);
1241         if (match_type == SINGLE_MATCH)
1242                 s[length - 2] = '\'';
1243         s[length - 1] = '\0';
1244         return s;
1245 }
1246
1247
1248
1249 static char *
1250 dequote_file_name(char *text, char quote_char)
1251 {
1252         char       *s;
1253         size_t          length;
1254
1255         if (!quote_char)
1256                 return xstrdup(text);
1257
1258         length = strlen(text);
1259         s = malloc(length - 2 + 1);
1260         strncpy(s, text +1, length - 2);
1261         s[length] = '\0';
1262
1263         return s;
1264 }
1265 #endif   /* 0 */
1266
1267 #endif   /* USE_READLINE */