diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 4c468a8..9c027f0 100644
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
*************** static const SchemaQuery Query_for_list_
*** 303,308 ****
--- 303,359 ----
  	NULL
  };
  
+ /* The bit masks for the following three functions come from
+  * src/include/catalog/pg_trigger.h.
+  */
+ static const SchemaQuery Query_for_list_of_insertables = {
+ 	/* catname */
+ 	"pg_catalog.pg_class c",
+ 	/* selcondition */
+ 	"(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
+ 	"(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 2) <> 0)))",
+ 	/* viscondition */
+ 	"pg_catalog.pg_table_is_visible(c.oid)",
+ 	/* namespace */
+ 	"c.relnamespace",
+ 	/* result */
+ 	"pg_catalog.quote_ident(c.relname)",
+ 	/* qualresult */
+ 	NULL
+ };
+ 
+ static const SchemaQuery Query_for_list_of_deletables = {
+ 	/* catname */
+ 	"pg_catalog.pg_class c",
+ 	/* selcondition */
+ 	"(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
+ 	"(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 3) <> 0)))",
+ 	/* viscondition */
+ 	"pg_catalog.pg_table_is_visible(c.oid)",
+ 	/* namespace */
+ 	"c.relnamespace",
+ 	/* result */
+ 	"pg_catalog.quote_ident(c.relname)",
+ 	/* qualresult */
+ 	NULL
+ };
+ 
+ static const SchemaQuery Query_for_list_of_updatables = {
+ 	/* catname */
+ 	"pg_catalog.pg_class c",
+ 	/* selcondition */
+ 	"(c.relkind = 'r' OR (c.relkind = 'v' AND c.relhastriggers AND EXISTS "
+ 	"(SELECT 1 FROM pg_catalog.pg_trigger t WHERE t.tgrelid = c.oid AND t.tgtype & (1 << 4) <> 0)))",
+ 	/* viscondition */
+ 	"pg_catalog.pg_table_is_visible(c.oid)",
+ 	/* namespace */
+ 	"c.relnamespace",
+ 	/* result */
+ 	"pg_catalog.quote_ident(c.relname)",
+ 	/* qualresult */
+ 	NULL
+ };
+ 
  static const SchemaQuery Query_for_list_of_tisv = {
  	/* catname */
  	"pg_catalog.pg_class c",
*************** static const SchemaQuery Query_for_list_
*** 333,338 ****
--- 384,404 ----
  	NULL
  };
  
+ static const SchemaQuery Query_for_list_of_tv = {
+ 	/* catname */
+ 	"pg_catalog.pg_class c",
+ 	/* selcondition */
+ 	"c.relkind IN ('r', 'v')",
+ 	/* viscondition */
+ 	"pg_catalog.pg_table_is_visible(c.oid)",
+ 	/* namespace */
+ 	"c.relnamespace",
+ 	/* result */
+ 	"pg_catalog.quote_ident(c.relname)",
+ 	/* qualresult */
+ 	NULL
+ };
+ 
  static const SchemaQuery Query_for_list_of_views = {
  	/* catname */
  	"pg_catalog.pg_class c",
*************** psql_completion(char *text, int start, i
*** 630,636 ****
  			   *prev2_wd,
  			   *prev3_wd,
  			   *prev4_wd,
! 			   *prev5_wd;
  
  	static const char *const sql_commands[] = {
  		"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
--- 696,703 ----
  			   *prev2_wd,
  			   *prev3_wd,
  			   *prev4_wd,
! 			   *prev5_wd,
! 			   *prev6_wd;
  
  	static const char *const sql_commands[] = {
  		"ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
*************** psql_completion(char *text, int start, i
*** 669,675 ****
  	completion_info_charp2 = NULL;
  
  	/*
! 	 * Scan the input line before our current position for the last five
  	 * 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.
  	 */
--- 736,742 ----
  	completion_info_charp2 = NULL;
  
  	/*
! 	 * Scan the input line before our current position for the last six
  	 * 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.
  	 */
*************** psql_completion(char *text, int start, i
*** 678,683 ****
--- 745,751 ----
  	prev3_wd = previous_word(start, 2);
  	prev4_wd = previous_word(start, 3);
  	prev5_wd = previous_word(start, 4);
+ 	prev6_wd = previous_word(start, 5);
  
  	/* If a backslash command was started, continue */
  	if (text[0] == '\\')
*************** psql_completion(char *text, int start, i
*** 974,987 ****
  		COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
  	}
  
- 	/*
- 	 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
- 	 */
- 	else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
- 			 pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
- 			 pg_strcasecmp(prev_wd, "ON") == 0)
- 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
- 
  	/* ALTER TRIGGER <name> ON <name> */
  	else if (pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "ON") == 0)
--- 1042,1047 ----
*************** psql_completion(char *text, int start, i
*** 1593,1599 ****
  	else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
  			 pg_strcasecmp(prev3_wd, "ON") == 0 &&
  			 pg_strcasecmp(prev_wd, "TO") == 0)
! 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
  
  /* CREATE SERVER <name> */
  	else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
--- 1653,1659 ----
  	else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
  			 pg_strcasecmp(prev3_wd, "ON") == 0 &&
  			 pg_strcasecmp(prev_wd, "TO") == 0)
! 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tv, NULL);
  
  /* CREATE SERVER <name> */
  	else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
*************** psql_completion(char *text, int start, i
*** 1655,1669 ****
  			 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
  	{
  		static const char *const list_CREATETRIGGER[] =
! 		{"BEFORE", "AFTER", NULL};
  
  		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};
--- 1715,1734 ----
  			 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
  	{
  		static const char *const list_CREATETRIGGER[] =
! 		{"BEFORE", "AFTER", "INSTEAD OF", NULL};
  
  		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)) ||
! 			(pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
! 			 pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
! 			 pg_strcasecmp(prev2_wd, "INSTEAD") == 0 &&
! 			 pg_strcasecmp(prev_wd, "OF") == 0))
! 
  	{
  		static const char *const list_CREATETRIGGER_EVENTS[] =
  		{"INSERT", "DELETE", "UPDATE", "TRUNCATE", NULL};
*************** psql_completion(char *text, int start, i
*** 1671,1680 ****
  		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 &&
  			 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
! 			  pg_strcasecmp(prev2_wd, "AFTER") == 0))
  	{
  		static const char *const list_CREATETRIGGER2[] =
  		{"ON", "OR", NULL};
--- 1736,1749 ----
  		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 &&
  			 (pg_strcasecmp(prev2_wd, "BEFORE") == 0 ||
! 			  pg_strcasecmp(prev2_wd, "AFTER") == 0)) ||
! 			(pg_strcasecmp(prev6_wd, "CREATE") == 0 &&
! 			 pg_strcasecmp(prev5_wd, "TRIGGER") == 0 &&
! 			 (pg_strcasecmp(prev3_wd, "INSTEAD") == 0 &&
! 			 (pg_strcasecmp(prev2_wd, "OF") == 0))))
  	{
  		static const char *const list_CREATETRIGGER2[] =
  		{"ON", "OR", NULL};
*************** psql_completion(char *text, int start, i
*** 1691,1696 ****
--- 1760,1770 ----
  			  pg_strcasecmp(prev3_wd, "AFTER") == 0) &&
  			 pg_strcasecmp(prev_wd, "ON") == 0)
  		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+ 	else if (pg_strcasecmp(prev6_wd, "TRIGGER") == 0 &&
+ 			 pg_strcasecmp(prev4_wd, "INSTEAD") == 0 &&
+ 			 pg_strcasecmp(prev3_wd, "OF") == 0 &&
+ 			 pg_strcasecmp(prev_wd, "ON") == 0)
+ 		 COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
  	/* complete CREATE TRIGGER ... EXECUTE with PROCEDURE */
  	else if (pg_strcasecmp(prev_wd, "EXECUTE") == 0)
  		COMPLETE_WITH_CONST("PROCEDURE");
*************** psql_completion(char *text, int start, i
*** 1778,1784 ****
  	/* Complete DELETE FROM with a list of tables */
  	else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
  			 pg_strcasecmp(prev_wd, "FROM") == 0)
! 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
  	/* Complete DELETE FROM <table> */
  	else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
  			 pg_strcasecmp(prev2_wd, "FROM") == 0)
--- 1852,1858 ----
  	/* Complete DELETE FROM with a list of tables */
  	else if (pg_strcasecmp(prev2_wd, "DELETE") == 0 &&
  			 pg_strcasecmp(prev_wd, "FROM") == 0)
! 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_deletables, NULL);
  	/* Complete DELETE FROM <table> */
  	else if (pg_strcasecmp(prev3_wd, "DELETE") == 0 &&
  			 pg_strcasecmp(prev2_wd, "FROM") == 0)
*************** psql_completion(char *text, int start, i
*** 2066,2072 ****
  	/* Complete INSERT INTO with table names */
  	else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
  			 pg_strcasecmp(prev_wd, "INTO") == 0)
! 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
  	/* Complete "INSERT INTO <table> (" with attribute names */
  	else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
  			 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
--- 2140,2146 ----
  	/* Complete INSERT INTO with table names */
  	else if (pg_strcasecmp(prev2_wd, "INSERT") == 0 &&
  			 pg_strcasecmp(prev_wd, "INTO") == 0)
! 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_insertables, NULL);
  	/* Complete "INSERT INTO <table> (" with attribute names */
  	else if (pg_strcasecmp(prev4_wd, "INSERT") == 0 &&
  			 pg_strcasecmp(prev3_wd, "INTO") == 0 &&
*************** psql_completion(char *text, int start, i
*** 2423,2429 ****
  /* 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");
--- 2497,2503 ----
  /* 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_updatables, NULL);
  	/* Complete UPDATE <table> with "SET" */
  	else if (pg_strcasecmp(prev2_wd, "UPDATE") == 0)
  		COMPLETE_WITH_CONST("SET");