*
* Copyright (c) 2000-2003, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.110 2004/08/20 04:29:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.111 2004/08/20 19:24:59 momjian Exp $
*/
/*----------------------------------------------------------------------
"SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
" WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
+#define Query_for_list_of_tablespaces \
+"SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
+" WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
+
#define Query_for_list_of_encodings \
" SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
" FROM pg_catalog.pg_conversion "\
" and pg_catalog.quote_ident(c2.relname)='%s'"\
" and pg_catalog.pg_table_is_visible(c2.oid)"
+/* the silly-looking length condition is just to eat up the current word */
+#define Query_for_index_of_table \
+"SELECT pg_catalog.quote_ident(c2.relname) "\
+" FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
+" WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
+" and (%d = length('%s'))"\
+" and pg_catalog.quote_ident(c1.relname)='%s'"\
+" and pg_catalog.pg_table_is_visible(c2.oid)"
+
/*
* 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.
{"SCHEMA", Query_for_list_of_schemas},
{"SEQUENCE", NULL, &Query_for_list_of_sequences},
{"TABLE", NULL, &Query_for_list_of_tables},
+ {"TABLESPACE", Query_for_list_of_tablespaces},
{"TEMP", NULL, NULL}, /* for CREATE TEMP TABLE ... */
{"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},
static const char * const sql_commands[] = {
"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER", "COMMENT",
- "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE", "DELETE", "DROP", "EXECUTE",
+ "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
static const char * const backslash_commands[] = {
"\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
- "\\d", "\\da", "\\dc", "\\dC", "\\dd", "\\dD", "\\df", "\\dg", "\\di",
- "\\dl", "\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT",
- "\\dv", "\\du",
+ "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\df",
+ "\\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",
pg_strcasecmp(prev3_wd, "TABLE") != 0)
{
static const char *const list_ALTER[] =
- {"DATABASE", "GROUP", "SCHEMA", "TABLE", "TRIGGER", "USER", "INDEX",
- NULL};
+ {"AGGREGATE", "CONVERSATION", "DATABASE","DOMAIN", "FUNCTION",
+ "GROUP", "LANGUAGE", "OPERATOR", "SCHEMA", "SEQUENCE", "TABLE",
+ "TABLESPACE", "TRIGGER", "TYPE", "USER", NULL};
COMPLETE_WITH_LIST(list_ALTER);
}
+
+ /* ALTER AGGREGATE,CONVERSION,FUNCTION,SCHEMA <name> */
+ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
+ pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
+ pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
+ pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ))
+ {
+ static const char *const list_ALTERGEN[] =
+ {"OWNER TO", "RENAME TO", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTERGEN);
+ }
/* ALTER DATABASE <name> */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
}
/* ALTER INDEX <name> */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev2_wd, "INDEX") == 0)
- {
- static const char *const list_ALTERINDEX[] =
- {"SET TABLESPACE", "OWNER TO", "RENAME TO", NULL};
-
- COMPLETE_WITH_LIST(list_ALTERINDEX);
- }
+ pg_strcasecmp(prev2_wd, "INDEX") == 0)
+ {
+ static const char *const list_ALTERINDEX[] =
+ {"SET TABLESPACE", "OWNER TO", "RENAME TO", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTERINDEX);
+ }
+
+ /* ALTER DOMAIN <name> */
+ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
+ {
+ static const char *const list_ALTERDOMAIN[] =
+ {"ADD", "DROP", "OWNER TO", "SET", NULL};
+ COMPLETE_WITH_LIST(list_ALTERDOMAIN);
+ }
+ /* ALTER DOMAIN <sth> DROP */
+ else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
+ pg_strcasecmp(prev_wd, "DROP") == 0)
+ {
+ static const char *const list_ALTERDOMAIN2[] =
+ {"CONSTRAINT", "DEFAULT", "NOT NULL", "OWNER TO", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
+ }
+ /* ALTER DOMAIN <sth> SET */
+ else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
+ pg_strcasecmp(prev_wd, "SET") == 0)
+ {
+ static const char *const list_ALTERDOMAIN3[] =
+ {"DEFAULT", "NOT NULL", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
+ }
/* ALTER TRIGGER <name>, add ON */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
- pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
+ pg_strcasecmp(prev2_wd, "TRIGGER") == 0 &&
+ pg_strcasecmp(prev_wd, "ON") != 0)
COMPLETE_WITH_CONST("ON");
/*
/*
* If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
- * RENAME, or OWNER
+ * RENAME, CLUSTER ON or OWNER
*/
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
pg_strcasecmp(prev2_wd, "TABLE") == 0)
{
static const char *const list_ALTER2[] =
- {"ADD", "ALTER", "DROP", "RENAME", "OWNER TO", NULL};
+ {"ADD", "ALTER", "CLUSTER ON", "DROP", "RENAME", "OWNER TO",
+ "SET", NULL};
COMPLETE_WITH_LIST(list_ALTER2);
}
pg_strcasecmp(prev2_wd, "DROP") == 0 &&
pg_strcasecmp(prev_wd, "COLUMN") == 0)
COMPLETE_WITH_ATTR(prev3_wd);
+ else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
+ pg_strcasecmp(prev_wd, "CLUSTER") == 0)
+ COMPLETE_WITH_CONST("ON");
+ else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
+ pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
+ pg_strcasecmp(prev_wd, "ON") == 0)
+ {
+ completion_info_charp = prev3_wd;
+ COMPLETE_WITH_QUERY(Query_for_index_of_table);
+ }
+ /* If we have TABLE <sth> SET, provide WITHOUT or TABLESPACE */
+ else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
+ pg_strcasecmp(prev_wd, "SET") == 0)
+ {
+ static const char *const list_TABLESET[] =
+ {"WITHOUT", "TABLESPACE", NULL};
+
+ COMPLETE_WITH_LIST(list_TABLESET);
+ }
+ /* If we have TABLE <sth> SET TABLESPACE provide a list of tablespaces*/
+ else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
+ pg_strcasecmp(prev2_wd, "SET") == 0 &&
+ pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
+ /* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS*/
+ else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
+ pg_strcasecmp(prev2_wd, "SET") == 0 &&
+ pg_strcasecmp(prev_wd, "WITHOUT") == 0)
+ {
+ static const char *const list_TABLESET2[] =
+ {"CLUSTER", "OIDS", NULL};
+ COMPLETE_WITH_LIST(list_TABLESET2);
+ }
+ /* we have ALTER TABLESPACE, so suggest RENAME TO, OWNER TO */
+ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
+ {
+ static const char *const list_ALTERTSPC[] =
+ {"RENAME TO", "OWNER TO", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTERTSPC);
+ }
+ /* complete ALTER TYPE <foo> with OWNER TO */
+ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev2_wd, "TYPE") == 0)
+ COMPLETE_WITH_CONST("OWNER TO");
/* complete ALTER GROUP <foo> with ADD or DROP */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
pg_strcasecmp(prev2_wd, "GROUP") == 0)
COMPLETE_WITH_LIST(list_TRANS);
}
+/* RELEASE SAVEPOINT */
+ else if ( pg_strcasecmp(prev_wd, "RELEASE") == 0 )
+ COMPLETE_WITH_CONST("SAVEPOINT");
/* ROLLBACK*/
else if ( pg_strcasecmp(prev_wd, "ROLLBACK") == 0 )
{
static const char * const list_TRANS[] =
- {"WORK", "TRANSACTION", "TO", NULL};
+ {"WORK", "TRANSACTION", "TO SAVEPOINT", NULL};
COMPLETE_WITH_LIST(list_TRANS);
}
/* CLUSTER */
- /* If the previous word is CLUSTER, produce list of indexes. */
- else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0)
+ /* If the previous word is CLUSTER and not without produce list
+ * of indexes. */
+ else if (pg_strcasecmp(prev_wd, "CLUSTER") == 0 &&
+ pg_strcasecmp(prev2_wd, "WITHOUT") != 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes, NULL);
/* If we have CLUSTER <sth>, then add "ON" */
- else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0)
+ else if (pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
+ pg_strcasecmp(prev_wd,"ON") != 0)
COMPLETE_WITH_CONST("ON");
/*
pg_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};
+ {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
+ "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
+ "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", NULL};
COMPLETE_WITH_LIST(list_COMMENT);
}
pg_strcasecmp(prev_wd, "MOVE") == 0)
{
static const char * const list_FETCH1[] =
- {"FORWARD", "BACKWARD", "RELATIVE", NULL};
+ {"ABSOLUT", "BACKWARD", "FORWARD", "RELATIVE", NULL};
COMPLETE_WITH_LIST(list_FETCH1);
}
" UNION SELECT 'DATABASE'"
" UNION SELECT 'FUNCTION'"
" UNION SELECT 'LANGUAGE'"
- " UNION SELECT 'SCHEMA'");
+ " UNION SELECT 'SCHEMA'"
+ " UNION SELECT 'TABLESPACE'");
/* Complete "GRANT/REVOKE * ON * " with "TO" */
else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
COMPLETE_WITH_QUERY(Query_for_list_of_languages);
else if (pg_strcasecmp(prev_wd, "SCHEMA") == 0)
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 } xxx TO
+ * FUNCTION | LANGUAGE | SCHEMA | TABLESPACE } xxx TO
*/
/* INSERT */
/* 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);
/* REINDEX */
else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
{
COMPLETE_WITH_LIST(my_list);
}
else if ((pg_strcasecmp(prev3_wd, "SET") == 0
+ || pg_strcasecmp(prev3_wd, "BEGIN") == 0
|| pg_strcasecmp(prev3_wd, "START") == 0
|| (pg_strcasecmp(prev4_wd, "CHARACTERISTICS") == 0
&& pg_strcasecmp(prev3_wd, "AS") == 0))
- && pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
+ && (pg_strcasecmp(prev2_wd, "TRANSACTION") == 0
+ || pg_strcasecmp(prev2_wd, "WORK") == 0)
&& pg_strcasecmp(prev_wd, "ISOLATION") == 0)
COMPLETE_WITH_CONST("LEVEL");
else if ((pg_strcasecmp(prev4_wd, "SET") == 0
+ || pg_strcasecmp(prev4_wd, "BEGIN") == 0
|| pg_strcasecmp(prev4_wd, "START") == 0
|| pg_strcasecmp(prev4_wd, "AS") == 0)
- && pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
+ && (pg_strcasecmp(prev3_wd, "TRANSACTION") == 0
+ || pg_strcasecmp(prev3_wd, "WORK") == 0)
&& pg_strcasecmp(prev2_wd, "ISOLATION") == 0
&& pg_strcasecmp(prev_wd, "LEVEL") == 0)
{
COMPLETE_WITH_LIST(my_list);
}
- else if (pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 &&
+ else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
+ pg_strcasecmp(prev4_wd, "WORK") == 0) &&
pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
pg_strcasecmp(prev2_wd, "LEVEL") == 0 &&
pg_strcasecmp(prev_wd, "READ") == 0)
COMPLETE_WITH_LIST(my_list);
}
- else if (pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 &&
+ else if ((pg_strcasecmp(prev4_wd, "TRANSACTION") == 0 ||
+ pg_strcasecmp(prev4_wd, "WORK") == 0) &&
pg_strcasecmp(prev3_wd, "ISOLATION") == 0 &&
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, "AS") == 0) &&
- pg_strcasecmp(prev2_wd, "TRANSACTION") == 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[] =
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)