Thread: psql tab-complete and backslash patch

psql tab-complete and backslash patch

From
Stefan Kaltenbrunner
Date:
Hi!

attached is a patch against psql that makes psql's tabcomplete code
ROLES aware, adds SET SCHEMA and basic CREATE DATABASE/TRIGGER support
as well as some other minor things.
In addition to this I modified \du to display a list of roles with some
additional information(createrole,connection limit) on 8.1 with a
fallback to the original output on older backends.

There are a few problems still left - in particular the the tab-complete
code is a little inconsistent wrt completing USER/ROLE/GROUP/OWNER TO
with roles or users/groups (from the pg_user/pg_group views)


comments(especially about the \du change)?

regards

Stefan Kaltenbrunner


Changes in Detail:

*) SET SCHEMA for ALTER AGGREGATE,FUNCTION.DOMAIN,SEQUENCE,TABLE,TYPE
*) add CONNECTION LIMIT to ALTER DATABASE
*) add support for ALTER ROLE
*) make ALTER USER aware about ROLES
*) COMMENT ON LARGE OBJECT
*) add support for CREATE DATABASE
*) add support for CREATE TRIGGER
*) add support for CREATE USER,ROLE,GROUP
*) complete SET ROLE with a list of roles
*) complete SET SCHEMA with a list of schemas
*) complete SET SESSION AUTHORIZATION with list of roles
*) fixes a small typo in a comment (ANALZYE -> ANALYZE)
*) modify \du to display createrole and the connection limit
Index: src/bin/psql/command.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/command.c,v
retrieving revision 1.151
diff -u -r1.151 command.c
--- src/bin/psql/command.c    25 Jul 2005 17:17:41 -0000    1.151
+++ src/bin/psql/command.c    13 Aug 2005 10:47:36 -0000
@@ -363,7 +363,7 @@
                 success = listTables(&cmd[1], pattern, show_verbose);
                 break;
             case 'u':
-                success = describeUsers(pattern);
+                success = describeRoles(pattern);
                 break;

             default:
Index: src/bin/psql/describe.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/describe.c,v
retrieving revision 1.122
diff -u -r1.122 describe.c
--- src/bin/psql/describe.c    18 Jul 2005 19:09:09 -0000    1.122
+++ src/bin/psql/describe.c    13 Aug 2005 10:47:38 -0000
@@ -1379,23 +1379,24 @@
 /*
  * \du
  *
- * Describes users.  Any schema portion of the pattern is ignored.
+ * Describes Roles.  Any schema portion of the pattern is ignored.
  */
 bool
-describeUsers(const char *pattern)
+describeRoles(const char *pattern)
 {
     PQExpBufferData buf;
     PGresult   *res;
     printQueryOpt myopt = pset.popt;

     initPQExpBuffer(&buf);
-
+    if (pset.sversion < 80100)
+        {
     printfPQExpBuffer(&buf,
                       "SELECT u.usename AS \"%s\",\n"
                       "  u.usesysid AS \"%s\",\n"
                       "  CASE WHEN u.usesuper AND u.usecreatedb THEN CAST('%s' AS pg_catalog.text)\n"
-            "       WHEN u.usesuper THEN CAST('%s' AS pg_catalog.text)\n"
-         "       WHEN u.usecreatedb THEN CAST('%s' AS pg_catalog.text)\n"
+                      "       WHEN u.usesuper THEN CAST('%s' AS pg_catalog.text)\n"
+                      "       WHEN u.usecreatedb THEN CAST('%s' AS pg_catalog.text)\n"
                       "       ELSE CAST('' AS pg_catalog.text)\n"
                       "  END AS \"%s\",\n"
                       "  ARRAY(SELECT g.groname FROM pg_catalog.pg_group g WHERE u.usesysid = ANY(g.grolist)) as
\"%s\"\n"
@@ -1408,6 +1409,37 @@
     processNamePattern(&buf, pattern, false, false,
                        NULL, "u.usename", NULL, NULL);

+    myopt.title = _("List of users");
+        } else {
+    printfPQExpBuffer(&buf,
+                      "SELECT r.rolname AS \"%s\",\n"
+                      "  CASE WHEN r.rolsuper AND r.rolcreaterole AND r.rolcreatedb THEN CAST('%s' AS
pg_catalog.text)\n"
+                      "  WHEN r.rolsuper AND r.rolcreaterole THEN CAST('%s' AS pg_catalog.text)\n"
+                      "  WHEN r.rolsuper AND r.rolcreatedb THEN CAST('%s' AS pg_catalog.text)\n"
+                      "  WHEN r.rolsuper THEN CAST('%s' AS pg_catalog.text)\n"
+                      "  WHEN r.rolcreaterole AND r.rolcreatedb THEN CAST('%s' AS pg_catalog.text)\n"
+                      "  WHEN r.rolcreaterole THEN CAST('%s' AS pg_catalog.text)\n"
+                      "  WHEN r.rolcreatedb THEN CAST('%s' AS pg_catalog.text)\n"
+                      "  ELSE CAST('' AS pg_catalog.text)\n"
+                      "  END AS \"%s\",\n"
+                      "  CASE WHEN r.rolconnlimit < 0 THEN CAST('no limit' AS pg_catalog.text)\n"
+                      "       ELSE CAST(r.rolconnlimit AS pg_catalog.text)\n"
+                      "  END AS \"%s\", \n"
+                      "  ARRAY(SELECT m.rolname FROM (SELECT pg_authid.rolname, ARRAY( SELECT pg_auth_members.member
FROMpg_auth_members WHERE pg_auth_members.roleid = pg_authid.oid) AS memlist FROM pg_authid) as m where r.oid =
ANY(m.memlist))as \"%s\"\n" 
+                      "FROM pg_catalog.pg_roles r\n",
+                      _("Role name"),
+                      _("superuser, create role, create database"),
+                      _("superuser, create role"),
+                      _("superuser, create database"),
+                      _("superuser"),_("create role, create database"),
+                      _("create role"),_("create database"),
+                      _("Attributes"),_("connection limit"),_("Member of"));
+
+    processNamePattern(&buf, pattern, false, false,
+                       NULL, "r.rolname", NULL, NULL);
+
+    myopt.title = _("List of roles");
+    }
     appendPQExpBuffer(&buf, "ORDER BY 1;");

     res = PSQLexec(buf.data, false);
@@ -1416,7 +1448,6 @@
         return false;

     myopt.nullPrint = NULL;
-    myopt.title = _("List of users");

     printQuery(res, &myopt, pset.queryFout, pset.logfile);

@@ -1424,7 +1455,6 @@
     return true;
 }

-
 /*
  * \dg
  *
Index: src/bin/psql/describe.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/describe.h,v
retrieving revision 1.28
diff -u -r1.28 describe.h
--- src/bin/psql/describe.h    1 Jan 2005 05:43:08 -0000    1.28
+++ src/bin/psql/describe.h    13 Aug 2005 10:47:38 -0000
@@ -26,7 +26,7 @@
 bool        describeOperators(const char *pattern);

 /* \du */
-bool        describeUsers(const char *pattern);
+bool        describeRoles(const char *pattern);

 /* \dg */
 bool        describeGroups(const char *pattern);
Index: src/bin/psql/tab-complete.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/tab-complete.c,v
retrieving revision 1.136
diff -u -r1.136 tab-complete.c
--- src/bin/psql/tab-complete.c    30 Jul 2005 15:17:22 -0000    1.136
+++ src/bin/psql/tab-complete.c    13 Aug 2005 10:47:39 -0000
@@ -363,6 +363,11 @@
 "   AND c.relnamespace = n.oid "\
 "   AND n.nspname = 'pg_catalog'"

+#define Query_for_list_of_roles \
+" SELECT pg_catalog.quote_ident(rolname) "\
+"   FROM pg_catalog.pg_roles "\
+"  WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
+
 #define Query_for_list_of_users \
 " SELECT pg_catalog.quote_ident(usename) "\
 "   FROM pg_catalog.pg_user "\
@@ -427,6 +432,7 @@
     {"INDEX", NULL, &Query_for_list_of_indexes},
     {"OPERATOR", NULL, NULL},    /* Querying for this is probably not such
                                  * a good idea. */
+    {"ROLE", Query_for_list_of_roles},
     {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE
substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
     {"SCHEMA", Query_for_list_of_schemas},
     {"SEQUENCE", NULL, &Query_for_list_of_sequences},
@@ -509,7 +515,9 @@
     static const char *const pgsql_variables[] = {
         /* these SET arguments are known in gram.y */
         "CONSTRAINTS",
+        "LOCAL",
         "NAMES",
+        "ROLE",
         "SESSION",
         "TRANSACTION",

@@ -681,17 +689,25 @@
     {
         static const char *const list_ALTER[] =
         {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION",
-            "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "SCHEMA", "SEQUENCE", "TABLE",
+            "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SEQUENCE", "TABLE",
         "TABLESPACE", "TRIGGER", "TYPE", "USER", NULL};

         COMPLETE_WITH_LIST(list_ALTER);
     }
+    /* ALTER AGGREGATE,FUNCTION <name> */
+    else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+            (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
+              pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
+    {
+        static const char *const list_ALTERAGG[] =
+                {"OWNER TO", "RENAME TO","SET SCHEMA", NULL};
+
+                COMPLETE_WITH_LIST(list_ALTERAGG);
+    }

-    /* ALTER AGGREGATE,CONVERSION,FUNCTION,SCHEMA <name> */
+    /* ALTER CONVERSION,SCHEMA <name> */
     else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
-             (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
-              pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
-              pg_strcasecmp(prev2_wd, "FUNCTION") == 0 ||
+              (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
               pg_strcasecmp(prev2_wd, "SCHEMA") == 0))
     {
         static const char *const list_ALTERGEN[] =
@@ -705,7 +721,7 @@
              pg_strcasecmp(prev2_wd, "DATABASE") == 0)
     {
         static const char *const list_ALTERDATABASE[] =
-        {"RESET", "SET", "OWNER TO", "RENAME TO", NULL};
+        {"RESET", "SET", "OWNER TO", "RENAME TO", "CONNECTION LIMIT", NULL};

         COMPLETE_WITH_LIST(list_ALTERDATABASE);
     }
@@ -725,17 +741,27 @@
              pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
         COMPLETE_WITH_CONST("RENAME TO");

-    /* ALTER USER <name> */
+    /* ALTER USER,ROLE <name> */
     else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
-             pg_strcasecmp(prev2_wd, "USER") == 0)
+             (pg_strcasecmp(prev2_wd, "USER") == 0 ||
+                pg_strcasecmp(prev2_wd, "ROLE") == 0))
     {
         static const char *const list_ALTERUSER[] =
         {"ENCRYPTED", "UNENCRYPTED", "CREATEDB", "NOCREATEDB", "CREATEUSER",
-         "NOCREATEUSER", "VALID UNTIL", "RENAME TO", "SET", "RESET", NULL};
+         "NOCREATEUSER","CREATEROLE","NOCREATEROLE","INHERIT","NOINHERIT",
+         "LOGIN","NOLOGIN","CONNECTION LIMIT", "VALID UNTIL", "RENAME TO",
+         "SUPERUSER","NOSUPERUSER", "SET", "RESET", NULL};

         COMPLETE_WITH_LIST(list_ALTERUSER);
     }

+    /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
+    else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
+            (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
+            (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
+    {
+                COMPLETE_WITH_CONST("PASSWORD");
+    }
     /* ALTER DOMAIN <name> */
     else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
              pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
@@ -761,7 +787,7 @@
              pg_strcasecmp(prev_wd, "SET") == 0)
     {
         static const char *const list_ALTERDOMAIN3[] =
-        {"DEFAULT", "NOT NULL", NULL};
+        {"DEFAULT", "NOT NULL", "SCHEMA", NULL};

         COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
     }
@@ -769,20 +795,21 @@
     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};
+            static const char *const list_ALTERSEQUENCE[] =
+            {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
+             "SET SCHEMA", NULL};

-            COMPLETE_WITH_LIST(list_ALTERSCHEMA);
+            COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
     }
     /* 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[] =
+            static const char *const list_ALTERSEQUENCE2[] =
             {"MINVALUE", "MAXVALUE", "CYCLE", NULL};

-            COMPLETE_WITH_LIST(list_ALTERSCHEMA2);
+            COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
     }
     /* ALTER TRIGGER <name>, add ON */
     else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
@@ -871,12 +898,12 @@
         completion_info_charp = prev3_wd;
         COMPLETE_WITH_QUERY(Query_for_index_of_table);
     }
-    /* If we have TABLE <sth> SET, provide WITHOUT or TABLESPACE */
+    /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
     else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
              pg_strcasecmp(prev_wd, "SET") == 0)
     {
         static const char *const list_TABLESET[] =
-        {"WITHOUT", "TABLESPACE", NULL};
+        {"WITHOUT", "TABLESPACE","SCHEMA", NULL};

         COMPLETE_WITH_LIST(list_TABLESET);
     }
@@ -904,10 +931,14 @@

         COMPLETE_WITH_LIST(list_ALTERTSPC);
     }
-    /* complete ALTER TYPE <foo> with OWNER TO */
+    /* complete ALTER TYPE <foo> with OWNER TO, SET SCHEMA */
     else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
              pg_strcasecmp(prev2_wd, "TYPE") == 0)
-        COMPLETE_WITH_CONST("OWNER TO");
+    {
+        static const char *const list_ALTERTYPE[] =
+        {"OWNER TO", "SET SCHEMA", NULL};
+        COMPLETE_WITH_LIST(list_ALTERTYPE);
+    }
     /* complete ALTER GROUP <foo> */
     else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
              pg_strcasecmp(prev2_wd, "GROUP") == 0)
@@ -993,7 +1024,7 @@
         static const char *const list_COMMENT[] =
         {"CAST", "CONVERSION", "DATABASE", "INDEX", "LANGUAGE", "RULE", "SCHEMA",
             "SEQUENCE", "TABLE", "TYPE", "VIEW", "COLUMN", "AGGREGATE", "FUNCTION",
-        "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", NULL};
+        "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN","LARGE OBJECT", NULL};

         COMPLETE_WITH_LIST(list_COMMENT);
     }
@@ -1054,6 +1085,16 @@
             COMPLETE_WITH_LIST(list_CSV);
         }

+/* CREATE DATABASE */
+    else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
+             pg_strcasecmp(prev2_wd, "DATABASE") == 0)
+        {
+            static const char *const list_DATABASE[] =
+                        {"OWNER", "TEMPLATE", "ENCODING", "TABLESPACE", "CONNECTION LIMIT", NULL};
+
+                        COMPLETE_WITH_LIST(list_DATABASE);
+                }
+
 /* CREATE INDEX */
     /* First off we complete CREATE UNIQUE with "INDEX" */
     else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
@@ -1145,10 +1186,58 @@
     }

 /* CREATE TRIGGER */
-    /* is on the agenda . . . */
+    /* complete CREATE TRIGGER <name> with BEFORE,AFTER */
+    else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
+            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 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};
+        COMPLETE_WITH_LIST(list_CREATETRIGGER2);
+    }
+
+/* CREATE ROLE,USER,GROUP */
+    else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
+             (pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
+              pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
+    {
+        static const char *const list_CREATEROLE[] =
+                        {"ADMIN","CONNECTION LIMIT","CREATEDB","CREATEROLE","CREATEUSER",
+             "ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOINHERIT", "NOLOGIN", "NOCREATEDB",
+             "NOCREATEROLE", "NOCREATEUSER", "NOSUPERUSER", "ROLE", "SUPERUSER", "SYSID",
+             "UNENCRYPTED",NULL};
+                COMPLETE_WITH_LIST(list_CREATEROLE);
+    }
+    /* complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
+    else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
+            (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
+                          pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
+            (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
+    {
+                COMPLETE_WITH_CONST("PASSWORD");
+    }
+    /* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
+    else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
+            (pg_strcasecmp(prev3_wd, "ROLE") == 0 ||
+                          pg_strcasecmp(prev3_wd, "GROUP") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
+            pg_strcasecmp(prev_wd, "IN") == 0)
+    {
+        static const char *const list_CREATEROLE3[] =
+                        {"GROUP","ROLE",NULL};
+                COMPLETE_WITH_LIST(list_CREATEROLE3);
+    }

 /* CREATE VIEW */
-    /* Complete "CREATE VIEW <name>" with "AS" */
+    /* Complete CREATE VIEW <name> with AS */
     else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
              pg_strcasecmp(prev2_wd, "VIEW") == 0)
         COMPLETE_WITH_CONST("AS");
@@ -1295,7 +1384,7 @@
              pg_strcasecmp(prev_wd, "REVOKE") == 0)
     {
         static const char *const list_privileg[] =
-        {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
+        {"CREATE", "SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
         "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};

         COMPLETE_WITH_LIST(list_privileg);
@@ -1438,10 +1527,10 @@
     else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
         COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE
substring(pg_catalog.quote_ident(relname),1,%d)='%s'");

-/* OWNER TO  - complete with available users*/
+/* OWNER TO  - complete with available roles*/
     else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
              pg_strcasecmp(prev_wd, "TO") == 0)
-        COMPLETE_WITH_QUERY(Query_for_list_of_users);
+        COMPLETE_WITH_QUERY(Query_for_list_of_roles);

 /* ORDER BY */
     else if (pg_strcasecmp(prev3_wd, "FROM") == 0 &&
@@ -1573,6 +1662,21 @@

         COMPLETE_WITH_LIST(constraint_list);
     }
+    /* COMPLETE SET ROLE */
+    else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
+             pg_strcasecmp(prev_wd, "ROLE") == 0)
+    {
+        static const char *const my_list[] =
+        {"NONE", NULL};
+
+        COMPLETE_WITH_LIST(my_list);
+    }
+    /* COMPLETE SET SCHEMA */
+    else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
+                         pg_strcasecmp(prev_wd, "SCHEMA") == 0)
+    {
+        COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
+    }
     /* Complete SET SESSION with AUTHORIZATION or CHARACTERISTICS... */
     else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
              pg_strcasecmp(prev_wd, "SESSION") == 0)
@@ -1586,7 +1690,7 @@
     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_users);
+        COMPLETE_WITH_QUERY(Query_for_list_of_roles);
     /* Complete SET <var> with "TO" */
     else if (pg_strcasecmp(prev2_wd, "SET") == 0 &&
              pg_strcasecmp(prev4_wd, "UPDATE") != 0 &&
@@ -1698,7 +1802,7 @@
               pg_strcasecmp(prev2_wd, "ANALYZE") == 0))
         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);

-/* ANALZYE */
+/* ANALYZE */
     /* If the previous word is ANALYZE, produce list of tables */
     else if (pg_strcasecmp(prev_wd, "ANALYZE") == 0)
         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
@@ -1745,7 +1849,7 @@
     else if (strcmp(prev_wd, "\\dT") == 0 || strcmp(prev_wd, "\\dT+") == 0)
         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
     else if (strcmp(prev_wd, "\\du") == 0)
-        COMPLETE_WITH_QUERY(Query_for_list_of_users);
+        COMPLETE_WITH_QUERY(Query_for_list_of_roles);
     else if (strcmp(prev_wd, "\\dv") == 0 || strcmp(prev_wd, "\\dv+") == 0)
         COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
     else if (strcmp(prev_wd, "\\encoding") == 0)

Re: psql tab-complete and backslash patch

From
Tom Lane
Date:
Stefan Kaltenbrunner <stefan@kaltenbrunner.cc> writes:
> attached is a patch against psql that makes psql's tabcomplete code
> ROLES aware, adds SET SCHEMA and basic CREATE DATABASE/TRIGGER support
> as well as some other minor things.

Applied with some changes.  I didn't see the point of making \du
backwards compatible to older versions; we've never worried about that
before in psql's \d commands.  Also I thought the "Attributes" approach
of the old \du code was well past its usefulness, so I just changed it
to separate columns.

            regards, tom lane

Re: psql tab-complete and backslash patch

From
Stefan Kaltenbrunner
Date:
Tom Lane wrote:
> Stefan Kaltenbrunner <stefan@kaltenbrunner.cc> writes:
>
>>attached is a patch against psql that makes psql's tabcomplete code
>>ROLES aware, adds SET SCHEMA and basic CREATE DATABASE/TRIGGER support
>>as well as some other minor things.
>
>
> Applied with some changes.  I didn't see the point of making \du
> backwards compatible to older versions; we've never worried about that
> before in psql's \d commands.  Also I thought the "Attributes" approach
> of the old \du code was well past its usefulness, so I just changed it
> to separate columns.


thanks for applying!
While I know that we have never guaranteed backwards-compatibility for
psql's backslash commands (or for tab-complete either) I modeled this
after the \db-tablespace code. Removing it altogether is fine too :-)
Any particular reason why you dropped the SET SCHEMA <tab> part of my
patch ?


Stefan

Re: psql tab-complete and backslash patch

From
Tom Lane
Date:
Stefan Kaltenbrunner <stefan@kaltenbrunner.cc> writes:
> Any particular reason why you dropped the SET SCHEMA <tab> part of my
> patch ?

Because we have no such command.

            regards, tom lane