*
* Copyright (c) 2000-2007, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.166 2007/07/03 01:30:37 neilc Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.167 2007/09/14 04:25:24 momjian Exp $
*/
/*----------------------------------------------------------------------
" AND pg_catalog.quote_ident(relname)='%s' "\
" AND pg_catalog.pg_table_is_visible(c.oid)"
+#define Query_for_list_of_template_databases \
+"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
+" WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' and datistemplate IS TRUE"
+
#define Query_for_list_of_databases \
"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
" WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
" (SELECT tgrelid FROM pg_catalog.pg_trigger "\
" WHERE pg_catalog.quote_ident(tgname)='%s')"
+#define Query_for_list_of_ts_configurations \
+"SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
+" WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
+
+#define Query_for_list_of_ts_dictionaries \
+"SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
+" WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
+
+#define Query_for_list_of_ts_parsers \
+"SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
+" WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
+
+#define Query_for_list_of_ts_templates \
+"SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
+" WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
+
/*
* This is a list of all "things" in Pgsql, which can show up after CREATE or
* DROP; and there is also a query to get a list of them.
const char *name;
const char *query; /* simple query, or NULL */
const SchemaQuery *squery; /* schema query, or NULL */
+ const bool noshow; /* NULL or true if this word should not show up after CREATE or DROP */
} pgsql_thing_t;
static const pgsql_thing_t words_after_create[] = {
* CREATE CONSTRAINT TRIGGER is not supported here because it is designed
* to be used only by pg_dump.
*/
+ {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, true},
{"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
{"DATABASE", Query_for_list_of_databases},
+ {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, true},
{"DOMAIN", NULL, &Query_for_list_of_domains},
{"FUNCTION", NULL, &Query_for_list_of_functions},
{"GROUP", Query_for_list_of_roles},
{"INDEX", NULL, &Query_for_list_of_indexes},
{"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
* good idea. */
+ {"PARSER", Query_for_list_of_ts_parsers, NULL, true},
{"ROLE", Query_for_list_of_roles},
{"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
{"SCHEMA", Query_for_list_of_schemas},
{"TABLE", NULL, &Query_for_list_of_tables},
{"TABLESPACE", Query_for_list_of_tablespaces},
{"TEMP", NULL, NULL}, /* for CREATE TEMP TABLE ... */
+ {"TEMPLATE", Query_for_list_of_ts_templates, NULL, true},
+ {"TEXT SEARCH", NULL, NULL},
{"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s'"},
{"TYPE", NULL, &Query_for_list_of_datatypes},
{"UNIQUE", NULL, NULL}, /* for CREATE UNIQUE INDEX ... */
{"USER", Query_for_list_of_roles},
{"VIEW", NULL, &Query_for_list_of_views},
- {NULL, NULL, NULL} /* end of list */
+ {NULL, NULL, NULL, false} /* end of list */
};
"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
"REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
"SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TRUNCATE", "UNLISTEN",
- "UPDATE", "VACUUM", NULL
+ "UPDATE", "VACUUM", "VALUES", NULL
};
static const char *const backslash_commands[] = {
"\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
"\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\df",
- "\\dg", "\\di", "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS",
- "\\dt", "\\dT", "\\dv", "\\du",
+ "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\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",
static const char *const list_ALTER[] =
{"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION",
"GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SEQUENCE", "TABLE",
- "TABLESPACE", "TRIGGER", "TYPE", "USER", "VIEW", NULL};
+ "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "VIEW", NULL};
COMPLETE_WITH_LIST(list_ALTER);
}
pg_strcasecmp(prev2_wd, "INDEX") == 0)
{
static const char *const list_ALTERINDEX[] =
- {"SET TABLESPACE", "OWNER TO", "RENAME TO", NULL};
+ {"SET TABLESPACE", "OWNER TO", "RENAME TO", "SET", "RESET", NULL};
COMPLETE_WITH_LIST(list_ALTERINDEX);
}
{
static const char *const list_ALTERSEQUENCE[] =
{"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
- "SET SCHEMA", "RENAME TO", NULL};
+ "SET SCHEMA", "OWNED BY", "RENAME TO", NULL};
COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
}
pg_strcasecmp(prev2_wd, "TABLE") == 0)
{
static const char *const list_ALTER2[] =
- {"ADD", "ALTER", "CLUSTER ON", "DROP", "RENAME", "OWNER TO",
- "SET", NULL};
+ {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
+ "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET", NULL};
COMPLETE_WITH_LIST(list_ALTER2);
}
+ /* ALTER TABLE xxx ENABLE */
+ else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
+ pg_strcasecmp(prev_wd, "ENABLE") == 0)
+ {
+ static const char *const list_ALTERENABLE[] =
+ {"ALWAYS","REPLICA","RULE", "TRIGGER", NULL};
+ COMPLETE_WITH_LIST(list_ALTERENABLE);
+ }
+ else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
+ pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
+ (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
+ pg_strcasecmp(prev_wd, "ALWAYS") == 0))
+ {
+ static const char *const list_ALTERENABLE2[] =
+ {"RULE", "TRIGGER", NULL};
+ COMPLETE_WITH_LIST(list_ALTERENABLE2);
+ }
+ else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
+ pg_strcasecmp(prev_wd, "DISABLE") == 0)
+ {
+ static const char *const list_ALTERDISABLE[] =
+ {"RULE", "TRIGGER", NULL};
+ COMPLETE_WITH_LIST(list_ALTERDISABLE);
+ }
+
/* If we have TABLE <sth> ALTER|RENAME, provide list of columns */
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
(pg_strcasecmp(prev_wd, "ALTER") == 0 ||
COMPLETE_WITH_LIST(list_ALTERTSPC);
}
+ /* ALTER TEXT SEARCH */
+ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev_wd, "SEARCH") == 0)
+ {
+ static const char *const list_ALTERTEXTSEARCH[] =
+ {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
+ }
+ else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
+ (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
+ pg_strcasecmp(prev2_wd, "PARSER") == 0))
+ COMPLETE_WITH_CONST("RENAME TO");
+
+ else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
+ pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
+ {
+ static const char *const list_ALTERTEXTSEARCH2[] =
+ {"OWNER TO", "RENAME TO", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
+ }
+
+ else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
+ pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
+ {
+ static const char *const list_ALTERTEXTSEARCH3[] =
+ {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
+ }
+
/* complete ALTER TYPE <foo> with OWNER TO, SET SCHEMA */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
pg_strcasecmp(prev2_wd, "TYPE") == 0)
}
/*
- * If we have CLUSTER <sth> ORDER BY, then add the index as well.
+ * If we have CLUSTER <sth> USING, then add the index as well.
*/
else if (pg_strcasecmp(prev3_wd, "CLUSTER") == 0 &&
pg_strcasecmp(prev_wd, "USING") == 0)
{"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
"SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
"OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT",
- "TABLESPACE", "ROLE", NULL};
+ "TABLESPACE", "TEXT SEARCH", "ROLE", NULL};
COMPLETE_WITH_LIST(list_COMMENT);
}
else if (pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
- pg_strcasecmp(prev3_wd, "ON") == 0)
+ pg_strcasecmp(prev3_wd, "ON") == 0 &&
+ pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev_wd, "SEARCH") == 0)
+ {
+ static const char *const list_TRANS2[] =
+ {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
+
+ COMPLETE_WITH_LIST(list_TRANS2);
+ }
+ else if ((pg_strcasecmp(prev4_wd, "COMMENT") == 0 &&
+ pg_strcasecmp(prev3_wd, "ON") == 0) ||
+ (pg_strcasecmp(prev5_wd, "ON") == 0 &&
+ pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev3_wd, "SEARCH") == 0))
COMPLETE_WITH_CONST("IS");
/* COPY */
COMPLETE_WITH_LIST(list_DATABASE);
}
+ else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
+ pg_strcasecmp(prev3_wd, "DATABASE") == 0 &&
+ pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
+
/* CREATE INDEX */
/* First off we complete CREATE UNIQUE with "INDEX" */
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
else if (pg_strcasecmp(prev_wd, "USING") == 0)
{
static const char *const index_mth[] =
- {"BTREE", "HASH", "GIST", NULL};
+ {"BTREE", "HASH", "GIN", "GIST", NULL};
COMPLETE_WITH_LIST(index_mth);
}
COMPLETE_WITH_CONST("LOCATION");
}
+/* CREATE TEXT SEARCH */
+ else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
+ pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev_wd, "SEARCH") == 0)
+ {
+ static const char *const list_CREATETEXTSEARCH[] =
+ {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
+
+ COMPLETE_WITH_LIST(list_CREATETEXTSEARCH);
+ }
+ else if (pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
+ pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
+ COMPLETE_WITH_CONST("(");
+
/* CREATE TRIGGER */
/* complete CREATE TRIGGER <name> with BEFORE,AFTER */
else if (pg_strcasecmp(prev3_wd, "CREATE") == 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] == ')'))
+ prev_wd[strlen(prev_wd) - 1] == ')') ||
+ (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
+ pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
+ (pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0 ||
+ pg_strcasecmp(prev2_wd, "DICTIONARY") == 0 ||
+ pg_strcasecmp(prev2_wd, "PARSER") == 0 ||
+ pg_strcasecmp(prev2_wd, "TEMPLATE") == 0))
+ )
{
if ((pg_strcasecmp(prev3_wd, "DROP") == 0) && (pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
{
pg_strcasecmp(prev2_wd, "OWNED") == 0 &&
pg_strcasecmp(prev_wd, "BY") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+ else if (pg_strcasecmp(prev3_wd, "DROP") == 0 &&
+ pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
+ pg_strcasecmp(prev_wd, "SEARCH") == 0)
+ {
+ static const char *const list_ALTERTEXTSEARCH[] =
+ {"CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE", NULL};
-
+ COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH);
+ }
+
/* EXPLAIN */
/*
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, "\\dF") == 0 || strcmp(prev_wd, "\\dF+") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_ts_configurations);
+ else if (strcmp(prev_wd, "\\dFd") == 0 || strcmp(prev_wd, "\\dFd+") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_ts_dictionaries);
+ else if (strcmp(prev_wd, "\\dFp") == 0 || strcmp(prev_wd, "\\dFp+") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_ts_parsers);
+ else if (strcmp(prev_wd, "\\dFt") == 0 || strcmp(prev_wd, "\\dFt+") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_ts_templates);
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)
static char *
create_command_generator(const char *text, int state)
{
- static int list_index,
- string_length;
+ static int list_index, string_length;
const char *name;
/* If this is the first time for this completion, init some values */
/* 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 ((pg_strncasecmp(name, text, string_length) == 0) && !words_after_create[list_index - 1].noshow)
+ return pg_strdup(name);
+ }
/* if nothing matches, return NULL */
return NULL;
}
static char *
drop_command_generator(const char *text, int state)
{
- static int list_index,
- string_length;
+ static int list_index, string_length;
const char *name;
if (state == 0)
*/
while ((name = words_after_create[list_index++ - 1].name))
{
- if (pg_strncasecmp(name, text, string_length) == 0)
+ if ((pg_strncasecmp(name, text, string_length) == 0) && (!words_after_create[list_index - 2].noshow))
return pg_strdup(name);
}