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
Views: Raw Message | Whole Thread | Download mbox | Resend email
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

Browse pgsql-patches by date

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