Skip to content

Commit c4e63f7

Browse files
committed
Added new commands and intelligence to psql tab completion.
1 parent c7558b3 commit c4e63f7

File tree

1 file changed

+130
-50
lines changed

1 file changed

+130
-50
lines changed

src/bin/psql/tab-complete.c

Lines changed: 130 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,44 @@
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

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy