Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit121213d

Browse files
committed
Improve tab completion for ANALYZE, EXPLAIN, and VACUUM.
Previously, we made no attempt to provide tab completion in thesestatements' optional parenthesized options lists. This patch teachespsql to do so.To prevent the option completions from being offered after we've alreadyseen a complete parenthesized option list, it's necessary to improveword_matches() so that it allows a wildcard '*' in the middle of analternative, not only at the end as formerly. That requires only alittle more code than before, and it allows us to test for "incompleteparenthesized options" with a test like else if (HeadMatches2("EXPLAIN", "(*") && !HeadMatches2("EXPLAIN", "(*)"))In addition, add some logic to offer column names in the context of"ANALYZE tablename ( ...", and likewise for VACUUM. This isn't realcomplete; it won't offer column names again after a comma. But it'sbetter than before, and it doesn't take much code.Justin Pryzby, reviewed at various times by Álvaro Herrera, ArthurZakirov, and Edmund Horner; some additional fixups by meDiscussion:https://postgr.es/m/20180529000623.GA21896@telsasoft.com
1 parente3b7a6d commit121213d

File tree

1 file changed

+87
-40
lines changed

1 file changed

+87
-40
lines changed

‎src/bin/psql/tab-complete.c

Lines changed: 87 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,9 +1131,8 @@ initialize_readline(void)
11311131
* If pattern is NULL, it's a wild card that matches any word.
11321132
* If pattern begins with '!', the result is negated, ie we check that 'word'
11331133
* does *not* match any alternative appearing in the rest of 'pattern'.
1134-
* Any alternative can end with '*' which is a wild card, i.e., it means
1135-
* match any word that matches the characters so far. (We do not currently
1136-
* support '*' elsewhere than the end of an alternative.)
1134+
* Any alternative can contain '*' which is a wild card, i.e., it can match
1135+
* any substring; however, we allow at most one '*' per alternative.
11371136
*
11381137
* For readability, callers should use the macros MatchAny and MatchAnyExcept
11391138
* to invoke those two special cases for 'pattern'. (But '|' and '*' must
@@ -1147,8 +1146,10 @@ word_matches_internal(const char *pattern,
11471146
constchar*word,
11481147
boolcase_sensitive)
11491148
{
1150-
size_twordlen,
1151-
patternlen;
1149+
size_twordlen;
1150+
1151+
#definecimatch(s1,s2,n) \
1152+
(case_sensitive ? strncmp(s1, s2, n) == 0 : pg_strncasecmp(s1, s2, n) == 0)
11521153

11531154
/* NULL pattern matches anything. */
11541155
if (pattern==NULL)
@@ -1162,31 +1163,34 @@ word_matches_internal(const char *pattern,
11621163
wordlen=strlen(word);
11631164
for (;;)
11641165
{
1166+
constchar*star=NULL;
11651167
constchar*c;
11661168

1167-
/* Find end of current alternative. */
1169+
/* Find end of current alternative, and locate any wild card. */
11681170
c=pattern;
11691171
while (*c!='\0'&&*c!='|')
1172+
{
1173+
if (*c=='*')
1174+
star=c;
11701175
c++;
1171-
/* Was there a wild card? (Assumes first alternative is not empty) */
1172-
if (c[-1]=='*')
1176+
}
1177+
/* Was there a wild card? */
1178+
if (star)
11731179
{
11741180
/* Yes, wildcard match? */
1175-
patternlen=c-pattern-1;
1176-
if (wordlen >=patternlen&&
1177-
(case_sensitive ?
1178-
strncmp(word,pattern,patternlen)==0 :
1179-
pg_strncasecmp(word,pattern,patternlen)==0))
1181+
size_tbeforelen=star-pattern,
1182+
afterlen=c-star-1;
1183+
1184+
if (wordlen >= (beforelen+afterlen)&&
1185+
cimatch(word,pattern,beforelen)&&
1186+
cimatch(word+wordlen-afterlen,star+1,afterlen))
11801187
return true;
11811188
}
11821189
else
11831190
{
11841191
/* No, plain match? */
1185-
patternlen=c-pattern;
1186-
if (wordlen==patternlen&&
1187-
(case_sensitive ?
1188-
strncmp(word,pattern,wordlen)==0 :
1189-
pg_strncasecmp(word,pattern,wordlen)==0))
1192+
if (wordlen== (c-pattern)&&
1193+
cimatch(word,pattern,wordlen))
11901194
return true;
11911195
}
11921196
/* Out of alternatives? */
@@ -2158,6 +2162,24 @@ psql_completion(const char *text, int start, int end)
21582162
elseif (Matches5("ALTER","TYPE",MatchAny,"RENAME","VALUE"))
21592163
COMPLETE_WITH_ENUM_VALUE(prev3_wd);
21602164

2165+
/*
2166+
* ANALYZE [ ( option [, ...] ) ] [ table_and_columns [, ...] ]
2167+
* ANALYZE [ VERBOSE ] [ table_and_columns [, ...] ]
2168+
*
2169+
* Currently the only allowed option is VERBOSE, so we can be skimpier on
2170+
* the option processing than VACUUM has to be.
2171+
*/
2172+
elseif (Matches1("ANALYZE"))
2173+
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_analyzables,
2174+
" UNION SELECT 'VERBOSE'");
2175+
elseif (Matches2("ANALYZE","("))
2176+
COMPLETE_WITH_CONST("VERBOSE)");
2177+
elseif (HeadMatches1("ANALYZE")&&TailMatches1("("))
2178+
/* "ANALYZE (" should be caught above, so assume we want columns */
2179+
COMPLETE_WITH_ATTR(prev2_wd,"");
2180+
elseif (HeadMatches1("ANALYZE"))
2181+
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_analyzables,NULL);
2182+
21612183
/* BEGIN */
21622184
elseif (Matches1("BEGIN"))
21632185
COMPLETE_WITH_LIST6("WORK","TRANSACTION","ISOLATION LEVEL","READ","DEFERRABLE","NOT DEFERRABLE");
@@ -2817,18 +2839,34 @@ psql_completion(const char *text, int start, int end)
28172839
elseif (Matches1("EXECUTE"))
28182840
COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
28192841

2820-
/* EXPLAIN */
2821-
2822-
/*
2823-
* Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
2824-
*/
2842+
/*
2843+
* EXPLAIN [ ( option [, ...] ) ] statement
2844+
* EXPLAIN [ ANALYZE ] [ VERBOSE ] statement
2845+
*/
28252846
elseif (Matches1("EXPLAIN"))
28262847
COMPLETE_WITH_LIST7("SELECT","INSERT","DELETE","UPDATE","DECLARE",
28272848
"ANALYZE","VERBOSE");
2849+
elseif (HeadMatches2("EXPLAIN","(*")&&
2850+
!HeadMatches2("EXPLAIN","(*)"))
2851+
{
2852+
/*
2853+
* This fires if we're in an unfinished parenthesized option list.
2854+
* get_previous_words treats a completed parenthesized option list as
2855+
* one word, so the above test is correct.
2856+
*/
2857+
if (ends_with(prev_wd,'(')||ends_with(prev_wd,','))
2858+
COMPLETE_WITH_LIST7("ANALYZE","VERBOSE","COSTS","BUFFERS",
2859+
"TIMING","SUMMARY","FORMAT");
2860+
elseif (TailMatches1("ANALYZE|VERBOSE|COSTS|BUFFERS|TIMING|SUMMARY"))
2861+
COMPLETE_WITH_LIST2("ON","OFF");
2862+
elseif (TailMatches1("FORMAT"))
2863+
COMPLETE_WITH_LIST4("TEXT","XML","JSON","YAML");
2864+
}
28282865
elseif (Matches2("EXPLAIN","ANALYZE"))
28292866
COMPLETE_WITH_LIST6("SELECT","INSERT","DELETE","UPDATE","DECLARE",
28302867
"VERBOSE");
2831-
elseif (Matches2("EXPLAIN","VERBOSE")||
2868+
elseif (Matches2("EXPLAIN","(*)")||
2869+
Matches2("EXPLAIN","VERBOSE")||
28322870
Matches3("EXPLAIN","ANALYZE","VERBOSE"))
28332871
COMPLETE_WITH_LIST5("SELECT","INSERT","DELETE","UPDATE","DECLARE");
28342872

@@ -3383,31 +3421,45 @@ psql_completion(const char *text, int start, int end)
33833421
COMPLETE_WITH_CONST("OPTIONS");
33843422

33853423
/*
3386-
* VACUUM [FULL | FREEZE ] [ VERBOSE] [table ]
3387-
* VACUUM [ FULL|FREEZE ] [ VERBOSE ]ANALYZE [ table [ (column [, ...] )] ]
3424+
* VACUUM [( option [, ...] )] [table_and_columns [, ...] ]
3425+
* VACUUM [ FULL] [FREEZE ] [ VERBOSE ][ ANALYZE ] [ table_and_columns [, ...] ]
33883426
*/
33893427
elseif (Matches1("VACUUM"))
33903428
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_vacuumables,
33913429
" UNION SELECT 'FULL'"
33923430
" UNION SELECT 'FREEZE'"
33933431
" UNION SELECT 'ANALYZE'"
33943432
" UNION SELECT 'VERBOSE'");
3395-
elseif (Matches2("VACUUM","FULL|FREEZE"))
3433+
elseif (Matches2("VACUUM","FULL"))
33963434
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_vacuumables,
3435+
" UNION SELECT 'FREEZE'"
33973436
" UNION SELECT 'ANALYZE'"
33983437
" UNION SELECT 'VERBOSE'");
3399-
elseif (Matches3("VACUUM","FULL|FREEZE","ANALYZE"))
3400-
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_vacuumables,
3401-
" UNION SELECT 'VERBOSE'");
3402-
elseif (Matches3("VACUUM","FULL|FREEZE","VERBOSE"))
3438+
elseif (Matches2("VACUUM","FREEZE")||
3439+
Matches3("VACUUM","FULL","FREEZE"))
34033440
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_vacuumables,
3441+
" UNION SELECT 'VERBOSE'"
34043442
" UNION SELECT 'ANALYZE'");
3405-
elseif (Matches2("VACUUM","VERBOSE"))
3443+
elseif (Matches2("VACUUM","VERBOSE")||
3444+
Matches3("VACUUM","FULL|FREEZE","VERBOSE")||
3445+
Matches4("VACUUM","FULL","FREEZE","VERBOSE"))
34063446
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_vacuumables,
34073447
" UNION SELECT 'ANALYZE'");
3408-
elseif (Matches2("VACUUM","ANALYZE"))
3409-
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_vacuumables,
3410-
" UNION SELECT 'VERBOSE'");
3448+
elseif (HeadMatches2("VACUUM","(*")&&
3449+
!HeadMatches2("VACUUM","(*)"))
3450+
{
3451+
/*
3452+
* This fires if we're in an unfinished parenthesized option list.
3453+
* get_previous_words treats a completed parenthesized option list as
3454+
* one word, so the above test is correct.
3455+
*/
3456+
if (ends_with(prev_wd,'(')||ends_with(prev_wd,','))
3457+
COMPLETE_WITH_LIST5("FULL","FREEZE","ANALYZE","VERBOSE",
3458+
"DISABLE_PAGE_SKIPPING");
3459+
}
3460+
elseif (HeadMatches1("VACUUM")&&TailMatches1("("))
3461+
/* "VACUUM (" should be caught above, so assume we want columns */
3462+
COMPLETE_WITH_ATTR(prev2_wd,"");
34113463
elseif (HeadMatches1("VACUUM"))
34123464
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_vacuumables,NULL);
34133465

@@ -3420,11 +3472,6 @@ psql_completion(const char *text, int start, int end)
34203472
elseif (Matches1("WITH"))
34213473
COMPLETE_WITH_CONST("RECURSIVE");
34223474

3423-
/* ANALYZE */
3424-
/* Complete with list of appropriate relations */
3425-
elseif (Matches1("ANALYZE"))
3426-
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_analyzables,NULL);
3427-
34283475
/* WHERE */
34293476
/* Simple case of the word before the where being the table name */
34303477
elseif (TailMatches2(MatchAny,"WHERE"))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp