diff -cprN head/src/bin/psql/tab-complete.c work/src/bin/psql/tab-complete.c
*** head/src/bin/psql/tab-complete.c	Tue Jan 26 11:47:08 2010
--- work/src/bin/psql/tab-complete.c	Wed Feb 10 10:57:29 2010
*************** psql_completion(char *text, int start, i
*** 618,624 ****
  	static const char *const sql_commands[] = {
  		"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
  		"COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
! 		"DELETE FROM", "DISCARD", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
  		"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
  		"REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
  		"SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TABLE", "TRUNCATE", "UNLISTEN",
--- 618,624 ----
  	static const char *const sql_commands[] = {
  		"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
  		"COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
! 		"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN", "FETCH",
  		"GRANT", "INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY", "PREPARE",
  		"REASSIGN", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
  		"SAVEPOINT", "SELECT", "SET", "SHOW", "START", "TABLE", "TRUNCATE", "UNLISTEN",
*************** psql_completion(char *text, int start, i
*** 749,754 ****
--- 749,788 ----
  
  		COMPLETE_WITH_LIST(list_ALTERINDEX);
  	}
+ 	/* ALTER INDEX <name> SET */
+ 	else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
+ 			 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
+ 			 pg_strcasecmp(prev_wd, "SET") == 0)
+ 	{
+ 		if (find_open_parenthesis(end))
+ 			COMPLETE_WITH_CONST("");
+ 		else
+ 		{
+ 			static const char *const list_ALTERINDEXSET[] =
+ 			{"(", "TABLESPACE", NULL};
+ 
+ 			COMPLETE_WITH_LIST(list_ALTERINDEXSET);
+ 		}
+ 	}
+ 	/* ALTER INDEX <name> RESET */
+ 	else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
+ 			 pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
+ 			 pg_strcasecmp(prev_wd, "RESET") == 0)
+ 	{
+ 		COMPLETE_WITH_CONST("(");
+ 	}
+ 	/* ALTER INDEX <foo> SET|RESET ( */
+ 	else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
+ 			 pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
+ 			 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
+ 			  pg_strcasecmp(prev2_wd, "RESET") == 0) &&
+ 			 pg_strcasecmp(prev_wd, "(") == 0)
+ 	{
+ 		static const char *const list_INDEXOPTIONS[] =
+ 		{"fillfactor", "fastupdate", NULL};
+ 
+ 		COMPLETE_WITH_LIST(list_INDEXOPTIONS);
+ 	}
  
  	/* ALTER LANGUAGE <name> */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
*************** psql_completion(char *text, int start, i
*** 977,997 ****
  			  pg_strcasecmp(prev2_wd, "ALTER") == 0))
  	{
  		static const char *const list_COLUMNALTER[] =
! 		{"TYPE", "SET", "DROP", NULL};
  
  		COMPLETE_WITH_LIST(list_COLUMNALTER);
  	}
  	else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  			   pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
  			  (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
  			   pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
  			 pg_strcasecmp(prev_wd, "SET") == 0)
  	{
! 		static const char *const list_COLUMNSET[] =
! 		{"DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
  
! 		COMPLETE_WITH_LIST(list_COLUMNSET);
  	}
  	else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  			   pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
  			  (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
--- 1011,1062 ----
  			  pg_strcasecmp(prev2_wd, "ALTER") == 0))
  	{
  		static const char *const list_COLUMNALTER[] =
! 		{"TYPE", "SET", "RESET", "DROP", NULL};
  
  		COMPLETE_WITH_LIST(list_COLUMNALTER);
  	}
+ 	/* ALTER TABLE ALTER [COLUMN] <foo> SET */
  	else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  			   pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
  			  (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
  			   pg_strcasecmp(prev3_wd, "ALTER") == 0)) &&
  			 pg_strcasecmp(prev_wd, "SET") == 0)
  	{
! 		if (find_open_parenthesis(end))
! 			COMPLETE_WITH_CONST("");
! 		else
! 		{
! 			static const char *const list_COLUMNSET[] =
! 			{"(", "DEFAULT", "NOT NULL", "STATISTICS", "STORAGE", NULL};
! 
! 			COMPLETE_WITH_LIST(list_COLUMNSET);
! 		}
! 	}
! 	/* ALTER TABLE ALTER [COLUMN] <foo> SET ( */
! 	else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
! 			   pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
! 			  pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
! 			 pg_strcasecmp(prev2_wd, "SET") == 0 &&
! 			 pg_strcasecmp(prev_wd, "(") == 0)
! 	{
! 		static const char *const list_COLUMNOPTIONS[] =
! 		{"n_distinct", "n_distinct_inherited", NULL};
! 
! 		COMPLETE_WITH_LIST(list_COLUMNOPTIONS);
! 	}
! 	/* ALTER TABLE ALTER [COLUMN] <foo> SET STORAGE */
! 	else if (((pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
! 			   pg_strcasecmp(prev4_wd, "COLUMN") == 0) ||
! 			  pg_strcasecmp(prev4_wd, "ALTER") == 0) &&
! 			 pg_strcasecmp(prev2_wd, "SET") == 0 &&
! 			 pg_strcasecmp(prev_wd, "STORAGE") == 0)
! 	{
! 		static const char *const list_COLUMNSTORAGE[] =
! 		{"PLAIN", "EXTERNAL", "EXTENDED", "MAIN", NULL};
  
! 		COMPLETE_WITH_LIST(list_COLUMNSTORAGE);
  	}
+ 	/* ALTER TABLE ALTER [COLUMN] <foo> DROP */
  	else if (((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  			   pg_strcasecmp(prev3_wd, "COLUMN") == 0) ||
  			  (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
*************** psql_completion(char *text, int start, i
*** 1003,1011 ****
--- 1068,1078 ----
  
  		COMPLETE_WITH_LIST(list_COLUMNDROP);
  	}
+ 	/* ALTER TABLE <foo> CLUSTER */
  	else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
  			 pg_strcasecmp(prev_wd, "CLUSTER") == 0)
  		COMPLETE_WITH_CONST("ON");
+ 	/* ALTER TABLE <foo> CLUSTER ON */
  	else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
  			 pg_strcasecmp(prev2_wd, "CLUSTER") == 0 &&
  			 pg_strcasecmp(prev_wd, "ON") == 0)
*************** psql_completion(char *text, int start, i
*** 1017,1026 ****
  	else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
  			 pg_strcasecmp(prev_wd, "SET") == 0)
  	{
! 		static const char *const list_TABLESET[] =
! 		{"WITHOUT", "TABLESPACE", "SCHEMA", 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 &&
--- 1084,1098 ----
  	else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
  			 pg_strcasecmp(prev_wd, "SET") == 0)
  	{
! 		if (find_open_parenthesis(end))
! 			COMPLETE_WITH_CONST("");
! 		else
! 		{
! 			static const char *const list_TABLESET[] =
! 			{"(", "WITHOUT", "TABLESPACE", "SCHEMA", 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 &&
*************** psql_completion(char *text, int start, i
*** 1037,1051 ****
  
  		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);
  	}
  	/* ALTER TEXT SEARCH */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
--- 1109,1176 ----
  
  		COMPLETE_WITH_LIST(list_TABLESET2);
  	}
! 	/* ALTER TABLE <foo> RESET */
! 	else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
! 			 pg_strcasecmp(prev_wd, "RESET") == 0)
! 	{
! 		COMPLETE_WITH_CONST("(");
! 	}
! 	/* ALTER TABLE <foo> SET|RESET ( */
! 	else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
! 			 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
! 			  pg_strcasecmp(prev2_wd, "RESET") == 0) &&
! 			 pg_strcasecmp(prev_wd, "(") == 0)
! 	{
! 		static const char *const list_TABLEOPTIONS[] =
! 		{"fillfactor",
! 		 "autovacuum_enabled", "toast.autovacuum_enabled",
! 		 "autovacuum_vacuum_threshold", "toast.autovacuum_vacuum_threshold",
! 		 "autovacuum_vacuum_scale_factor", "toast.autovacuum_vacuum_scale_factor",
! 		 "autovacuum_analyze_threshold", "toast.autovacuum_analyze_threshold",
! 		 "autovacuum_analyze_scale_factor", "toast.autovacuum_analyze_scale_factor",
! 		 "autovacuum_vacuum_cost_delay", "toast.autovacuum_vacuum_cost_delay",
! 		 "autovacuum_vacuum_cost_limit", "toast.autovacuum_vacuum_cost_limit",
! 		 "autovacuum_freeze_min_age", "toast.autovacuum_freeze_min_age",
! 		 "autovacuum_freeze_max_age", "toast.autovacuum_freeze_max_age",
! 		 "autovacuum_freeze_table_age", "toast.autovacuum_freeze_table_age",
! 		 NULL};
! 
! 		COMPLETE_WITH_LIST(list_TABLEOPTIONS);
! 	}
! 
! 	/* ALTER TABLESPACE <foo> with RENAME TO, OWNER TO, SET, RESET */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "TABLESPACE") == 0)
  	{
  		static const char *const list_ALTERTSPC[] =
! 		{"RENAME TO", "OWNER TO", "SET", "RESET", NULL};
  
  		COMPLETE_WITH_LIST(list_ALTERTSPC);
  	}
+ 	/* ALTER TABLESPACE <foo> SET|RESET */
+ 	else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
+ 			 pg_strcasecmp(prev3_wd, "TABLESPACE") == 0 &&
+ 			 (pg_strcasecmp(prev_wd, "SET") == 0 ||
+ 			  pg_strcasecmp(prev_wd, "RESET") == 0))
+ 	{
+ 		if (find_open_parenthesis(end))
+ 			COMPLETE_WITH_CONST("");
+ 		else
+ 			COMPLETE_WITH_CONST("(");
+ 	}
+ 	/* ALTER TABLESPACE <foo> SET|RESET ( */
+ 	else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
+ 			 pg_strcasecmp(prev4_wd, "TABLESPACE") == 0 &&
+ 			 (pg_strcasecmp(prev2_wd, "SET") == 0 ||
+ 			  pg_strcasecmp(prev2_wd, "RESET") == 0) &&
+ 			 pg_strcasecmp(prev_wd, "(") == 0)
+ 	{
+ 		static const char *const list_TABLESPACEOPTIONS[] =
+ 		{"seq_page_cost", "random_page_cost", NULL};
+ 
+ 		COMPLETE_WITH_LIST(list_TABLESPACEOPTIONS);
+ 	}
+ 
  	/* ALTER TEXT SEARCH */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "TEXT") == 0 &&
*************** psql_completion(char *text, int start, i
*** 1417,1422 ****
--- 1542,1558 ----
  
  		COMPLETE_WITH_LIST(list_CREATETRIGGER);
  	}
+ 	/* complete CREATE TRIGGER <name> BEFORE,AFTER with an event */
+ 	else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
+ 			 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
+ 			 (pg_strcasecmp(prev_wd, "BEFORE") == 0 ||
+ 			  pg_strcasecmp(prev_wd, "AFTER") == 0))
+ 	{
+ 		static const char *const list_CREATETRIGGER_EVENTS[] =
+ 		{"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
+ 
+ 		COMPLETE_WITH_LIST(list_CREATETRIGGER_EVENTS);
+ 	}
  	/* complete CREATE TRIGGER <name> BEFORE,AFTER sth with OR,ON */
  	else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
  			 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
*************** psql_completion(char *text, int start, i
*** 1428,1433 ****
--- 1564,1578 ----
  
  		COMPLETE_WITH_LIST(list_CREATETRIGGER2);
  	}
+ 	/* complete CREATE TRIGGER <name> BEFORE,AFTER event ON with a list of tables */
+ 	else if (pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
+ 			 (pg_strcasecmp(prev3_wd, "BEFORE") == 0 ||
+ 			  pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
+ 			 pg_strcasecmp(prev_wd, "ON") == 0)
+ 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+ 	/* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
+ 	else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0)
+ 		COMPLETE_WITH_CONST("PROCEDURE");
  
  /* CREATE ROLE,USER,GROUP */
  	else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
*************** psql_completion(char *text, int start, i
*** 1487,1492 ****
--- 1632,1638 ----
  		COMPLETE_WITH_LIST(list_DECLARE);
  	}
  
+ /* CURSOR */
  	else if (pg_strcasecmp(prev_wd, "CURSOR") == 0)
  	{
  		static const char *const list_DECLARECURSOR[] =
*************** psql_completion(char *text, int start, i
*** 1700,1711 ****
  	else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
  			 pg_strcasecmp(prev_wd, "REVOKE") == 0)
  	{
! 		static const char *const list_privileg[] =
  		{"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES",
  			"TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
  		"ALL", NULL};
  
! 		COMPLETE_WITH_LIST(list_privileg);
  	}
  	/* Complete GRANT/REVOKE <sth> with "ON" */
  	else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
--- 1846,1857 ----
  	else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
  			 pg_strcasecmp(prev_wd, "REVOKE") == 0)
  	{
! 		static const char *const list_privilege[] =
  		{"SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES",
  			"TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
  		"ALL", NULL};
  
! 		COMPLETE_WITH_LIST(list_privilege);
  	}
  	/* Complete GRANT/REVOKE <sth> with "ON" */
  	else if (pg_strcasecmp(prev2_wd, "GRANT") == 0 ||
*************** psql_completion(char *text, int start, i
*** 1735,1742 ****
  								   " UNION SELECT 'LARGE OBJECT'"
  								   " UNION SELECT 'SCHEMA'"
  								   " UNION SELECT 'TABLESPACE'");
  
! 	/* Complete "GRANT/REVOKE * ON * " with "TO" */
  	else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
  			  pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
  			 pg_strcasecmp(prev2_wd, "ON") == 0)
--- 1881,1898 ----
  								   " UNION SELECT 'LARGE OBJECT'"
  								   " UNION SELECT 'SCHEMA'"
  								   " UNION SELECT 'TABLESPACE'");
+ 	else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
+ 			  pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
+ 			 pg_strcasecmp(prev2_wd, "ON") == 0 &&
+ 			 pg_strcasecmp(prev_wd, "FOREIGN") == 0)
+ 	{
+ 		static const char *const list_privilege_foreign[] =
+ 		{"DATA WRAPPER", "SERVER", NULL};
  
! 		COMPLETE_WITH_LIST(list_privilege_foreign);
! 	}
! 
! 	/* Complete "GRANT/REVOKE * ON * " with "TO/FROM" */
  	else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
  			  pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
  			 pg_strcasecmp(prev2_wd, "ON") == 0)
*************** psql_completion(char *text, int start, i
*** 1758,1769 ****
  	}
  
  	/* 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_roles);
  
  /* GROUP BY */
  	else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
--- 1914,1935 ----
  	}
  
  	/* Complete "GRANT/REVOKE * ON * TO/FROM" with username, GROUP, or PUBLIC */
! 	else if (pg_strcasecmp(prev5_wd, "GRANT") == 0 &&
! 			 pg_strcasecmp(prev3_wd, "ON") == 0)
! 	{
! 		if (pg_strcasecmp(prev_wd, "TO") == 0)
! 			COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
! 		else
! 			COMPLETE_WITH_CONST("TO");
! 	}
! 	else if (pg_strcasecmp(prev5_wd, "REVOKE") == 0 &&
! 			 pg_strcasecmp(prev3_wd, "ON") == 0)
! 	{
! 		if (pg_strcasecmp(prev_wd, "FROM") == 0)
! 			COMPLETE_WITH_QUERY(Query_for_list_of_grant_roles);
! 		else
! 			COMPLETE_WITH_CONST("FROM");
! 	}
  
  /* GROUP BY */
  	else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
*************** psql_completion(char *text, int start, i
*** 2044,2049 ****
--- 2210,2216 ----
  	else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
  			 pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
  			 pg_strcasecmp(prev_wd, "TABLESPACE") != 0 &&
+ 			 pg_strcasecmp(prev_wd, "(") != 0 &&
  			 pg_strcasecmp(prev4_wd, "DOMAIN") != 0)
  		COMPLETE_WITH_CONST("TO");
  	/* Suggest possible variable values */
