Re: psql tab completion enhancements - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: psql tab completion enhancements
Date
Msg-id 200602120726.k1C7QSG16657@candle.pha.pa.us
Whole thread Raw
In response to psql tab completion enhancements  (Joachim Wieland <joe@mcknight.de>)
List pgsql-patches
Modified patch attached and applied.

Rather than create the lists in psql, I used UNION SELECT 'KEYWORD' to
pass the keyword to the backend to be added to the query list.

This was already being done for schema names, and was easy and efficient
to add.  My addition is even simpler because it just concatenates two
adjacent strings.  If you have more modifications, please use this
system.

If you find a macro that needs an 'addon', you can add it as a macro
parameter to all calls and just use "" if you don't need it.  If any
macro call uses a non-constant string, you have to make a new *_ADDON
macro version.

---------------------------------------------------------------------------

Joachim Wieland wrote:
> Hi,
>
> psql's tab completion has the following problem:
>
> If we have the following syntax for example:
>
> SET SESSION AUTHORIZATION <user>;
> SET SESSION AUTHORIZATION DEFAULT;
>
> After "SET SESSION AUTHORIZATION", the tab completion can offer a list of
> roles or the string constant "DEFAULT". However it can't offer both because
> it can't get a list of roles and add a string constant to this list.
>
> The appended patch adds the functionality of lists that can be extended with
> constants.
>
> Then you get:
>
> template1=# SET session AUTHORIZATION <tab>
> DEFAULT  fred     joe      john
>
> I did proof-of-concept examples to add a constant to a
>
>  - list from a query
>  - list from a schema query
>  - list of table attributes
>
>
> Joachim
>

[ Attachment, skipping... ]

>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: explain analyze is your friend

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: src/bin/psql/tab-complete.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v
retrieving revision 1.146
diff -c -c -r1.146 tab-complete.c
*** src/bin/psql/tab-complete.c    12 Feb 2006 03:22:19 -0000    1.146
--- src/bin/psql/tab-complete.c    12 Feb 2006 07:18:33 -0000
***************
*** 140,153 ****
  */
  #define COMPLETE_WITH_QUERY(query) \
  do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
! #define COMPLETE_WITH_SCHEMA_QUERY(query,addon) \
  do { completion_squery = &(query); completion_charp = addon; matches = completion_matches(text,
complete_from_schema_query);} while(0) 
  #define COMPLETE_WITH_LIST(list) \
  do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
  #define COMPLETE_WITH_CONST(string) \
  do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
! #define COMPLETE_WITH_ATTR(table) \
! do {completion_charp = Query_for_list_of_attributes; completion_info_charp = table; matches =
completion_matches(text,complete_from_query); } while(0) 

  /*
   * Assembly instructions for schema queries
--- 140,155 ----
  */
  #define COMPLETE_WITH_QUERY(query) \
  do { completion_charp = query; matches = completion_matches(text, complete_from_query); } while(0)
! #define COMPLETE_WITH_QUERY_ADDON(query, addon) \
! do { completion_charp = query addon; matches = completion_matches(text, complete_from_query); } while(0)
! #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
  do { completion_squery = &(query); completion_charp = addon; matches = completion_matches(text,
complete_from_schema_query);} while(0) 
  #define COMPLETE_WITH_LIST(list) \
  do { completion_charpp = list; matches = completion_matches(text, complete_from_list); } while(0)
  #define COMPLETE_WITH_CONST(string) \
  do { completion_charp = string; matches = completion_matches(text, complete_from_const); } while(0)
! #define COMPLETE_WITH_ATTR(table, addon) \
! do {completion_charp = Query_for_list_of_attributes addon; completion_info_charp = table; matches =
completion_matches(text,complete_from_query); } while(0) 

  /*
   * Assembly instructions for schema queries
***************
*** 754,767 ****
      else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
               (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
                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 &&
               pg_strcasecmp(prev_wd, "TO") != 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)
--- 756,783 ----
      else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
               (pg_strcasecmp(prev_wd, "ALTER") == 0 ||
                pg_strcasecmp(prev_wd, "RENAME") == 0))
!         COMPLETE_WITH_ATTR(prev2_wd, " UNION SELECT 'COLUMN'");

+     /* If we have TABLE <sth> ALTER COLUMN|RENAME COLUMN, provide list of columns */
+     else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
+              (pg_strcasecmp(prev2_wd, "ALTER") == 0 ||
+               pg_strcasecmp(prev2_wd, "RENAME") == 0) &&
+              pg_strcasecmp(prev_wd, "COLUMN") == 0)
+         COMPLETE_WITH_ATTR(prev3_wd, "");
+
      /* ALTER TABLE xxx RENAME yyy */
      else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
               pg_strcasecmp(prev2_wd, "RENAME") == 0 &&
               pg_strcasecmp(prev_wd, "TO") != 0)
          COMPLETE_WITH_CONST("TO");

+     /* ALTER TABLE xxx RENAME COLUMN yyy */
+     else if (pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
+              pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
+              pg_strcasecmp(prev2_wd, "COLUMN") == 0 &&
+              pg_strcasecmp(prev_wd, "TO") != 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)
***************
*** 775,781 ****
      else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
               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) ||
--- 791,797 ----
      else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
               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) ||
***************
*** 1021,1038 ****
               pg_strcasecmp(prev2_wd, "ON") == 0)
      {
          if (find_open_parenthesis(end))
!             COMPLETE_WITH_ATTR(prev_wd);
          else
              COMPLETE_WITH_CONST("(");
      }
      else if (pg_strcasecmp(prev5_wd, "INDEX") == 0 &&
              pg_strcasecmp(prev3_wd, "ON") == 0 &&
              pg_strcasecmp(prev_wd, "(") == 0)
!         COMPLETE_WITH_ATTR(prev2_wd);
      /* same if you put in USING */
      else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
               pg_strcasecmp(prev2_wd, "USING") == 0)
!         COMPLETE_WITH_ATTR(prev3_wd);
      /* Complete USING with an index method */
      else if (pg_strcasecmp(prev_wd, "USING") == 0)
      {
--- 1037,1054 ----
               pg_strcasecmp(prev2_wd, "ON") == 0)
      {
          if (find_open_parenthesis(end))
!             COMPLETE_WITH_ATTR(prev_wd, "");
          else
              COMPLETE_WITH_CONST("(");
      }
      else if (pg_strcasecmp(prev5_wd, "INDEX") == 0 &&
              pg_strcasecmp(prev3_wd, "ON") == 0 &&
              pg_strcasecmp(prev_wd, "(") == 0)
!         COMPLETE_WITH_ATTR(prev2_wd, "");
      /* same if you put in USING */
      else if (pg_strcasecmp(prev4_wd, "ON") == 0 &&
               pg_strcasecmp(prev2_wd, "USING") == 0)
!         COMPLETE_WITH_ATTR(prev3_wd, "");
      /* Complete USING with an index method */
      else if (pg_strcasecmp(prev_wd, "USING") == 0)
      {
***************
*** 1420,1426 ****
      else if (rl_line_buffer[start - 1] == '(' &&
               pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
               pg_strcasecmp(prev2_wd, "INTO") == 0)
!         COMPLETE_WITH_ATTR(prev_wd);

      /*
       * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
--- 1436,1442 ----
      else if (rl_line_buffer[start - 1] == '(' &&
               pg_strcasecmp(prev3_wd, "INSERT") == 0 &&
               pg_strcasecmp(prev2_wd, "INTO") == 0)
!         COMPLETE_WITH_ATTR(prev_wd, "");

      /*
       * Complete INSERT INTO <table> with "VALUES" or "SELECT" or "DEFAULT
***************
*** 1452,1461 ****

  /* LOCK */
      /* Complete LOCK [TABLE] with a list of tables */
!     else if (pg_strcasecmp(prev_wd, "LOCK") == 0 ||
!              (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
!               pg_strcasecmp(prev2_wd, "LOCK") == 0))
!         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);

      /* For the following, handle the case of a single table only for now */

--- 1468,1479 ----

  /* LOCK */
      /* Complete LOCK [TABLE] with a list of tables */
!     else if (pg_strcasecmp(prev_wd, "LOCK") == 0)
!         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables,
!                                    " UNION SELECT 'TABLE'");
!     else if (pg_strcasecmp(prev_wd, "TABLE") == 0 &&
!              pg_strcasecmp(prev2_wd, "LOCK") == 0)
!         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");

      /* For the following, handle the case of a single table only for now */

***************
*** 1498,1504 ****
      else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
               pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
               pg_strcasecmp(prev_wd, "BY") == 0)
!         COMPLETE_WITH_ATTR(prev3_wd);

  /* PREPARE xx AS */
      else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
--- 1516,1522 ----
      else if (pg_strcasecmp(prev4_wd, "FROM") == 0 &&
               pg_strcasecmp(prev2_wd, "ORDER") == 0 &&
               pg_strcasecmp(prev_wd, "BY") == 0)
!         COMPLETE_WITH_ATTR(prev3_wd, "");

  /* PREPARE xx AS */
      else if (pg_strcasecmp(prev_wd, "AS") == 0 &&
***************
*** 1639,1645 ****
      else if (pg_strcasecmp(prev3_wd, "SET") == 0
               && pg_strcasecmp(prev2_wd, "SESSION") == 0
               && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
!         COMPLETE_WITH_QUERY(Query_for_list_of_roles);
      /* Complete RESET SESSION with AUTHORIZATION */
      else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
               pg_strcasecmp(prev_wd, "SESSION") == 0)
--- 1657,1663 ----
      else if (pg_strcasecmp(prev3_wd, "SET") == 0
               && pg_strcasecmp(prev2_wd, "SESSION") == 0
               && pg_strcasecmp(prev_wd, "AUTHORIZATION") == 0)
!         COMPLETE_WITH_QUERY_ADDON(Query_for_list_of_roles, " UNION SELECT 'DEFAULT'");
      /* Complete RESET SESSION with AUTHORIZATION */
      else if (pg_strcasecmp(prev2_wd, "RESET") == 0 &&
               pg_strcasecmp(prev_wd, "SESSION") == 0)
***************
*** 1706,1712 ****
       * make a list of attributes.
       */
      else if (pg_strcasecmp(prev_wd, "SET") == 0)
!         COMPLETE_WITH_ATTR(prev2_wd);

  /* UPDATE xx SET yy = */
      else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
--- 1724,1730 ----
       * make a list of attributes.
       */
      else if (pg_strcasecmp(prev_wd, "SET") == 0)
!         COMPLETE_WITH_ATTR(prev2_wd, "");

  /* UPDATE xx SET yy = */
      else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
***************
*** 1763,1769 ****
  /* WHERE */
      /* Simple case of the word before the where being the table name */
      else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
!         COMPLETE_WITH_ATTR(prev2_wd);

  /* ... FROM ... */
  /* TODO: also include SRF ? */
--- 1781,1787 ----
  /* WHERE */
      /* Simple case of the word before the where being the table name */
      else if (pg_strcasecmp(prev_wd, "WHERE") == 0)
!         COMPLETE_WITH_ATTR(prev2_wd, "");

  /* ... FROM ... */
  /* TODO: also include SRF ? */

pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: OS X shared memory documentation
Next
From: Bruce Momjian
Date:
Subject: Re: parallel builds with dependencies