📄 tab-complete.c
字号:
char *prev_wd, *prev2_wd, *prev3_wd, *prev4_wd; static const char * const sql_commands[] = { "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE", "DROP", "EXECUTE", "EXPLAIN", "FETCH", "GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE", "REINDEX", "RESET", "REVOKE", "ROLLBACK", "SELECT", "SET", "SHOW", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", NULL }; static const char * const pgsql_variables[] = { /* these SET arguments are known in gram.y */ "CONSTRAINTS", "NAMES", "SESSION", "TRANSACTION", /* * the rest should match USERSET and possibly SUSET entries in * backend/utils/misc/guc.c. */ "add_missing_from", "australian_timezones", "client_encoding", "client_min_messages", "commit_delay", "commit_siblings", "cpu_index_tuple_cost", "cpu_operator_cost", "cpu_tuple_cost", "DateStyle", "deadlock_timeout", "debug_pretty_print", "debug_print_parse", "debug_print_plan", "debug_print_rewritten", "default_statistics_target", "default_transaction_isolation", "default_transaction_read_only", "dynamic_library_path", "effective_cache_size", "enable_hashagg", "enable_hashjoin", "enable_indexscan", "enable_mergejoin", "enable_nestloop", "enable_seqscan", "enable_sort", "enable_tidscan", "explain_pretty_print", "extra_float_digits", "from_collapse_limit", "fsync", "geqo", "geqo_effort", "geqo_generations", "geqo_pool_size", "geqo_selection_bias", "geqo_threshold", "join_collapse_limit", "krb_server_keyfile", "lc_messages", "lc_monetary", "lc_numeric", "lc_time", "log_duration", "log_error_verbosity", "log_executor_stats", "log_min_duration_statement", "log_min_error_statement", "log_min_messages", "log_parser_stats", "log_planner_stats", "log_statement", "log_statement_stats", "max_connections", "max_expr_depth", "max_files_per_process", "max_fsm_pages", "max_fsm_relations", "max_locks_per_transaction", "password_encryption", "port", "random_page_cost", "regex_flavor", "search_path", "shared_buffers", "seed", "server_encoding", "sort_mem", "sql_inheritance", "ssl", "statement_timeout", "stats_block_level", "stats_command_string", "stats_reset_on_server_start", "stats_row_level", "stats_start_collector", "superuser_reserved_connections", "syslog", "syslog_facility", "syslog_ident", "tcpip_socket", "TimeZone", "trace_notify", "transform_null_equals", "unix_socket_directory", "unix_socket_group", "unix_socket_permissions", "vacuum_mem", "wal_buffers", "wal_debug", "wal_sync_method", NULL }; static const char * const backslash_commands[] = { "\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright", "\\d", "\\da", "\\dc", "\\dC", "\\dd", "\\dD", "\\df", "\\di", "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du", "\\e", "\\echo", "\\encoding", "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l", "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink", "\\o", "\\p", "\\pset", "\\q", "\\qecho", "\\r", "\\set", "\\t", "\\T", "\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL }; (void) end; /* not used */#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER rl_completion_append_character = ' ';#endif /* Clear a few things. */ completion_charp = NULL; completion_charpp = NULL; completion_info_charp = NULL; /* * Scan the input line before our current position for the last four * words. According to those we'll make some smart decisions on what * the user is probably intending to type. TODO: Use strtokx() to do * this. */ prev_wd = previous_word(start, 0); prev2_wd = previous_word(start, 1); prev3_wd = previous_word(start, 2); prev4_wd = previous_word(start, 3); /* If a backslash command was started, continue */ if (text[0] == '\\') COMPLETE_WITH_LIST(backslash_commands); /* If no previous word, suggest one of the basic sql commands */ else if (!prev_wd) COMPLETE_WITH_LIST(sql_commands);/* CREATE or DROP but not ALTER TABLE sth DROP */ /* complete with something you can create or drop */ else if (strcasecmp(prev_wd, "CREATE") == 0 || (strcasecmp(prev_wd, "DROP") == 0 && strcasecmp(prev3_wd, "TABLE") != 0)) matches = completion_matches(text, create_command_generator);/* ALTER */ /* * complete with what you can alter (TABLE, GROUP, USER, ...) unless * we're in ALTER TABLE sth ALTER */ else if (strcasecmp(prev_wd, "ALTER") == 0 && strcasecmp(prev3_wd, "TABLE") != 0) { static const char *const list_ALTER[] = {"DATABASE", "GROUP", "SCHEMA", "TABLE", "TRIGGER", "USER", NULL}; COMPLETE_WITH_LIST(list_ALTER); } /* ALTER DATABASE <name> */ else if (strcasecmp(prev3_wd, "ALTER") == 0 && strcasecmp(prev2_wd, "DATABASE") == 0) { static const char *const list_ALTERDATABASE[] = {"RESET", "SET", "RENAME TO", NULL}; COMPLETE_WITH_LIST(list_ALTERDATABASE); } /* ALTER TRIGGER <name>, add ON */ else if (strcasecmp(prev3_wd, "ALTER") == 0 && strcasecmp(prev2_wd, "TRIGGER") == 0) COMPLETE_WITH_CONST("ON"); /* * If we have ALTER TRIGGER <sth> ON, then add the correct tablename */ else if (strcasecmp(prev4_wd, "ALTER") == 0 && strcasecmp(prev3_wd, "TRIGGER") == 0 && strcasecmp(prev_wd, "ON") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER, * RENAME, or OWNER */ else if (strcasecmp(prev3_wd, "ALTER") == 0 && strcasecmp(prev2_wd, "TABLE") == 0) { static const char *const list_ALTER2[] = {"ADD", "ALTER", "DROP", "RENAME", "OWNER TO", NULL}; COMPLETE_WITH_LIST(list_ALTER2); } /* If we have TABLE <sth> ALTER|RENAME, provide list of columns */ else if (strcasecmp(prev3_wd, "TABLE") == 0 && (strcasecmp(prev_wd, "ALTER") == 0 || strcasecmp(prev_wd, "RENAME") == 0)) COMPLETE_WITH_ATTR(prev2_wd); /* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */ else if (strcasecmp(prev3_wd, "TABLE") == 0 && strcasecmp(prev_wd, "DROP") == 0) { static const char *const list_TABLEDROP[] = {"COLUMN", "CONSTRAINT", NULL}; COMPLETE_WITH_LIST(list_TABLEDROP); } /* If we have TABLE <sth> DROP COLUMN, provide list of columns */ else if (strcasecmp(prev4_wd, "TABLE") == 0 && strcasecmp(prev2_wd, "DROP") == 0 && strcasecmp(prev_wd, "COLUMN") == 0) COMPLETE_WITH_ATTR(prev3_wd); /* complete ALTER GROUP <foo> with ADD or DROP */ else if (strcasecmp(prev3_wd, "ALTER") == 0 && strcasecmp(prev2_wd, "GROUP") == 0) { static const char *const list_ALTERGROUP[] = {"ADD", "DROP", NULL}; COMPLETE_WITH_LIST(list_ALTERGROUP); } /* complete ALTER GROUP <foo> ADD|DROP with USER */ else if (strcasecmp(prev4_wd, "ALTER") == 0 && strcasecmp(prev3_wd, "GROUP") == 0 && (strcasecmp(prev_wd, "ADD") == 0 || strcasecmp(prev_wd, "DROP") == 0)) COMPLETE_WITH_CONST("USER"); /* complete {ALTER} GROUP <foo> ADD|DROP USER with a user name */ else if (strcasecmp(prev4_wd, "GROUP") == 0 && (strcasecmp(prev2_wd, "ADD") == 0 || strcasecmp(prev2_wd, "DROP") == 0) && 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 (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 (strcasecmp(prev2_wd, "ANALYZE") == 0) COMPLETE_WITH_CONST(";");/* CLUSTER */ /* If the previous word is CLUSTER, produce list of indexes. */ else if (strcasecmp(prev_wd, "CLUSTER") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL); /* If we have CLUSTER <sth>, then add "ON" */ else if (strcasecmp(prev2_wd, "CLUSTER") == 0) COMPLETE_WITH_CONST("ON"); /* * If we have CLUSTER <sth> ON, then add the correct tablename as * well. */ else if (strcasecmp(prev3_wd, "CLUSTER") == 0 && strcasecmp(prev_wd, "ON") == 0) { completion_info_charp = prev2_wd; COMPLETE_WITH_QUERY(Query_for_table_owning_index); }/* COMMENT */ else if (strcasecmp(prev_wd, "COMMENT") == 0) COMPLETE_WITH_CONST("ON"); else if (strcasecmp(prev2_wd, "COMMENT") == 0 && strcasecmp(prev_wd, "ON") == 0) { static const char *const list_COMMENT[] = {"DATABASE", "INDEX", "RULE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", NULL}; COMPLETE_WITH_LIST(list_COMMENT); } else if (strcasecmp(prev4_wd, "COMMENT") == 0 && strcasecmp(prev3_wd, "ON") == 0) COMPLETE_WITH_CONST("IS");/* COPY */ /* * If we have COPY [BINARY] (which you'd have to type yourself), offer * list of tables (Also cover the analogous backslash command) */ else if (strcasecmp(prev_wd, "COPY") == 0 || strcasecmp(prev_wd, "\\copy") == 0 || (strcasecmp(prev2_wd, "COPY") == 0 && strcasecmp(prev_wd, "BINARY") == 0)) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* If we have COPY|BINARY <sth>, complete it with "TO" or "FROM" */ else if (strcasecmp(prev2_wd, "COPY") == 0 || strcasecmp(prev2_wd, "\\copy") == 0 || strcasecmp(prev2_wd, "BINARY") == 0) { static const char *const list_FROMTO[] = {"FROM", "TO", NULL}; COMPLETE_WITH_LIST(list_FROMTO); }/* CREATE INDEX */ /* First off we complete CREATE UNIQUE with "INDEX" */ else if (strcasecmp(prev2_wd, "CREATE") == 0 && strcasecmp(prev_wd, "UNIQUE") == 0) COMPLETE_WITH_CONST("INDEX"); /* If we have CREATE|UNIQUE INDEX <sth>, then add "ON" */ else if (strcasecmp(prev2_wd, "INDEX") == 0 && (strcasecmp(prev3_wd, "CREATE") == 0 || strcasecmp(prev3_wd, "UNIQUE") == 0)) COMPLETE_WITH_CONST("ON"); /* Complete ... INDEX <name> ON with a list of tables */ else if (strcasecmp(prev3_wd, "INDEX") == 0 && strcasecmp(prev_wd, "ON") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* * Complete INDEX <name> ON <table> with a list of table columns * (which should really be in parens) */ else if (strcasecmp(prev4_wd, "INDEX") == 0 && strcasecmp(prev2_wd, "ON") == 0) COMPLETE_WITH_ATTR(prev_wd); /* same if you put in USING */ else if (strcasecmp(prev4_wd, "ON") == 0 && strcasecmp(prev2_wd, "USING") == 0) COMPLETE_WITH_ATTR(prev3_wd); /* Complete USING with an index method */ else if (strcasecmp(prev_wd, "USING") == 0) { static const char *const index_mth[] = {"BTREE", "RTREE", "HASH", "GIST", NULL}; COMPLETE_WITH_LIST(index_mth); }/* CREATE RULE */ /* Complete "CREATE RULE <sth>" with "AS" */ else if (strcasecmp(prev3_wd, "CREATE") == 0 && strcasecmp(prev2_wd, "RULE") == 0) COMPLETE_WITH_CONST("AS"); /* Complete "CREATE RULE <sth> AS with "ON" */ else if (strcasecmp(prev4_wd, "CREATE") == 0 && strcasecmp(prev3_wd, "RULE") == 0 && strcasecmp(prev_wd, "AS") == 0) COMPLETE_WITH_CONST("ON"); /* Complete "RULE * AS ON" with SELECT|UPDATE|DELETE|INSERT */ else if (strcasecmp(prev4_wd, "RULE") == 0 && strcasecmp(prev2_wd, "AS") == 0 && strcasecmp(prev_wd, "ON") == 0) { static const char *const rule_events[] = {"SELECT", "UPDATE", "INSERT", "DELETE", NULL}; COMPLETE_WITH_LIST(rule_events); } /* Complete "AS ON <sth with a 'T' :)>" with a "TO" */ else if (strcasecmp(prev3_wd, "AS") == 0 && strcasecmp(prev2_wd, "ON") == 0 && (toupper((unsigned char) prev_wd[4]) == 'T' || toupper((unsigned char) prev_wd[5]) == 'T')) COMPLETE_WITH_CONST("TO"); /* Complete "AS ON <sth> TO" with a table name */ else if (strcasecmp(prev4_wd, "AS") == 0 && strcasecmp(prev3_wd, "ON") == 0 && strcasecmp(prev_wd, "TO") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);/* CREATE TABLE */ /* Complete CREATE TEMP with "TABLE" */ else if (strcasecmp(prev2_wd, "CREATE") == 0 && strcasecmp(prev_wd, "TEMP") == 0) COMPLETE_WITH_CONST("TABLE");/* CREATE TRIGGER */ /* is on the agenda . . . *//* CREATE VIEW */ /* Complete "CREATE VIEW <name>" with "AS" */ else if (strcasecmp(prev3_wd, "CREATE") == 0 && strcasecmp(prev2_wd, "VIEW") == 0) COMPLETE_WITH_CONST("AS"); /* Complete "CREATE VIEW <sth> AS with "SELECT" */ else if (strcasecmp(prev4_wd, "CREATE") == 0 && strcasecmp(prev3_wd, "VIEW") == 0 && strcasecmp(prev_wd, "AS") == 0) COMPLETE_WITH_CONST("SELECT");/* DELETE */ /* * Complete DELETE with FROM (only if the word before that is not "ON" * (cf. rules) or "BEFORE" or "AFTER" (cf. triggers) or GRANT) */ else if (strcasecmp(prev_wd, "DELETE") == 0 && !(strcasecmp(prev2_wd, "ON") == 0 || strcasecmp(prev2_wd, "GRANT") == 0 || strcasecmp(prev2_wd, "BEFORE") == 0 || strcasecmp(prev2_wd, "AFTER") == 0)) COMPLETE_WITH_CONST("FROM"); /* Complete DELETE FROM with a list of tables */ else if (strcasecmp(prev2_wd, "DELETE") == 0 && strcasecmp(prev_wd, "FROM") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* Complete DELETE FROM <table> with "WHERE" (perhaps a safe idea?) */ else if (strcasecmp(prev3_wd, "DELETE") == 0 && strcasecmp(prev2_wd, "FROM") == 0) COMPLETE_WITH_CONST("WHERE");/* EXPLAIN */ /* * Complete EXPLAIN [VERBOSE] (which you'd have to type yourself) with * the list of SQL commands */ else if (strcasecmp(prev_wd, "EXPLAIN") == 0 || (strcasecmp(prev2_wd, "EXPLAIN") == 0 && strcasecmp(prev_wd, "VERBOSE") == 0)) COMPLETE_WITH_LIST(sql_commands);/* FETCH && MOVE */ /* Complete FETCH with one of FORWARD, BACKWARD, RELATIVE */ else if (strcasecmp(prev_wd, "FETCH") == 0 || strcasecmp(prev_wd, "MOVE") == 0) { static const char * const list_FETCH1[] = {"FORWARD", "BACKWARD", "RELATIVE", NULL}; COMPLETE_WITH_LIST(list_FETCH1); } /* Complete FETCH <sth> with one of ALL, NEXT, PRIOR */ else if (strcasecmp(prev2_wd, "FETCH") == 0 || strcasecmp(prev2_wd, "MOVE") == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -