3
3
*
4
4
* Copyright 2000 by PostgreSQL Global Development Group
5
5
*
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 $
7
7
*/
8
8
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
+ */
34
44
35
45
#include "postgres.h"
36
46
#include "tab-complete.h"
@@ -120,6 +130,7 @@ pgsql_thing_t words_after_create[] = {
120
130
{"AGGREGATE" ,"SELECT distinct aggname FROM pg_aggregate WHERE substr(aggname,1,%d)='%s'" },
121
131
{"DATABASE" ,"SELECT datname FROM pg_database WHERE substr(datname,1,%d)='%s'" },
122
132
{"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'" },
123
134
{"INDEX" ,"SELECT relname FROM pg_class WHERE relkind='i' and substr(relname,1,%d)='%s'" },
124
135
{"OPERATOR" ,NULL },/* Querying for this is probably not such
125
136
* a good idea. */
@@ -138,11 +149,11 @@ pgsql_thing_t words_after_create[] = {
138
149
139
150
/* The query to get a list of tables and a list of indexes, which are used at
140
151
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
143
154
#define Query_for_list_of_databases words_after_create[1].query
144
155
#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
146
157
147
158
/* A couple of macros to ease typing. You can use these to complete the given
148
159
string with
@@ -179,39 +190,45 @@ psql_completion(char *text, int start, int end)
179
190
* prev4_wd ;
180
191
181
192
static char * sql_commands []= {
182
- "ABORT" ,"ALTER" ,"BEGIN" ,"CLOSE" ,"CLUSTER" ,"COMMIT" ,"COPY" ,
193
+ "ABORT" ,"ALTER" ,"BEGIN" ,"CLOSE" ,"CLUSTER" ,"COMMENT" , " COMMIT" ,"COPY" ,
183
194
"CREATE" ,"DECLARE" ,"DELETE" ,"DROP" ,"EXPLAIN" ,"FETCH" ,"GRANT" ,
184
195
"INSERT" ,"LISTEN" ,"LOAD" ,"LOCK" ,"MOVE" ,"NOTIFY" ,"RESET" ,
185
- "REVOKE" ,"ROLLBACK" ,"SELECT" ,"SET" ,"SHOW" ,"UNLISTEN" ,"UPDATE" ,
196
+ "REVOKE" ,"ROLLBACK" ,"SELECT" ,"SET" ,"SHOW" ,"TRUNCATE" , " UNLISTEN" ,"UPDATE" ,
186
197
"VACUUM" ,NULL
187
198
};
188
199
189
200
static char * pgsql_variables []= {
190
201
/* these SET arguments are known in gram.y */
191
- "TRANSACTION ISOLATION LEVEL " ,
202
+ "CONSTRAINTS " ,
192
203
"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 */
194
206
"DateStyle" ,
195
207
"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 */
201
214
"enable_seqscan" ,
202
215
"enable_indexscan" ,
203
216
"enable_tidscan" ,
204
217
"enable_sort" ,
205
218
"enable_nestloop" ,
206
219
"enable_mergejoin" ,
207
220
"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" ,
212
226
"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" ,
215
232
NULL
216
233
};
217
234
@@ -260,25 +277,41 @@ psql_completion(char *text, int start, int end)
260
277
matches = completion_matches (text ,create_command_generator );
261
278
262
279
/* ALTER */
263
- /* complete with what you can alter (TABLE or USER) */
280
+ /* complete with what you can alter (TABLE, GROUP, USER) */
264
281
else if (strcasecmp (prev_wd ,"ALTER" )== 0 )
265
282
{
266
- char * list_ALTER []= {"TABLE" ,"USER" ,NULL };
283
+ char * list_ALTER []= {"GROUP" , " TABLE" ,"USER" ,NULL };
267
284
268
285
COMPLETE_WITH_LIST (list_ALTER );
269
286
}
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 */
271
288
else if (strcasecmp (prev3_wd ,"ALTER" )== 0 && strcasecmp (prev2_wd ,"TABLE" )== 0 )
272
289
{
273
- char * list_ALTER2 []= {"ADD" ,"RENAME" ,NULL };
290
+ char * list_ALTER2 []= {"ADD" ,"ALTER" , " RENAME" ,NULL };
274
291
275
292
COMPLETE_WITH_LIST (list_ALTER2 );
276
293
}
277
- /* If we have TABLE <sth>ADD |RENAME, provide list of columns */
294
+ /* If we have TABLE <sth>ALTER |RENAME, provide list of columns */
278
295
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 ))
280
297
COMPLETE_WITH_ATTR (prev2_wd );
281
298
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
+
282
315
/* CLUSTER */
283
316
/* If the previous word is CLUSTER, produce list of indexes. */
284
317
else if (strcasecmp (prev_wd ,"CLUSTER" )== 0 )
@@ -304,6 +337,19 @@ psql_completion(char *text, int start, int end)
304
337
COMPLETE_WITH_QUERY (query_buffer );
305
338
}
306
339
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
+
307
353
/* COPY */
308
354
309
355
/*
@@ -510,6 +556,26 @@ psql_completion(char *text, int start, int end)
510
556
COMPLETE_WITH_QUERY (Query_for_list_of_tables );
511
557
/* (If you want more with LOCK, you better think about it yourself.) */
512
558
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
+
513
579
/* SELECT */
514
580
/* naah . . . */
515
581
@@ -540,6 +606,12 @@ psql_completion(char *text, int start, int end)
540
606
strcasecmp (prev2_wd ,"LEVEL" )== 0 &&
541
607
strcasecmp (prev_wd ,"READ" )== 0 )
542
608
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
+ }
543
615
/* Complete SET <var> with "TO" */
544
616
else if (strcasecmp (prev2_wd ,"SET" )== 0 &&
545
617
strcasecmp (prev4_wd ,"UPDATE" )!= 0 )
@@ -568,6 +640,14 @@ psql_completion(char *text, int start, int end)
568
640
}
569
641
}
570
642
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
+
571
651
/* UPDATE */
572
652
/* If prev. word is UPDATE suggest a list of tables */
573
653
else if (strcasecmp (prev_wd ,"UPDATE" )== 0 )