33 *
44 * Copyright 2000 by PostgreSQL Global Development Group
55 *
6- * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.19 2000/05/05 08:44:27 petere Exp $
6+ * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.20 2000/06/25 14:25:51 petere Exp $
77 */
88
9- /*-----------
10- This file implements a somewhat more sophisticated readline "TAB completion"
11- in psql. It is not intended to be AI, to replace learning SQL, or to relieve
12- you from thinking about what you're doing. Also it does not always give you
13- all the syntactically legal completions, only those that are the most common
14- or the ones that the programmer felt most like implementing.
15-
16- CAVEAT: Tab completion causes queries to be sent to the backend. The number
17- tuples returned gets limited, in most default installations to 101, but if
18- you still don't like this prospect, you can turn off tab completion in your
19- ~/.inputrc (or else ${INPUTRC}) file so:
20- $if psql
21- TAB: self-insert
22- $endif
23- See `man 3 readline` or `info readline` for the full details. Also, hence the
24-
25- BUGS:
26- * If you split your queries across lines, this whole things gets confused.
27- (To fix this, one would have to read psql's query buffer rather than
28- readline's line buffer, which would require some major revisions of
29- things.)
30- * Table or attribute names with spaces in it will equally confuse it.
31- * Quotes, parenthesis, and other funny characters are not handled all that
32- gracefully.
33- -------------*/
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 will equally confuse
38+ * it.
39+ *
40+ * - Quotes, parenthesis, and other funny characters are not handled
41+ * all that gracefully.
42+ *----------------------------------------------------------------------
43+ */
3444
3545#include "postgres.h"
3646#include "tab-complete.h"
@@ -120,6 +130,7 @@ pgsql_thing_t words_after_create[] = {
120130 {"AGGREGATE" , "SELECT distinct aggname FROM pg_aggregate WHERE substr(aggname,1,%d)='%s'" },
121131 {"DATABASE" , "SELECT datname FROM pg_database WHERE substr(datname,1,%d)='%s'" },
122132 {"FUNCTION" , "SELECT distinct proname FROM pg_proc WHERE substr(proname,1,%d)='%s'" },
133+ {"GROUP" , "SELECT groname FROM pg_group WHERE substr(groname,1,%d)='%s'" },
123134 {"INDEX" , "SELECT relname FROM pg_class WHERE relkind='i' and substr(relname,1,%d)='%s'" },
124135 {"OPERATOR" , NULL }, /* Querying for this is probably not such
125136 * a good idea. */
@@ -138,11 +149,11 @@ pgsql_thing_t words_after_create[] = {
138149
139150/* The query to get a list of tables and a list of indexes, which are used at
140151 various places. */
141- #define Query_for_list_of_tables words_after_create[7 ].query
142- #define Query_for_list_of_indexes words_after_create[3 ].query
152+ #define Query_for_list_of_tables words_after_create[8 ].query
153+ #define Query_for_list_of_indexes words_after_create[4 ].query
143154#define Query_for_list_of_databases words_after_create[1].query
144155#define Query_for_list_of_attributes "SELECT a.attname FROM pg_attribute a, pg_class c WHERE c.oid = a.attrelid and a.attnum>0 and substr(a.attname,1,%d)='%s' and c.relname='%s'"
145-
156+ #define Query_for_list_of_users words_after_create[13].query
146157
147158/* A couple of macros to ease typing. You can use these to complete the given
148159 string with
@@ -179,39 +190,45 @@ psql_completion(char *text, int start, int end)
179190 * prev4_wd ;
180191
181192 static char * sql_commands [] = {
182- "ABORT" , "ALTER" , "BEGIN" , "CLOSE" , "CLUSTER" , "COMMIT" , "COPY" ,
193+ "ABORT" , "ALTER" , "BEGIN" , "CLOSE" , "CLUSTER" , "COMMENT" , " COMMIT" , "COPY" ,
183194 "CREATE" , "DECLARE" , "DELETE" , "DROP" , "EXPLAIN" , "FETCH" , "GRANT" ,
184195 "INSERT" , "LISTEN" , "LOAD" , "LOCK" , "MOVE" , "NOTIFY" , "RESET" ,
185- "REVOKE" , "ROLLBACK" , "SELECT" , "SET" , "SHOW" , "UNLISTEN" , "UPDATE" ,
196+ "REVOKE" , "ROLLBACK" , "SELECT" , "SET" , "SHOW" , "TRUNCATE" , " UNLISTEN" , "UPDATE" ,
186197 "VACUUM" , NULL
187198 };
188199
189200 static char * pgsql_variables [] = {
190201 /* these SET arguments are known in gram.y */
191- "TRANSACTION ISOLATION LEVEL " ,
202+ "CONSTRAINTS " ,
192203 "NAMES" ,
193- /* rest should match table in src/backend/commands/variable.c */
204+ "TRANSACTION ISOLATION LEVEL" ,
205+ /* these are treated in backend/commands/variable.c */
194206 "DateStyle" ,
195207 "TimeZone" ,
196- "effective_cache_size" ,
197- "random_page_cost" ,
198- "cpu_tuple_cost" ,
199- "cpu_index_tuple_cost" ,
200- "cpu_operator_cost" ,
208+ "client_encoding" ,
209+ "server_encoding" ,
210+ "random_seed" ,
211+ /* the rest should match USERSET and SUSET entries in
212+ * backend/utils/misc/guc.c, but feel free to leave out the
213+ * esoteric or debug settings */
201214 "enable_seqscan" ,
202215 "enable_indexscan" ,
203216 "enable_tidscan" ,
204217 "enable_sort" ,
205218 "enable_nestloop" ,
206219 "enable_mergejoin" ,
207220 "enable_hashjoin" ,
208- "GEQO" ,
209- "client_encoding" ,
210- "server_encoding" ,
211- "KSQO" ,
221+ "geqo" ,
222+ "ksqo" ,
223+ "sql_inheritance" ,
224+ "sort_mem" ,
225+ "debug_level" ,
212226 "max_expr_depth" ,
213- "XactIsoLevel" ,
214- "PG_Options" ,
227+ "effective_cache_size" ,
228+ "random_page_cost" ,
229+ "cpu_tuple_cost" ,
230+ "cpu_index_tuple_cost" ,
231+ "cpu_operator_cost" ,
215232 NULL
216233 };
217234
@@ -260,25 +277,41 @@ psql_completion(char *text, int start, int end)
260277 matches = completion_matches (text , create_command_generator );
261278
262279/* ALTER */
263- /* complete with what you can alter (TABLE or USER) */
280+ /* complete with what you can alter (TABLE, GROUP, USER) */
264281 else if (strcasecmp (prev_wd , "ALTER" ) == 0 )
265282 {
266- char * list_ALTER [] = {"TABLE" , "USER" , NULL };
283+ char * list_ALTER [] = {"GROUP" , " TABLE" , "USER" , NULL };
267284
268285 COMPLETE_WITH_LIST (list_ALTER );
269286 }
270- /* If we detect ALTER TABLE <name>, suggest either " ADD" or " RENAME" */
287+ /* If we detect ALTER TABLE <name>, suggest either ADD, ALTER, or RENAME */
271288 else if (strcasecmp (prev3_wd , "ALTER" ) == 0 && strcasecmp (prev2_wd , "TABLE" ) == 0 )
272289 {
273- char * list_ALTER2 [] = {"ADD" , "RENAME" , NULL };
290+ char * list_ALTER2 [] = {"ADD" , "ALTER" , " RENAME" , NULL };
274291
275292 COMPLETE_WITH_LIST (list_ALTER2 );
276293 }
277- /* If we have TABLE <sth> ADD |RENAME, provide list of columns */
294+ /* If we have TABLE <sth> ALTER |RENAME, provide list of columns */
278295 else if (strcasecmp (prev3_wd , "TABLE" ) == 0 &&
279- (strcasecmp (prev_wd , "ADD " ) == 0 || strcasecmp (prev_wd , "RENAME" ) == 0 ))
296+ (strcasecmp (prev_wd , "ALTER " ) == 0 || strcasecmp (prev_wd , "RENAME" ) == 0 ))
280297 COMPLETE_WITH_ATTR (prev2_wd );
281298
299+ /* complete ALTER GROUP <foo> with ADD or DROP */
300+ else if (strcasecmp (prev3_wd , "ALTER" ) == 0 && strcasecmp (prev2_wd , "GROUP" ) == 0 )
301+ {
302+ char * list_ALTERGROUP [] = {"ADD" , "DROP" , NULL };
303+ COMPLETE_WITH_LIST (list_ALTERGROUP );
304+ }
305+ /* complete ALTER GROUP <foo> ADD|DROP with USER */
306+ else if (strcasecmp (prev4_wd , "ALTER" ) == 0 && strcasecmp (prev3_wd , "GROUP" ) == 0
307+ && (strcasecmp (prev_wd , "ADD" )== 0 || strcasecmp (prev_wd , "DROP" )== 0 ))
308+ COMPLETE_WITH_CONST ("USER" );
309+ /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */
310+ else if (strcasecmp (prev4_wd , "GROUP" ) == 0
311+ && (strcasecmp (prev2_wd , "ADD" )== 0 || strcasecmp (prev2_wd , "DROP" )== 0 )
312+ && strcasecmp (prev_wd , "USER" ) == 0 )
313+ COMPLETE_WITH_QUERY (Query_for_list_of_users );
314+
282315/* CLUSTER */
283316 /* If the previous word is CLUSTER, produce list of indexes. */
284317 else if (strcasecmp (prev_wd , "CLUSTER" ) == 0 )
@@ -304,6 +337,19 @@ psql_completion(char *text, int start, int end)
304337 COMPLETE_WITH_QUERY (query_buffer );
305338 }
306339
340+ /* COMMENT */
341+ else if (strcasecmp (prev_wd , "COMMENT" )== 0 )
342+ COMPLETE_WITH_CONST ("ON" );
343+ else if (strcasecmp (prev2_wd , "COMMENT" )== 0 && strcasecmp (prev_wd , "ON" )== 0 )
344+ {
345+ char * list_COMMENT [] =
346+ {"DATABASE" , "INDEX" , "RULE" , "SEQUENCE" , "TABLE" , "TYPE" , "VIEW" ,
347+ "COLUMN" , "AGGREGATE" , "FUNCTION" , "OPERATOR" , "TRIGGER" , NULL };
348+ COMPLETE_WITH_LIST (list_COMMENT );
349+ }
350+ else if (strcasecmp (prev4_wd , "COMMENT" )== 0 && strcasecmp (prev3_wd , "ON" )== 0 )
351+ COMPLETE_WITH_CONST ("IS" );
352+
307353/* COPY */
308354
309355 /*
@@ -510,6 +556,26 @@ psql_completion(char *text, int start, int end)
510556 COMPLETE_WITH_QUERY (Query_for_list_of_tables );
511557 /* (If you want more with LOCK, you better think about it yourself.) */
512558
559+ /* NOTIFY */
560+ else if (strcasecmp (prev_wd , "NOTIFY" )== 0 )
561+ COMPLETE_WITH_QUERY ("SELECT relname FROM pg_listener WHERE substr(relname,1,%d)='%s'" );
562+
563+ /* REINDEX */
564+ else if (strcasecmp (prev_wd , "REINDEX" ) == 0 )
565+ {
566+ char * list_REINDEX [] = {"TABLE" , "DATABASE" , "INDEX" , NULL };
567+ COMPLETE_WITH_LIST (list_REINDEX );
568+ }
569+ else if (strcasecmp (prev2_wd , "REINDEX" )== 0 )
570+ {
571+ if (strcasecmp (prev_wd , "TABLE" )== 0 )
572+ COMPLETE_WITH_QUERY (Query_for_list_of_tables );
573+ else if (strcasecmp (prev_wd , "DATABASE" )== 0 )
574+ COMPLETE_WITH_QUERY (Query_for_list_of_databases );
575+ else if (strcasecmp (prev_wd , "INDEX" )== 0 )
576+ COMPLETE_WITH_QUERY (Query_for_list_of_indexes );
577+ }
578+
513579/* SELECT */
514580 /* naah . . . */
515581
@@ -540,6 +606,12 @@ psql_completion(char *text, int start, int end)
540606 strcasecmp (prev2_wd , "LEVEL" ) == 0 &&
541607 strcasecmp (prev_wd , "READ" ) == 0 )
542608 COMPLETE_WITH_CONST ("COMMITTED" );
609+ /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */
610+ else if (strcasecmp (prev3_wd , "SET" )== 0 && strcasecmp (prev2_wd , "CONSTRAINTS" )== 0 )
611+ {
612+ char * constraint_list [] = {"DEFERRED" , "IMMEDIATE" , NULL };
613+ COMPLETE_WITH_LIST (constraint_list );
614+ }
543615 /* Complete SET <var> with "TO" */
544616 else if (strcasecmp (prev2_wd , "SET" ) == 0 &&
545617 strcasecmp (prev4_wd , "UPDATE" ) != 0 )
@@ -568,6 +640,14 @@ psql_completion(char *text, int start, int end)
568640 }
569641 }
570642
643+ /* TRUNCATE */
644+ else if (strcasecmp (prev_wd , "TRUNCATE" )== 0 )
645+ COMPLETE_WITH_QUERY (Query_for_list_of_tables );
646+
647+ /* UNLISTEN */
648+ else if (strcasecmp (prev_wd , "UNLISTEN" )== 0 )
649+ COMPLETE_WITH_QUERY ("SELECT relname FROM pg_listener WHERE substr(relname,1,%d)='%s' UNION SELECT '*'::text" );
650+
571651/* UPDATE */
572652 /* If prev. word is UPDATE suggest a list of tables */
573653 else if (strcasecmp (prev_wd , "UPDATE" ) == 0 )
0 commit comments