psql tab-completion improvements - Mailing list pgsql-patches

From Greg Sabino Mullane
Subject psql tab-completion improvements
Date
Msg-id b447ea8bbb88618afc0ebc998f8149b7@biglumber.com
Whole thread Raw
Responses Re: psql tab-completion improvements  (Bruce Momjian <pgman@candle.pha.pa.us>)
Re: psql tab-completion improvements  (Neil Conway <neilc@samurai.com>)
List 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@turnstep.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-----



pgsql-patches by date:

Previous
From: "Greg Sabino Mullane"
Date:
Subject: Typo in tab-complete.c
Next
From: Bruce Momjian
Date:
Subject: Re: Typo in tab-complete.c