-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Attached are some tab-completion enhancements for psql. In rough order, they are: * Made DELETE into "DELETE FROM" * Moved ANALZYE to the end of the list to ease EXPLAIN / VACUUM conflicts * Removed the ANALYZE xx semicolon completion: we don't do that anywhere else * Add DECLARE support * Add parens for DROP AGGREGATE * Add "CASCADE | RESTRICT" for DROP xx * Make EXPLAIN <tab> a lot smarter * GROUP "BY" and ORDER "BY" * "ISOLATION" becomes "ISOLATION LEVEL" * Fix error in which REVOKE xx ON yy was receiving "TO", now gets "FROM" * Add GRANT/REVOKE xx ON yy TO/FROM choices: usernames, GROUP, PUBLIC * PREPARE xx <tab> AS "SELECT | INSERT | UPDATE | DELETE" * Add = at end of UPDATE xx SET yy * Beef up VACUUM stuff - -- Greg Sabino Mullane [EMAIL PROTECTED] PGP Key: 0x14964AC8 200505161845 http://biglumber.com/x/web?pk=2529DF6AB8F79407E94445B4BC9B906714964AC8 -----BEGIN PGP SIGNATURE----- iD8DBQFCiSKGvJuQZxSWSsgRAu72AKCpp9kOoXGt3+4Krew77ShzPhMaiQCdEU08 XYkiOCkrDdYILwEO3QQlLUk= =NmML -----END PGP SIGNATURE-----
Index: tab-complete.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/bin/psql/tab-complete.c,v retrieving revision 1.127 diff -c -r1.127 tab-complete.c *** tab-complete.c 7 May 2005 02:22:49 -0000 1.127 --- tab-complete.c 16 May 2005 19:59:28 -0000 *************** *** 368,373 **** --- 368,379 ---- " FROM pg_catalog.pg_user "\ " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'" + #define Query_for_list_of_grant_users \ + " SELECT pg_catalog.quote_ident(usename) "\ + " FROM pg_catalog.pg_user "\ + " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"\ + " UNION SELECT 'PUBLIC' UNION SELECT 'GROUP'" + /* the silly-looking length condition is just to eat up the current word */ #define Query_for_table_owning_index \ "SELECT pg_catalog.quote_ident(c1.relname) "\ *************** *** 494,500 **** static const char *const sql_commands[] = { "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT", ! "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK", "SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL --- 500,506 ---- static const char *const sql_commands[] = { "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT", ! "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE FROM", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK", "SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL *************** *** 920,932 **** pg_strcasecmp(prev_wd, "USER") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_users); ! /* ANALYZE */ ! /* If the previous word is ANALYZE, produce list of tables. */ ! else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); ! /* If we have ANALYZE <table>, complete with semicolon. */ ! else if (pg_strcasecmp(prev2_wd, "ANALYZE") == 0) ! COMPLETE_WITH_CONST(";"); /* BEGIN, END, COMMIT, ABORT */ else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 || --- 926,932 ---- pg_strcasecmp(prev_wd, "USER") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_users); ! /* ANALYZE - moved to end to ease EXPLAIN / VACUUM conflicts */ /* BEGIN, END, COMMIT, ABORT */ else if (pg_strcasecmp(prev_wd, "BEGIN") == 0 || *************** *** 1149,1154 **** --- 1149,1171 ---- pg_strcasecmp(prev_wd, "AS") == 0) COMPLETE_WITH_CONST("SELECT"); + /* DECLARE */ + + else if (pg_strcasecmp(prev2_wd, "DECLARE") == 0) + { + static const char *const list_DECLARE[] = + {"BINARY", "INSENSITIVE", "SCROLL", "NO SCROLL", "CURSOR", NULL}; + COMPLETE_WITH_LIST(list_DECLARE); + } + + else if (pg_strcasecmp(prev_wd, "CURSOR") == 0) + { + static const char *const list_DECLARECURSOR[] = + {"WITH HOLD", "WITHOUT HOLD", "FOR", NULL}; + COMPLETE_WITH_LIST(list_DECLARECURSOR); + } + + /* DELETE */ /* *************** *** 1176,1191 **** } /* XXX: implement tab completion for DELETE ... USING */ /* EXPLAIN */ /* ! * Complete EXPLAIN [VERBOSE] (which you'd have to type yourself) with ! * the list of SQL commands */ ! else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0 || ! (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 && ! pg_strcasecmp(prev_wd, "VERBOSE") == 0)) ! COMPLETE_WITH_LIST(sql_commands); /* FETCH && MOVE */ /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */ --- 1193,1259 ---- } /* XXX: implement tab completion for DELETE ... USING */ + /* DROP (when not the previous word) */ + /* DROP AGGREGATE */ + else if (pg_strcasecmp(prev3_wd, "DROP") == 0 && + pg_strcasecmp(prev2_wd, "AGGREGATE") == 0) + COMPLETE_WITH_CONST("("); + + /* DROP object with CASCADE / RESTRICT */ + else if ( + ( + pg_strcasecmp(prev3_wd, "DROP") == 0 && + ( + pg_strcasecmp(prev2_wd, "CONVERSION") == 0 || + pg_strcasecmp(prev2_wd, "DOMAIN") == 0 || + pg_strcasecmp(prev2_wd, "FUNCTION") == 0 || + pg_strcasecmp(prev2_wd, "INDEX") == 0 || + pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 || + pg_strcasecmp(prev2_wd, "SCHEMA") == 0 || + pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 || + pg_strcasecmp(prev2_wd, "TABLE") == 0 || + pg_strcasecmp(prev2_wd, "TYPE") == 0 || + pg_strcasecmp(prev2_wd, "VIEW") == 0 + )) || + (pg_strcasecmp(prev4_wd, "DROP") == 0 && + pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 && + prev_wd[strlen(prev_wd) - 1] == ')') + ) + { + static const char *const list_DROPCR[] = + {"CASCADE", "RESTRICT", NULL}; + COMPLETE_WITH_LIST(list_DROPCR); + } + + /* EXPLAIN */ /* ! * Complete EXPLAIN [ANALYZE] [VERBOSE] with list of EXPLAIN-able commands */ ! else if (pg_strcasecmp(prev_wd, "EXPLAIN") == 0) ! { ! static const char *const list_EXPLAIN[] = ! {"SELECT","INSERT","DELETE","UPDATE","DECLARE","ANALYZE","VERBOSE",NULL}; ! COMPLETE_WITH_LIST(list_EXPLAIN); ! } ! else if (pg_strcasecmp(prev2_wd, "EXPLAIN") == 0 && ! pg_strcasecmp(prev_wd, "ANALYZE") == 0) ! { ! static const char *const list_EXPLAIN[] = ! {"SELECT","INSERT","DELETE","UPDATE","DECLARE","VERBOSE",NULL}; ! COMPLETE_WITH_LIST(list_EXPLAIN); ! } ! else if (pg_strcasecmp(prev_wd, "VERBOSE") == 0 && ! pg_strcasecmp(prev3_wd, "VACUUM") != 0 && ! pg_strcasecmp(prev4_wd, "VACUUM") != 0 && ! (pg_strcasecmp(prev2_wd, "ANALYZE") == 0 || ! pg_strcasecmp(prev2_wd, "EXPLAIN") == 0)) ! { ! static const char *const list_EXPLAIN[] = ! {"SELECT","INSERT","DELETE","UPDATE","DECLARE",NULL}; ! COMPLETE_WITH_LIST(list_EXPLAIN); ! } /* FETCH && MOVE */ /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */ *************** *** 1273,1287 **** COMPLETE_WITH_QUERY(Query_for_list_of_schemas); else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); else ! COMPLETE_WITH_CONST("TO"); } ! /* ! * TODO: to complete with user name we need prev5_wd -- wait for a ! * more general solution there same for GRANT <sth> ON { DATABASE | ! * FUNCTION | LANGUAGE | SCHEMA | TABLESPACE } xxx TO ! */ /* INSERT */ /* Complete INSERT with "INTO" */ --- 1341,1364 ---- COMPLETE_WITH_QUERY(Query_for_list_of_schemas); else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); + else if (pg_strcasecmp(prev4_wd, "GRANT") == 0) + COMPLETE_WITH_CONST("TO"); else ! COMPLETE_WITH_CONST("FROM"); } ! /* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */ ! else if (pg_strcasecmp(prev3_wd, "ON") == 0 && ! ((pg_strcasecmp(prev5_wd, "GRANT") == 0 && ! pg_strcasecmp(prev_wd, "TO") == 0) || ! (pg_strcasecmp(prev5_wd, "REVOKE") == 0 && ! pg_strcasecmp(prev_wd, "FROM") == 0))) ! COMPLETE_WITH_QUERY(Query_for_list_of_grant_users); ! ! /* GROUP BY */ ! else if (pg_strcasecmp(prev3_wd, "FROM") == 0 && ! pg_strcasecmp(prev_wd, "GROUP") == 0) ! COMPLETE_WITH_CONST("BY"); /* INSERT */ /* Complete INSERT with "INTO" */ *************** *** 1360,1369 **** --- 1437,1469 ---- /* NOTIFY */ else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0) COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'"); + /* OWNER TO - complete with available users*/ else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 && pg_strcasecmp(prev_wd, "TO") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_users); + + /* ORDER BY */ + else if (pg_strcasecmp(prev3_wd, "FROM") == 0 && + pg_strcasecmp(prev_wd, "ORDER") == 0) + COMPLETE_WITH_CONST("BY"); + + else if (pg_strcasecmp(prev4_wd, "FROM") == 0 && + pg_strcasecmp(prev2_wd, "ORDER") == 0 && + pg_strcasecmp(prev_wd, "BY") == 0) + COMPLETE_WITH_ATTR(prev3_wd); + + /* PREPARE xx AS */ + else if (pg_strcasecmp(prev_wd, "AS") == 0 && + pg_strcasecmp(prev3_wd, "PREPARE") == 0) + { + static const char *const list_PREPARE[] = + {"SELECT", "UPDATE", "INSERT", "DELETE", NULL}; + + COMPLETE_WITH_LIST(list_PREPARE); + } + + /* REINDEX */ else if (pg_strcasecmp(prev_wd, "REINDEX") == 0) { *************** *** 1407,1413 **** && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)) { static const char *const my_list[] = ! {"ISOLATION", "READ", NULL}; COMPLETE_WITH_LIST(my_list); } --- 1507,1513 ---- && pg_strcasecmp(prev_wd, "TRANSACTION") == 0)) { static const char *const my_list[] = ! {"ISOLATION LEVEL", "READ", NULL}; COMPLETE_WITH_LIST(my_list); } *************** *** 1551,1567 **** else if (pg_strcasecmp(prev_wd, "SET") == 0) COMPLETE_WITH_ATTR(prev2_wd); /* VACUUM */ else if (pg_strcasecmp(prev_wd, "VACUUM") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, " UNION SELECT 'FULL'" " UNION SELECT 'ANALYZE'" " UNION SELECT 'VERBOSE'"); else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 && ! (pg_strcasecmp(prev_wd, "FULL") == 0 || ! pg_strcasecmp(prev_wd, "ANALYZE") == 0 || ! pg_strcasecmp(prev_wd, "VERBOSE") == 0)) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* WHERE */ /* Simple case of the word before the where being the table name */ --- 1651,1710 ---- else if (pg_strcasecmp(prev_wd, "SET") == 0) COMPLETE_WITH_ATTR(prev2_wd); + /* UPDATE xx SET yy = */ + else if (pg_strcasecmp(prev2_wd, "SET") == 0 && + pg_strcasecmp(prev4_wd, "UPDATE") == 0) + COMPLETE_WITH_CONST("="); + + /* + VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ] + VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ] + */ + + /* VACUUM */ else if (pg_strcasecmp(prev_wd, "VACUUM") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, " UNION SELECT 'FULL'" + " UNION SELECT 'FREEZE'" " UNION SELECT 'ANALYZE'" " UNION SELECT 'VERBOSE'"); else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 && ! (pg_strcasecmp(prev_wd, "FULL") == 0 || ! pg_strcasecmp(prev_wd, "FREEZE") == 0)) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ! " UNION SELECT 'ANALYZE'" ! " UNION SELECT 'VERBOSE'"); ! else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 && ! pg_strcasecmp(prev_wd, "ANALYZE") == 0 && ! (pg_strcasecmp(prev2_wd, "FULL") == 0 || ! pg_strcasecmp(prev2_wd, "FREEZE") == 0)) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ! " UNION SELECT 'VERBOSE'"); ! else if (pg_strcasecmp(prev3_wd, "VACUUM") == 0 && ! pg_strcasecmp(prev_wd, "VERBOSE") == 0 && ! (pg_strcasecmp(prev2_wd, "FULL") == 0 || ! pg_strcasecmp(prev2_wd, "FREEZE") == 0)) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ! " UNION SELECT 'ANALYZE'"); ! else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 && ! pg_strcasecmp(prev_wd, "VERBOSE") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ! " UNION SELECT 'ANALYZE'"); ! else if (pg_strcasecmp(prev2_wd, "VACUUM") == 0 && ! pg_strcasecmp(prev_wd, "ANALYZE") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, ! " UNION SELECT 'VERBOSE'"); ! else if ((pg_strcasecmp(prev_wd, "ANALYZE") == 0 && ! pg_strcasecmp(prev2_wd, "VERBOSE") == 0) || ! (pg_strcasecmp(prev_wd, "VERBOSE") == 0 && ! pg_strcasecmp(prev2_wd, "ANALYZE") == 0)) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); ! ! /* ANALZYE */ ! /* If the previous word is ANALYZE, produce list of tables */ ! else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0) ! COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* WHERE */ /* Simple case of the word before the where being the table name */
---------------------------(end of broadcast)--------------------------- TIP 6: Have you searched our list archives? http://archives.postgresql.org