33 *
44 * Copyright (c) 2000-2005, PostgreSQL Global Development Group
55 *
6- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.127 2005/05/07 02:22:49 momjian Exp $
6+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.128 2005/05/18 04:47:40 neilc Exp $
77 */
88
99/*----------------------------------------------------------------------
@@ -368,6 +368,12 @@ static const SchemaQuery Query_for_list_of_views = {
368368" FROM pg_catalog.pg_user "\
369369" WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
370370
371+ #define Query_for_list_of_grant_users \
372+ " SELECT pg_catalog.quote_ident(usename) "\
373+ " FROM pg_catalog.pg_user "\
374+ " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"\
375+ " UNION SELECT 'PUBLIC' UNION SELECT 'GROUP'"
376+
371377/* the silly-looking length condition is just to eat up the current word */
372378#define Query_for_table_owning_index \
373379"SELECT pg_catalog.quote_ident(c1.relname) "\
@@ -494,7 +500,7 @@ psql_completion(char *text, int start, int end)
494500
495501 static const char * const sql_commands [] = {
496502 "ABORT" , "ALTER" , "ANALYZE" , "BEGIN" , "CHECKPOINT" , "CLOSE" , "CLUSTER" , "COMMENT" ,
497- "COMMIT" , "COPY" , "CREATE" , "DEALLOCATE" , "DECLARE" , "DELETE" , "DROP" , "END" , "EXECUTE" ,
503+ "COMMIT" , "COPY" , "CREATE" , "DEALLOCATE" , "DECLARE" , "DELETE FROM " , "DROP" , "END" , "EXECUTE" ,
498504 "EXPLAIN" , "FETCH" , "GRANT" , "INSERT" , "LISTEN" , "LOAD" , "LOCK" , "MOVE" , "NOTIFY" ,
499505 "PREPARE" , "REINDEX" , "RELEASE" , "RESET" , "REVOKE" , "ROLLBACK" , "SAVEPOINT" ,
500506 "SELECT" , "SET" , "SHOW" , "START" , "TRUNCATE" , "UNLISTEN" , "UPDATE" , "VACUUM" , NULL
@@ -920,14 +926,6 @@ psql_completion(char *text, int start, int end)
920926 pg_strcasecmp (prev_wd , "USER" ) == 0 )
921927 COMPLETE_WITH_QUERY (Query_for_list_of_users );
922928
923- /* ANALYZE */
924- /* If the previous word is ANALYZE, produce list of tables. */
925- else if (pg_strcasecmp (prev_wd , "ANALYZE" ) == 0 )
926- COMPLETE_WITH_SCHEMA_QUERY (Query_for_list_of_tables , NULL );
927- /* If we have ANALYZE <table>, complete with semicolon. */
928- else if (pg_strcasecmp (prev2_wd , "ANALYZE" ) == 0 )
929- COMPLETE_WITH_CONST (";" );
930-
931929/* BEGIN, END, COMMIT, ABORT */
932930 else if (pg_strcasecmp (prev_wd , "BEGIN" ) == 0 ||
933931 pg_strcasecmp (prev_wd , "END" ) == 0 ||
@@ -1149,8 +1147,23 @@ psql_completion(char *text, int start, int end)
11491147 pg_strcasecmp (prev_wd , "AS" ) == 0 )
11501148 COMPLETE_WITH_CONST ("SELECT" );
11511149
1152- /* DELETE */
1150+ /* DECLARE */
1151+ else if (pg_strcasecmp (prev2_wd , "DECLARE" ) == 0 )
1152+ {
1153+ static const char * const list_DECLARE [] =
1154+ {"BINARY" , "INSENSITIVE" , "SCROLL" , "NO SCROLL" , "CURSOR" , NULL };
1155+ COMPLETE_WITH_LIST (list_DECLARE );
1156+ }
1157+
1158+ else if (pg_strcasecmp (prev_wd , "CURSOR" ) == 0 )
1159+ {
1160+ static const char * const list_DECLARECURSOR [] =
1161+ {"WITH HOLD" , "WITHOUT HOLD" , "FOR" , NULL };
1162+ COMPLETE_WITH_LIST (list_DECLARECURSOR );
1163+ }
11531164
1165+
1166+ /* DELETE */
11541167 /*
11551168 * Complete DELETE with FROM (only if the word before that is not "ON"
11561169 * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT)
@@ -1176,16 +1189,60 @@ psql_completion(char *text, int start, int end)
11761189 }
11771190 /* XXX: implement tab completion for DELETE ... USING */
11781191
1179- /* EXPLAIN */
1192+ /* DROP (when not the previous word) */
1193+ /* DROP AGGREGATE */
1194+ else if (pg_strcasecmp (prev3_wd , "DROP" ) == 0 &&
1195+ pg_strcasecmp (prev2_wd , "AGGREGATE" ) == 0 )
1196+ COMPLETE_WITH_CONST ("(" );
1197+
1198+ /* DROP object with CASCADE / RESTRICT */
1199+ else if ((pg_strcasecmp (prev3_wd , "DROP" ) == 0 &&
1200+ (pg_strcasecmp (prev2_wd , "CONVERSION" ) == 0 ||
1201+ pg_strcasecmp (prev2_wd , "DOMAIN" ) == 0 ||
1202+ pg_strcasecmp (prev2_wd , "FUNCTION" ) == 0 ||
1203+ pg_strcasecmp (prev2_wd , "INDEX" ) == 0 ||
1204+ pg_strcasecmp (prev2_wd , "LANGUAGE" ) == 0 ||
1205+ pg_strcasecmp (prev2_wd , "SCHEMA" ) == 0 ||
1206+ pg_strcasecmp (prev2_wd , "SEQUENCE" ) == 0 ||
1207+ pg_strcasecmp (prev2_wd , "TABLE" ) == 0 ||
1208+ pg_strcasecmp (prev2_wd , "TYPE" ) == 0 ||
1209+ pg_strcasecmp (prev2_wd , "VIEW" ) == 0 )) ||
1210+ (pg_strcasecmp (prev4_wd , "DROP" ) == 0 &&
1211+ pg_strcasecmp (prev3_wd , "AGGREGATE" ) == 0 &&
1212+ prev_wd [strlen (prev_wd ) - 1 ] == ')' ))
1213+ {
1214+ static const char * const list_DROPCR [] =
1215+ {"CASCADE" , "RESTRICT" , NULL };
1216+ COMPLETE_WITH_LIST (list_DROPCR );
1217+ }
11801218
1219+ /* EXPLAIN */
11811220 /*
1182- * Complete EXPLAIN [VERBOSE] (which you'd have to type yourself) with
1183- * the list of SQL commands
1221+ * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands
11841222 */
1185- else if (pg_strcasecmp (prev_wd , "EXPLAIN" ) == 0 ||
1186- (pg_strcasecmp (prev2_wd , "EXPLAIN" ) == 0 &&
1187- pg_strcasecmp (prev_wd , "VERBOSE" ) == 0 ))
1188- COMPLETE_WITH_LIST (sql_commands );
1223+ else if (pg_strcasecmp (prev_wd , "EXPLAIN" ) == 0 )
1224+ {
1225+ static const char * const list_EXPLAIN [] =
1226+ {"SELECT" ,"INSERT" ,"DELETE" ,"UPDATE" ,"DECLARE" ,"ANALYZE" ,"VERBOSE" ,NULL };
1227+ COMPLETE_WITH_LIST (list_EXPLAIN );
1228+ }
1229+ else if (pg_strcasecmp (prev2_wd , "EXPLAIN" ) == 0 &&
1230+ pg_strcasecmp (prev_wd , "ANALYZE" ) == 0 )
1231+ {
1232+ static const char * const list_EXPLAIN [] =
1233+ {"SELECT" ,"INSERT" ,"DELETE" ,"UPDATE" ,"DECLARE" ,"VERBOSE" ,NULL };
1234+ COMPLETE_WITH_LIST (list_EXPLAIN );
1235+ }
1236+ else if (pg_strcasecmp (prev_wd , "VERBOSE" ) == 0 &&
1237+ pg_strcasecmp (prev3_wd , "VACUUM" ) != 0 &&
1238+ pg_strcasecmp (prev4_wd , "VACUUM" ) != 0 &&
1239+ (pg_strcasecmp (prev2_wd , "ANALYZE" ) == 0 ||
1240+ pg_strcasecmp (prev2_wd , "EXPLAIN" ) == 0 ))
1241+ {
1242+ static const char * const list_EXPLAIN [] =
1243+ {"SELECT" ,"INSERT" ,"DELETE" ,"UPDATE" ,"DECLARE" ,NULL };
1244+ COMPLETE_WITH_LIST (list_EXPLAIN );
1245+ }
11891246
11901247/* FETCH && MOVE */
11911248 /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */
@@ -1273,15 +1330,24 @@ psql_completion(char *text, int start, int end)
12731330 COMPLETE_WITH_QUERY (Query_for_list_of_schemas );
12741331 else if (pg_strcasecmp (prev_wd , "TABLESPACE" ) == 0 )
12751332 COMPLETE_WITH_QUERY (Query_for_list_of_tablespaces );
1276- else
1333+ else if ( pg_strcasecmp ( prev4_wd , "GRANT" ) == 0 )
12771334 COMPLETE_WITH_CONST ("TO" );
1335+ else
1336+ COMPLETE_WITH_CONST ("FROM" );
12781337 }
12791338
1280- /*
1281- * TODO: to complete with user name we need prev5_wd -- wait for a
1282- * more general solution there same for GRANT <sth> ON { DATABASE |
1283- * FUNCTION | LANGUAGE | SCHEMA | TABLESPACE } xxx TO
1284- */
1339+ /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
1340+ else if (pg_strcasecmp (prev3_wd , "ON" ) == 0 &&
1341+ ((pg_strcasecmp (prev5_wd , "GRANT" ) == 0 &&
1342+ pg_strcasecmp (prev_wd , "TO" ) == 0 ) ||
1343+ (pg_strcasecmp (prev5_wd , "REVOKE" ) == 0 &&
1344+ pg_strcasecmp (prev_wd , "FROM" ) == 0 )))
1345+ COMPLETE_WITH_QUERY (Query_for_list_of_grant_users );
1346+
1347+ /* GROUP BY */
1348+ else if (pg_strcasecmp (prev3_wd , "FROM" ) == 0 &&
1349+ pg_strcasecmp (prev_wd , "GROUP" ) == 0 )
1350+ COMPLETE_WITH_CONST ("BY" );
12851351
12861352/* INSERT */
12871353 /* Complete INSERT with "INTO" */
@@ -1360,10 +1426,32 @@ psql_completion(char *text, int start, int end)
13601426/* NOTIFY */
13611427 else if (pg_strcasecmp (prev_wd , "NOTIFY" ) == 0 )
13621428 COMPLETE_WITH_QUERY ("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'" );
1429+
13631430/* OWNER TO - complete with available users*/
13641431 else if (pg_strcasecmp (prev2_wd , "OWNER" ) == 0 &&
13651432 pg_strcasecmp (prev_wd , "TO" ) == 0 )
13661433 COMPLETE_WITH_QUERY (Query_for_list_of_users );
1434+
1435+ /* ORDER BY */
1436+ else if (pg_strcasecmp (prev3_wd , "FROM" ) == 0 &&
1437+ pg_strcasecmp (prev_wd , "ORDER" ) == 0 )
1438+ COMPLETE_WITH_CONST ("BY" );
1439+ else if (pg_strcasecmp (prev4_wd , "FROM" ) == 0 &&
1440+ pg_strcasecmp (prev2_wd , "ORDER" ) == 0 &&
1441+ pg_strcasecmp (prev_wd , "BY" ) == 0 )
1442+ COMPLETE_WITH_ATTR (prev3_wd );
1443+
1444+ /* PREPARE xx AS */
1445+ else if (pg_strcasecmp (prev_wd , "AS" ) == 0 &&
1446+ pg_strcasecmp (prev3_wd , "PREPARE" ) == 0 )
1447+ {
1448+ static const char * const list_PREPARE [] =
1449+ {"SELECT" , "UPDATE" , "INSERT" , "DELETE" , NULL };
1450+
1451+ COMPLETE_WITH_LIST (list_PREPARE );
1452+ }
1453+
1454+
13671455/* REINDEX */
13681456 else if (pg_strcasecmp (prev_wd , "REINDEX" ) == 0 )
13691457 {
@@ -1407,7 +1495,7 @@ psql_completion(char *text, int start, int end)
14071495 && pg_strcasecmp (prev_wd , "TRANSACTION" ) == 0 ))
14081496 {
14091497 static const char * const my_list [] =
1410- {"ISOLATION" , "READ" , NULL };
1498+ {"ISOLATION LEVEL " , "READ" , NULL };
14111499
14121500 COMPLETE_WITH_LIST (my_list );
14131501 }
@@ -1501,8 +1589,8 @@ psql_completion(char *text, int start, int end)
15011589 {
15021590 static const char * const my_list [] =
15031591 {"ISO" , "SQL" , "Postgres" , "German" ,
1504- "YMD" , "DMY" , "MDY" ,
1505- "US" , "European" , "NonEuropean" ,
1592+ "YMD" , "DMY" , "MDY" ,
1593+ "US" , "European" , "NonEuropean" ,
15061594 "DEFAULT" , NULL };
15071595
15081596 COMPLETE_WITH_LIST (my_list );
@@ -1551,16 +1639,56 @@ psql_completion(char *text, int start, int end)
15511639 else if (pg_strcasecmp (prev_wd , "SET" ) == 0 )
15521640 COMPLETE_WITH_ATTR (prev2_wd );
15531641
1554- /* VACUUM */
1642+ /* UPDATE xx SET yy = */
1643+ else if (pg_strcasecmp (prev2_wd , "SET" ) == 0 &&
1644+ pg_strcasecmp (prev4_wd , "UPDATE" ) == 0 )
1645+ COMPLETE_WITH_CONST ("=" );
1646+
1647+ /*
1648+ * VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
1649+ * VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
1650+ */
15551651 else if (pg_strcasecmp (prev_wd , "VACUUM" ) == 0 )
15561652 COMPLETE_WITH_SCHEMA_QUERY (Query_for_list_of_tables ,
15571653 " UNION SELECT 'FULL'"
1654+ " UNION SELECT 'FREEZE'"
15581655 " UNION SELECT 'ANALYZE'"
15591656 " UNION SELECT 'VERBOSE'" );
15601657 else if (pg_strcasecmp (prev2_wd , "VACUUM" ) == 0 &&
15611658 (pg_strcasecmp (prev_wd , "FULL" ) == 0 ||
1562- pg_strcasecmp (prev_wd , "ANALYZE" ) == 0 ||
1563- pg_strcasecmp (prev_wd , "VERBOSE" ) == 0 ))
1659+ pg_strcasecmp (prev_wd , "FREEZE" ) == 0 ))
1660+ COMPLETE_WITH_SCHEMA_QUERY (Query_for_list_of_tables ,
1661+ " UNION SELECT 'ANALYZE'"
1662+ " UNION SELECT 'VERBOSE'" );
1663+ else if (pg_strcasecmp (prev3_wd , "VACUUM" ) == 0 &&
1664+ pg_strcasecmp (prev_wd , "ANALYZE" ) == 0 &&
1665+ (pg_strcasecmp (prev2_wd , "FULL" ) == 0 ||
1666+ pg_strcasecmp (prev2_wd , "FREEZE" ) == 0 ))
1667+ COMPLETE_WITH_SCHEMA_QUERY (Query_for_list_of_tables ,
1668+ " UNION SELECT 'VERBOSE'" );
1669+ else if (pg_strcasecmp (prev3_wd , "VACUUM" ) == 0 &&
1670+ pg_strcasecmp (prev_wd , "VERBOSE" ) == 0 &&
1671+ (pg_strcasecmp (prev2_wd , "FULL" ) == 0 ||
1672+ pg_strcasecmp (prev2_wd , "FREEZE" ) == 0 ))
1673+ COMPLETE_WITH_SCHEMA_QUERY (Query_for_list_of_tables ,
1674+ " UNION SELECT 'ANALYZE'" );
1675+ else if (pg_strcasecmp (prev2_wd , "VACUUM" ) == 0 &&
1676+ pg_strcasecmp (prev_wd , "VERBOSE" ) == 0 )
1677+ COMPLETE_WITH_SCHEMA_QUERY (Query_for_list_of_tables ,
1678+ " UNION SELECT 'ANALYZE'" );
1679+ else if (pg_strcasecmp (prev2_wd , "VACUUM" ) == 0 &&
1680+ pg_strcasecmp (prev_wd , "ANALYZE" ) == 0 )
1681+ COMPLETE_WITH_SCHEMA_QUERY (Query_for_list_of_tables ,
1682+ " UNION SELECT 'VERBOSE'" );
1683+ else if ((pg_strcasecmp (prev_wd , "ANALYZE" ) == 0 &&
1684+ pg_strcasecmp (prev2_wd , "VERBOSE" ) == 0 ) ||
1685+ (pg_strcasecmp (prev_wd , "VERBOSE" ) == 0 &&
1686+ pg_strcasecmp (prev2_wd , "ANALYZE" ) == 0 ))
1687+ COMPLETE_WITH_SCHEMA_QUERY (Query_for_list_of_tables , NULL );
1688+
1689+ /* ANALZYE */
1690+ /* If the previous word is ANALYZE, produce list of tables */
1691+ else if (pg_strcasecmp (prev_wd , "ANALYZE" ) == 0 )
15641692 COMPLETE_WITH_SCHEMA_QUERY (Query_for_list_of_tables , NULL );
15651693
15661694/* WHERE */
0 commit comments