Skip site navigation (1) Skip section navigation (2)

psql tab-completion improvements

From: "Greg Sabino Mullane" <greg(at)turnstep(dot)com>
To: pgsql-patches(at)postgresql(dot)org
Subject: psql tab-completion improvements
Date: 2004-08-31 23:34:10
Message-ID: b447ea8bbb88618afc0ebc998f8149b7@biglumber.com (view raw or flat)
Thread:
Lists: pgsql-patches
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
NotDashEscaped: You need GnuPG to verify this message


Some improvements for the tab-completion of psql. This should 
address all of the items in the todo list and adds some new 
things as well. Specifically:

* Add support for ALTER SEQUENCE ...
* Add "RENAME TO" for ALTER TRIGGER xx ON yy
* Pick proper table for ALTER TRIGGER xx ON ...
* Support for ALTER USER xxx ...
* Fix ALTER GROUP xxx DROP ...
* Fix ALTER DOMAIN xxx DROP ...
* Remove "OWNER TO" from ALTER DOMAIN xx DROP ...
* Fix ALTER DOMAIN xx SET DEFAULT ..
* Prevent ALTER INDEX xxx SET TABLESPACE from using "TO"
* Support for ALTER LANGUAGE xxx (RENAME TO)
* More support for ALTER TABLE xxx ALTER COLUMN xxx ...
* More support for COPY

--
Greg Sabino Mullane greg(at)turnstep(dot)com
PGP Key: 0x14964AC8 200408311930




Index: tab-complete.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/psql/tab-complete.c,v
retrieving revision 1.114
diff -c -r1.114 tab-complete.c
*** tab-complete.c	29 Aug 2004 05:06:54 -0000	1.114
--- tab-complete.c	31 Aug 2004 23:25:07 -0000
***************
*** 386,391 ****
--- 386,400 ----
  "       and pg_catalog.quote_ident(c1.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_list_of_tables_for_trigger \
+ "SELECT pg_catalog.quote_ident(relname) "\
+ "  FROM pg_catalog.pg_class"\
+ " WHERE (%d = length('%s'))"\
+ "   AND oid IN "\
+ "       (SELECT tgrelid FROM pg_catalog.pg_trigger "\
+ "         WHERE pg_catalog.quote_ident(tgname)='%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.
***************
*** 637,647 ****
  	else if (!prev_wd)
  		COMPLETE_WITH_LIST(sql_commands);
  
! /* CREATE or DROP but not ALTER TABLE sth DROP */
  	/* complete with something you can create or drop */
  	else if (pg_strcasecmp(prev_wd, "CREATE") == 0 ||
  			 (pg_strcasecmp(prev_wd, "DROP") == 0 &&
! 			  pg_strcasecmp(prev3_wd, "TABLE") != 0))
  		matches = completion_matches(text, create_command_generator);
  
  /* ALTER */
--- 646,658 ----
  	else if (!prev_wd)
  		COMPLETE_WITH_LIST(sql_commands);
  
! /* CREATE or DROP but not ALTER (TABLE|DOMAIN|GROUP) sth DROP */
  	/* complete with something you can create or drop */
  	else if (pg_strcasecmp(prev_wd, "CREATE") == 0 ||
  			 (pg_strcasecmp(prev_wd, "DROP") == 0 &&
! 			  pg_strcasecmp(prev3_wd, "TABLE") != 0 &&
! 			  pg_strcasecmp(prev3_wd, "DOMAIN") != 0 &&
! 			  pg_strcasecmp(prev3_wd, "GROUP") != 0))
  		matches = completion_matches(text, create_command_generator);
  
  /* ALTER */
***************
*** 694,699 ****
--- 705,726 ----
  		COMPLETE_WITH_LIST(list_ALTERINDEX);
  	}
  
+ 	/* ALTER LANGUAGE <name> */
+ 	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ 					 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
+ 			COMPLETE_WITH_CONST("RENAME TO");
+ 
+ 	/* ALTER USER <name> */
+ 	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ 			 pg_strcasecmp(prev2_wd, "USER") == 0)
+ 	{
+ 		static const char *const list_ALTERUSER[] =
+ 		{"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
+ 		 "NOCREATEUSER", "VALID UNTIL", "RENAME TO", "SET", "RESET", NULL};
+ 
+ 		COMPLETE_WITH_LIST(list_ALTERUSER);
+ 	}
+ 
  	/* ALTER DOMAIN <name> */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
***************
*** 709,715 ****
  			 pg_strcasecmp(prev_wd, "DROP") == 0)
  	{
  		static const char *const list_ALTERDOMAIN2[] =
! 		{"CONSTRAINT", "DEFAULT", "NOT NULL", "OWNER TO", NULL};
  
  		COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
  	}
--- 736,742 ----
  			 pg_strcasecmp(prev_wd, "DROP") == 0)
  	{
  		static const char *const list_ALTERDOMAIN2[] =
! 		{"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
  
  		COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
  	}
***************
*** 723,733 ****
  
  		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(prev_wd, "ON") != 0)
! 		COMPLETE_WITH_CONST("ON");
  
  	/*
  	 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
--- 750,785 ----
  
  		COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
  	}
+ 	/* ALTER SEQUENCE <name> */
+ 	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ 					 pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
+ 	{
+ 			static const char *const list_ALTERSCHEMA[] =
+ 			{"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE", NULL};
+ 
+ 			COMPLETE_WITH_LIST(list_ALTERSCHEMA);
+ 	}
+ 	/* ALTER SEQUENCE <name> NO */
+ 	else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
+ 					 pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
+ 					 pg_strcasecmp(prev_wd, "NO") == 0)
+ 	{
+ 			static const char *const list_ALTERSCHEMA2[] =
+ 			{"MINVALUE", "MAXVALUE", "CYCLE", NULL};
+ 			
+ 			COMPLETE_WITH_LIST(list_ALTERSCHEMA2);
+ 	}
  	/* ALTER TRIGGER <name>, add ON */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
! 					 pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
! 			COMPLETE_WITH_CONST("ON");
! 	
! 	else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
! 					 pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
! 	{
! 			completion_info_charp = prev2_wd;
! 			COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
! 	}
  
  	/*
  	 * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
***************
*** 737,742 ****
--- 789,799 ----
  			 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)
+ 			COMPLETE_WITH_CONST("RENAME TO");
+ 
  	/*
  	 * If we detect ALTER TABLE <name>, suggest either ADD, DROP, ALTER,
  	 * RENAME, CLUSTER ON or OWNER
***************
*** 756,761 ****
--- 813,823 ----
  			  pg_strcasecmp(prev_wd, "RENAME") == 0))
  		COMPLETE_WITH_ATTR(prev2_wd);
  
+ 	/* ALTER TABLE xxx RENAME yyy */
+ 	else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
+ 					 pg_strcasecmp(prev2_wd, "RENAME") == 0)
+ 		COMPLETE_WITH_CONST("TO");
+ 
  	/* If we have TABLE <sth> DROP, provide COLUMN or CONSTRAINT */
  	else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
  			 pg_strcasecmp(prev_wd, "DROP") == 0)
***************
*** 770,775 ****
--- 832,850 ----
  			 pg_strcasecmp(prev2_wd, "DROP") == 0 &&
  			 pg_strcasecmp(prev_wd, "COLUMN") == 0)
  		COMPLETE_WITH_ATTR(prev3_wd);
+ 	/* ALTER TABLE ALTER [COLUMN] <foo> */
+ 	else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ 						pg_strcasecmp(prev2_wd, "COLUMN") == 0) ||
+ 					 (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
+ 						pg_strcasecmp(prev2_wd, "ALTER") == 0))
+ 	{
+ 		/* DROP ... does not work well yet */
+ 			static const char *const list_COLUMNALTER[] = 
+ 			{"TYPE", "SET DEFAULT", "DROP DEFAULT", "SET NOT NULL", "DROP NOT NULL",
+ 			 "SET STATISTICS", "SET STORAGE", NULL};
+ 
+ 			COMPLETE_WITH_LIST(list_COLUMNALTER);
+ 	}
  	else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
  			 pg_strcasecmp(prev_wd, "CLUSTER") == 0)
  		COMPLETE_WITH_CONST("ON");
***************
*** 817,828 ****
  	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)
  	{
  		static const char *const list_ALTERGROUP[] =
! 		{"ADD", "DROP", NULL};
  
  		COMPLETE_WITH_LIST(list_ALTERGROUP);
  	}
--- 892,903 ----
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "TYPE") == 0)
  		COMPLETE_WITH_CONST("OWNER TO");
! 	/* complete ALTER GROUP <foo> */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "GROUP") == 0)
  	{
  		static const char *const list_ALTERGROUP[] =
! 		{"ADD USER", "DROP USER", "RENAME TO", NULL};
  
  		COMPLETE_WITH_LIST(list_ALTERGROUP);
  	}
***************
*** 926,937 ****
  	else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
  			 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
  			 pg_strcasecmp(prev2_wd, "BINARY") == 0)
! 	{
! 		static const char *const list_FROMTO[] =
! 		{"FROM", "TO", NULL};
  
! 		COMPLETE_WITH_LIST(list_FROMTO);
! 	}
  
  /* CREATE INDEX */
  	/* First off we complete CREATE UNIQUE with "INDEX" */
--- 1001,1043 ----
  	else if (pg_strcasecmp(prev2_wd, "COPY") == 0 ||
  			 pg_strcasecmp(prev2_wd, "\\copy") == 0 ||
  			 pg_strcasecmp(prev2_wd, "BINARY") == 0)
! 		{
! 			static const char *const list_FROMTO[] =
! 			{"FROM", "TO", NULL};
! 			
! 			COMPLETE_WITH_LIST(list_FROMTO);
! 		}
! 	/* If we have COPY|BINARY <sth> FROM|TO, complete with filename */
! 	else if ((pg_strcasecmp(prev3_wd, "COPY") == 0 ||
! 						pg_strcasecmp(prev3_wd, "\\copy") == 0 ||
! 						pg_strcasecmp(prev3_wd, "BINARY") == 0) &&
! 					 (pg_strcasecmp(prev_wd, "FROM") == 0 ||
! 						pg_strcasecmp(prev_wd, "TO") == 0))
! 		matches = completion_matches(text, filename_completion_function);
  
! 	/* Handle COPY|BINARY <sth> FROM|TO filename */
! 	else if ((pg_strcasecmp(prev4_wd, "COPY") == 0 ||
! 						pg_strcasecmp(prev4_wd, "\\copy") == 0 ||
! 						pg_strcasecmp(prev4_wd, "BINARY") == 0) &&
! 					 (pg_strcasecmp(prev2_wd, "FROM") == 0 ||
! 						pg_strcasecmp(prev2_wd, "TO") == 0))
! 		{
! 			static const char *const list_COPY[] =
! 			{"BINARY", "OIDS", "DELIMETER", "NULL", "CSV", NULL};
! 
! 			COMPLETE_WITH_LIST(list_COPY);
! 		}
! 
! 	/* Handle COPY|BINARY <sth> FROM|TO filename CSV */
! 	else if (pg_strcasecmp(prev_wd, "CSV") == 0 && 
! 					 (pg_strcasecmp(prev3_wd, "FROM") == 0 ||
! 						pg_strcasecmp(prev3_wd, "TO") == 0))
! 		{
! 			static const char *const list_CSV[] =
! 			{"QUOTE", "ESCAPE", "FORCE QUOTE", NULL};
! 
! 			COMPLETE_WITH_LIST(list_CSV);
! 		}
  
  /* CREATE INDEX */
  	/* First off we complete CREATE UNIQUE with "INDEX" */
***************
*** 1353,1359 ****
  		COMPLETE_WITH_QUERY(Query_for_list_of_users);
  	/* Complete SET <var> with "TO" */
  	else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
! 			 pg_strcasecmp(prev4_wd, "UPDATE") != 0)
  		COMPLETE_WITH_CONST("TO");
  	/* Suggest possible variable values */
  	else if (pg_strcasecmp(prev3_wd, "SET") == 0 &&
--- 1459,1467 ----
  		COMPLETE_WITH_QUERY(Query_for_list_of_users);
  	/* 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 &&
***************
*** 1432,1438 ****
  
  /* ... FROM ... */
  /* TODO: also include SRF ? */
! 	else if (pg_strcasecmp(prev_wd, "FROM") == 0)
  		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv, NULL);
  
  
--- 1540,1548 ----
  
  /* ... 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);
  
  


-----BEGIN PGP SIGNATURE-----

iD8DBQFBNQrPvJuQZxSWSsgRAqU2AKDEoTixdsiLcpZOKpY4Na1UNZmmSgCcDsxQ
7gyOrB6e2Pvtt5KrecRVULA=
=/xhb
-----END PGP SIGNATURE-----



Responses

pgsql-patches by date

Next:From: Bruce MomjianDate: 2004-09-01 00:09:58
Subject: Re: Typo in tab-complete.c
Previous:From: Greg Sabino MullaneDate: 2004-08-31 23:14:56
Subject: Typo in tab-complete.c

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group