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 FROM pg_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 */ + 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 */ + /* ALTER CONVERSION,SCHEMA */ 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 */ + /* ALTER USER,ROLE */ 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 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 */ 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 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 , 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 SET, provide WITHOUT or TABLESPACE */ + /* If we have TABLE 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 with OWNER TO */ + /* complete ALTER TYPE 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 */ 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 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 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 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 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 " with "AS" */ + /* Complete CREATE VIEW 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 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)