📄 tab-complete.c
字号:
pg_strcasecmp(prev2_wd, "LEVEL") == 0 && pg_strcasecmp(prev_wd, "REPEATABLE") == 0) COMPLETE_WITH_CONST("READ"); else if ((pg_strcasecmp(prev3_wd, "SET") == 0 || pg_strcasecmp(prev3_wd, "BEGIN") == 0 || pg_strcasecmp(prev3_wd, "START") == 0 || pg_strcasecmp(prev3_wd, "AS") == 0) && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0 || pg_strcasecmp(prev2_wd, "WORK") == 0) && pg_strcasecmp(prev_wd, "READ") == 0) { static const char *const my_list[] = {"ONLY", "WRITE", NULL}; COMPLETE_WITH_LIST(my_list); } /* Complete SET CONSTRAINTS <foo> with DEFERRED|IMMEDIATE */ else if (pg_strcasecmp(prev3_wd, "SET") == 0 && pg_strcasecmp(prev2_wd, "CONSTRAINTS") == 0) { static const char *const constraint_list[] = {"DEFERRED", "IMMEDIATE", NULL}; COMPLETE_WITH_LIST(constraint_list); } /* Complete SET ROLE */ else if (pg_strcasecmp(prev2_wd, "SET") == 0 && pg_strcasecmp(prev_wd, "ROLE") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_roles); /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */ else if (pg_strcasecmp(prev2_wd, "SET") == 0 && pg_strcasecmp(prev_wd, "SESSION") == 0) { static const char *const my_list[] = {"AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION", NULL}; COMPLETE_WITH_LIST(my_list); } /* Complete SET SESSION AUTHORIZATION with username */ else if (pg_strcasecmp(prev3_wd, "SET") == 0 && pg_strcasecmp(prev2_wd, "SESSION") == 0 && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_roles); /* Complete SET <var> with "TO" */ else if (pg_strcasecmp(prev2_wd, "SET") == 0 && pg_strcasecmp(prev4_wd, "UPDATE") != 0 && pg_strcasecmp(prev_wd, "TABLESPACE") != 0 && pg_strcasecmp(prev4_wd, "DOMAIN") != 0) COMPLETE_WITH_CONST("TO"); /* Suggest possible variable values */ else if (pg_strcasecmp(prev3_wd, "SET") == 0 && (pg_strcasecmp(prev_wd, "TO") == 0 || strcmp(prev_wd, "=") == 0)) { if (pg_strcasecmp(prev2_wd, "DateStyle") == 0) { static const char *const my_list[] = {"ISO", "SQL", "Postgres", "German", "YMD", "DMY", "MDY", "US", "European", "NonEuropean", "DEFAULT", NULL}; COMPLETE_WITH_LIST(my_list); } else if (pg_strcasecmp(prev2_wd, "GEQO") == 0) { static const char *const my_list[] = {"ON", "OFF", "DEFAULT", NULL}; COMPLETE_WITH_LIST(my_list); } else { static const char *const my_list[] = {"DEFAULT", NULL}; COMPLETE_WITH_LIST(my_list); } }/* START TRANSACTION */ else if (pg_strcasecmp(prev_wd, "START") == 0) COMPLETE_WITH_CONST("TRANSACTION");/* TRUNCATE */ else if (pg_strcasecmp(prev_wd, "TRUNCATE") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);/* UNLISTEN */ else if (pg_strcasecmp(prev_wd, "UNLISTEN") == 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' UNION SELECT '*'");/* UPDATE */ /* If prev. word is UPDATE suggest a list of tables */ else if (pg_strcasecmp(prev_wd, "UPDATE") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); /* Complete UPDATE <table> with "SET" */ else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0) COMPLETE_WITH_CONST("SET"); /* * If the previous word is SET (and it wasn't caught above as the _first_ * word) the word before it was (hopefully) a table name and we'll now * make a list of attributes. */ 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 [, ...] ) ] ] */ 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);/* 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);/* WHERE */ /* Simple case of the word before the where being the table name */ else if (pg_strcasecmp(prev_wd, "WHERE") == 0) COMPLETE_WITH_ATTR(prev2_wd);/* ... FROM ... *//* TODO: also include SRF ? */ else if (pg_strcasecmp(prev_wd, "FROM") == 0 && pg_strcasecmp(prev3_wd, "COPY") != 0 && pg_strcasecmp(prev3_wd, "\\copy") != 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);/* Backslash commands *//* TODO: \dc \dd \dl */ else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_databases); else if (strcmp(prev_wd, "\\d") == 0 || strcmp(prev_wd, "\\d+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisv, NULL); else if (strcmp(prev_wd, "\\da") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL); else if (strcmp(prev_wd, "\\db") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); else if (strcmp(prev_wd, "\\dD") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL); else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL); else if (strcmp(prev_wd, "\\di") == 0 || strcmp(prev_wd, "\\di+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL); else if (strcmp(prev_wd, "\\dn") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_schemas); else if (strcmp(prev_wd, "\\dp") == 0 || strcmp(prev_wd, "\\z") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL); else if (strcmp(prev_wd, "\\ds") == 0 || strcmp(prev_wd, "\\ds+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_sequences, NULL); else if (strcmp(prev_wd, "\\dS") == 0 || strcmp(prev_wd, "\\dS+") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_system_relations); else if (strcmp(prev_wd, "\\dt") == 0 || strcmp(prev_wd, "\\dt+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL); else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL); else if (strcmp(prev_wd, "\\du") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_roles); else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL); else if (strcmp(prev_wd, "\\encoding") == 0) COMPLETE_WITH_QUERY(Query_for_list_of_encodings); else if (strcmp(prev_wd, "\\h") == 0 || strcmp(prev_wd, "\\help") == 0) COMPLETE_WITH_LIST(sql_commands); else if (strcmp(prev_wd, "\\pset") == 0) { static const char *const my_list[] = {"format", "border", "expanded", "null", "fieldsep", "tuples_only", "title", "tableattr", "pager", "recordsep", NULL}; COMPLETE_WITH_LIST(my_list); } else if (strcmp(prev_wd, "\\cd") == 0 || strcmp(prev_wd, "\\e") == 0 || strcmp(prev_wd, "\\edit") == 0 || strcmp(prev_wd, "\\g") == 0 || strcmp(prev_wd, "\\i") == 0 || strcmp(prev_wd, "\\include") == 0 || strcmp(prev_wd, "\\o") == 0 || strcmp(prev_wd, "\\out") == 0 || strcmp(prev_wd, "\\s") == 0 || strcmp(prev_wd, "\\w") == 0 || strcmp(prev_wd, "\\write") == 0 ) matches = completion_matches(text, filename_completion_function); /* * Finally, we look through the list of "things", such as TABLE, INDEX and * check if that was the previous word. If so, execute the query to get a * list of them. */ else { int i; for (i = 0; words_after_create[i].name; i++) { if (pg_strcasecmp(prev_wd, words_after_create[i].name) == 0) { if (words_after_create[i].query) COMPLETE_WITH_QUERY(words_after_create[i].query); else if (words_after_create[i].squery) COMPLETE_WITH_SCHEMA_QUERY(*words_after_create[i].squery, NULL); break; } } } /* * If we still don't have anything to match we have to fabricate some sort * of default list. If we were to just return NULL, readline automatically * attempts filename completion, and that's usually no good. */ if (matches == NULL) { COMPLETE_WITH_CONST("");#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER rl_completion_append_character = '\0';#endif } /* free storage */ free(prev_wd); free(prev2_wd); free(prev3_wd); free(prev4_wd); free(prev5_wd); /* Return our Grand List O' Matches */ return matches;}/* GENERATOR FUNCTIONS These functions do all the actual work of completing the input. They get passed the text so far and the count how many times they have been called so far with the same text. If you read the above carefully, you'll see that these don't get called directly but through the readline interface. The return value is expected to be the full completion of the text, going through a list each time, or NULL if there are no more matches. The string will be free()'d by readline, so you must run it through strdup() or something of that sort.*//* This one gives you one from a list of things you can put after CREATE or DROP as defined above.*/static char *create_command_generator(const char *text, int state){ static int list_index, string_length; const char *name; /* If this is the first time for this completion, init some values */ if (state == 0) { list_index = 0; string_length = strlen(text); } /* find something that matches */ while ((name = words_after_create[list_index++].name)) if (pg_strncasecmp(name, text, string_length) == 0) return pg_strdup(name); /* if nothing matches, return NULL */ return NULL;}/* The following two functions are wrappers for _complete_from_query */static char *complete_from_query(const char *text, int state){ return _complete_from_query(0, text, state);}static char *complete_from_schema_query(const char *text, int state){ return _complete_from_query(1, text, state);}/* This creates a list of matching things, according to a query pointed to by completion_charp. The query can be one of two kinds: - A simple query which must contain a %d and a %s, which will be replaced by the string length of the text and the text itself. The query may also have another %s in it, which will be replaced by the value of completion_info_charp. or: - A schema query used for completion of both schema and relation names; these are more complex and must contain in the following order: %d %s %d %s %d %s %s %d %s where %d is the string length of the text and %s the text itself. It is assumed that strings should be escaped to become SQL literals (that is, what is in the query is actually ... '%s' ...) See top of file for examples of both kinds of query.*/static char *_complete_from_query(int is_schema_query, const char *text, int state){ static int list_index, string_length; static PGresult *result = NULL; /* * If this is the first time for this completion, we fetch a list of our * "things" from the backend. */ if (state == 0) { PQExpBufferData query_buffer; char *e_text; char *e_info_charp; list_index = 0; string_length = strlen(text); /* Free any prior result */ PQclear(result); result = NULL; /* Set up suitably-escaped copies of textual inputs */ e_text = pg_malloc(string_length * 2 + 1); PQescapeString(e_text, text, string_length); if (completion_info_charp) { size_t charp_len; charp_len = strlen(completion_info_charp); e_info_charp = pg_malloc(charp_len * 2 + 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -