[PATCH] ALTER DEFAULT PRIVILEGES with GRANT/REVOKE ON SCHEMAS
Hi all,
I noticed that we have no option to set default privileges for newly
created schemas, other than calling GRANT explicitly. At work I use ALTER
DEFAULT PRIVILEGE (ADP) command extensively, as the developers are
permitted to manage DDL on the databases, and all work fine except for when
a new schema is created. So,I'd like to propose this very simple patch
(attached) that adds the capability of using SCHEMAS, adding the following
syntax to ADP:
ALTER DEFAULT PRIVILEGES
[ FOR { ROLE | USER } target_role [, ...] ]
abbreviated_grant_or_revoke
where abbreviated_grant_or_revoke is one of:
GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] }
ON SCHEMAS
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | CREATE | ALL [ PRIVILEGES ] }
ON SCHEMAS
FROM { [ GROUP ] role_name | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
The patch itself is really straight forward (I'm new to sending patches, so
I've chosen a simple one), and there is only one thing that concerns me (as
in, if I did it right/good). The difference in syntax for SCHEMAS and the
other objects is that IN SCHEMA option makes no sense here (as we don't
have nested schemas), and to solve that I simple added the error "cannot
use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS".
Does that look good to you?
Also, should I add translations for that error message in other languages
(I can do that without help of tools for pt_BR) or is that a latter process
in the releasing?
Other than that, I added a few regression tests (similar to others used for
ADP), and patched the documentation (my English is not that good, so I'm
open to suggestions). Anything else I forgot?
While at this, I'd like to ask if you are interested in have all the other
types we have in GRANT/REVOKE for ADP (I myself see few use for that at
work, but the symmetry on those commands seems like a good idea). If you
agree, I can take some time to do the others (looks very simple to do). I
just wonder if that should be done as one patch for each, or just a single
patch for all of them (perhaps send the sequence of patches in order, as
certainly one will conflict with the other if done apart).
Best regards,
--
Matheus de Oliveira
Attachments:
postgresql-defacl-schema-v1.patchtext/x-patch; charset=US-ASCII; name=postgresql-defacl-schema-v1.patchDownload
diff --git a/doc/src/sgml/ref/alter_default_privileges.sgml b/doc/src/sgml/ref/alter_default_privileges.sgml
index 04064d3..7745792 100644
*** a/doc/src/sgml/ref/alter_default_privileges.sgml
--- b/doc/src/sgml/ref/alter_default_privileges.sgml
***************
*** 46,51 **** GRANT { USAGE | ALL [ PRIVILEGES ] }
--- 46,55 ----
ON TYPES
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+ GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] }
+ ON SCHEMAS
+ TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[, ...] | ALL [ PRIVILEGES ] }
***************
*** 71,76 **** REVOKE [ GRANT OPTION FOR ]
--- 75,86 ----
ON TYPES
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+
+ REVOKE [ GRANT OPTION FOR ]
+ { USAGE | CREATE | ALL [ PRIVILEGES ] }
+ ON SCHEMAS
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
***************
*** 125,130 **** REVOKE [ GRANT OPTION FOR ]
--- 135,142 ----
are altered for objects later created in that schema.
If <literal>IN SCHEMA</> is omitted, the global default privileges
are altered.
+ <literal>IN SCHEMA</> is not allowed when using <literal>ON SCHEMAS</>
+ as schemas can't be nested.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/catalog/aclchk.c b/src/backeindex c0df671..e1256f1 100644
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
***************
*** 948,953 **** ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s
--- 948,957 ----
all_privileges = ACL_ALL_RIGHTS_TYPE;
errormsg = gettext_noop("invalid privilege type %s for type");
break;
+ case ACL_OBJECT_NAMESPACE:
+ all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
+ errormsg = gettext_noop("invalid privilege type %s for schema");
+ break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) action->objtype);
***************
*** 1135,1140 **** SetDefaultACL(InternalDefaultACL *iacls)
--- 1139,1154 ----
this_privileges = ACL_ALL_RIGHTS_TYPE;
break;
+ case ACL_OBJECT_NAMESPACE:
+ if (OidIsValid(iacls->nspid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_GRANT_OPERATION),
+ errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
+ objtype = DEFACLOBJ_NAMESPACE;
+ if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
+ this_privileges = ACL_ALL_RIGHTS_NAMESPACE;
+ break;
+
default:
elog(ERROR, "unrecognized objtype: %d",
(int) iacls->objtype);
***************
*** 1361,1366 **** RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
--- 1375,1383 ----
case DEFACLOBJ_TYPE:
iacls.objtype = ACL_OBJECT_TYPE;
break;
+ case DEFACLOBJ_NAMESPACE:
+ iacls.objtype = ACL_OBJECT_NAMESPACE;
+ break;
default:
/* Shouldn't get here */
elog(ERROR, "unexpected default ACL type: %d",
***************
*** 5189,5194 **** get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
--- 5206,5215 ----
defaclobjtype = DEFACLOBJ_TYPE;
break;
+ case ACL_OBJECT_NAMESPACE:
+ defaclobjtype = DEFACLOBJ_NAMESPACE;
+ break;
+
default:
return NULL;
}
diff --git a/src/backend/catalog/obindex d531d17..23d6684 100644
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
***************
*** 1788,1798 **** get_object_address_defacl(List *objname, List *objargs, bool missing_ok)
case DEFACLOBJ_TYPE:
objtype_str = "types";
break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized default ACL object type %c", objtype),
! errhint("Valid object types are \"r\", \"S\", \"f\", and \"T\".")));
}
/*
--- 1788,1801 ----
case DEFACLOBJ_TYPE:
objtype_str = "types";
break;
+ case DEFACLOBJ_NAMESPACE:
+ objtype_str = "schemas";
+ break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized default ACL object type %c", objtype),
! errhint("Valid object types are \"r\", \"S\", \"f\", \"T\" and \"s\".")));
}
/*
***************
*** 3093,3098 **** getObjectDescription(const ObjectAddress *object)
--- 3096,3106 ----
_("default privileges on new types belonging to role %s"),
GetUserNameFromId(defacl->defaclrole, false));
break;
+ case DEFACLOBJ_NAMESPACE:
+ appendStringInfo(&buffer,
+ _("default privileges on new schemas belonging to role %s"),
+ GetUserNameFromId(defacl->defaclrole, false));
+ break;
default:
/* shouldn't get here */
appendStringInfo(&buffer,
***************
*** 4547,4552 **** getObjectIdentityParts(const ObjectAddress *object,
--- 4555,4564 ----
appendStringInfoString(&buffer,
" on types");
break;
+ case DEFACLOBJ_NAMESPACE:
+ appendStringInfoString(&buffer,
+ " on schemas");
+ break;
}
if (objname)
diff --git a/src/backend/catalog/pg_namespindex e5eed79..34e957f 100644
*** a/src/backend/catalog/pg_namespace.c
--- b/src/backend/catalog/pg_namespace.c
***************
*** 31,40 ****
* Create a namespace (schema) with the given name and owner OID.
*
* If isTemp is true, this schema is a per-backend schema for holding
! * temporary tables. Currently, the only effect of that is to prevent it
! * from being linked as a member of any active extension. (If someone
! * does CREATE TEMP TABLE in an extension script, we don't want the temp
! * schema to become part of the extension.)
* ---------------
*/
Oid
--- 31,41 ----
* Create a namespace (schema) with the given name and owner OID.
*
* If isTemp is true, this schema is a per-backend schema for holding
! * temporary tables. Currently, it is used to prevent it from being
! * linked as a member of any active extension. (If someone * does CREATE
! * TEMP TABLE in an extension script, we don't want the temp schema to
! * become part of the extension). And to avoid checking for default ACL
! * for temp namespace (as it is not necessary).
* ---------------
*/
Oid
***************
*** 49,54 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
--- 50,56 ----
TupleDesc tupDesc;
ObjectAddress myself;
int i;
+ Acl *nspacl;
/* sanity checks */
if (!nspName)
***************
*** 60,65 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
--- 62,73 ----
(errcode(ERRCODE_DUPLICATE_SCHEMA),
errmsg("schema \"%s\" already exists", nspName)));
+ if (!isTemp)
+ nspacl = get_user_default_acl(ACL_OBJECT_NAMESPACE, ownerId,
+ InvalidOid);
+ else
+ nspacl = NULL;
+
/* initialize nulls and values */
for (i = 0; i < Natts_pg_namespace; i++)
{
***************
*** 69,75 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
! nulls[Anum_pg_namespace_nspacl - 1] = true;
nspdesc = heap_open(NamespaceRelationId, RowExclusiveLock);
tupDesc = nspdesc->rd_att;
--- 77,86 ----
namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
! if (nspacl != NULL)
! values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl);
! else
! nulls[Anum_pg_namespace_nspacl - 1] = true;
nspdesc = heap_open(NamespaceRelationId, RowExclusiveLock);
tupDesc = nspdesc->rd_att;
diff --git a/src/backend/parser/gram.y b/index 0ec1cd3..b845733 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 632,638 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
! SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P START
STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING
--- 632,638 ----
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
! SAVEPOINT SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P START
STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING
***************
*** 6689,6694 **** defacl_privilege_target:
--- 6689,6695 ----
| FUNCTIONS { $$ = ACL_OBJECT_FUNCTION; }
| SEQUENCES { $$ = ACL_OBJECT_SEQUENCE; }
| TYPES_P { $$ = ACL_OBJECT_TYPE; }
+ | SCHEMAS { $$ = ACL_OBJECT_NAMESPACE; }
;
***************
*** 13923,13928 **** unreserved_keyword:
--- 13924,13930 ----
| RULE
| SAVEPOINT
| SCHEMA
+ | SCHEMAS
| SCROLL
| SEARCH
| SECOND_P
diff --git a/src/bin/pg_dump/dumindex 0d51668..ff486ff 100644
*** a/src/bin/pg_dump/dumputils.c
--- b/src/bin/pg_dump/dumputils.c
***************
*** 511,517 **** do { \
CONVERT_PRIV('X', "EXECUTE");
else if (strcmp(type, "LANGUAGE") == 0)
CONVERT_PRIV('U', "USAGE");
! else if (strcmp(type, "SCHEMA") == 0)
{
CONVERT_PRIV('C', "CREATE");
CONVERT_PRIV('U', "USAGE");
--- 511,519 ----
CONVERT_PRIV('X', "EXECUTE");
else if (strcmp(type, "LANGUAGE") == 0)
CONVERT_PRIV('U', "USAGE");
! else if (strcmp(type, "SCHEMA") == 0 ||
! strcmp(type, "SCHEMAS") == 0
! )
{
CONVERT_PRIV('C', "CREATE");
CONVERT_PRIV('U', "USAGE");
diff --git a/src/bin/pg_dump/pg_duindex 9f59f53..8f5d9c5 100644
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 13373,13378 **** dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
--- 13373,13381 ----
case DEFACLOBJ_TYPE:
type = "TYPES";
break;
+ case DEFACLOBJ_NAMESPACE:
+ type = "SCHEMAS";
+ break;
default:
/* shouldn't get here */
exit_horribly(NULL,
diff --git a/src/bin/psql/descriindex 1632104..15dd5f9 100644
*** a/src/bin/psql/describe.c
--- b/src/bin/psql/describe.c
***************
*** 984,990 **** listDefaultACLs(const char *pattern)
printfPQExpBuffer(&buf,
"SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
" n.nspname AS \"%s\",\n"
! " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
" ",
gettext_noop("Owner"),
gettext_noop("Schema"),
--- 984,990 ----
printfPQExpBuffer(&buf,
"SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
" n.nspname AS \"%s\",\n"
! " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
" ",
gettext_noop("Owner"),
gettext_noop("Schema"),
***************
*** 996,1001 **** listDefaultACLs(const char *pattern)
--- 996,1003 ----
gettext_noop("function"),
DEFACLOBJ_TYPE,
gettext_noop("type"),
+ DEFACLOBJ_NAMESPACE,
+ gettext_noop("schema"),
gettext_noop("Type"));
printACLColumn(&buf, "d.defaclacl");
diff --git a/src/include/catalindex 06aaaba..7b7d7b8 100644
*** a/src/include/catalog/pg_default_acl.h
--- b/src/include/catalog/pg_default_acl.h
***************
*** 70,74 **** typedef FormData_pg_default_acl *Form_pg_default_acl;
--- 70,75 ----
#define DEFACLOBJ_SEQUENCE 'S' /* sequence */
#define DEFACLOBJ_FUNCTION 'f' /* function */
#define DEFACLOBJ_TYPE 'T' /* type */
+ #define DEFACLOBJ_NAMESPACE 'n' /* namespace */
#endif /* PG_DEFAULT_ACL_H */
diff --git a/src/include/parser/kwlist.h b/index 77d873b..5dc0244 100644
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 339,344 **** PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
--- 339,345 ----
PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
+ PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
diff --git a/src/test/regress/expeindex f66b443..449b0e3 100644
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
***************
*** 1337,1342 **** SELECT has_table_privilege('regress_user1', 'testns.acltest1', 'INSERT'); -- no
--- 1337,1400 ----
(1 row)
ALTER DEFAULT PRIVILEGES FOR ROLE regress_user1 REVOKE EXECUTE ON FUNCTIONS FROM public;
+ ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_user2; -- error
+ ERROR: cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS
+ ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_user2;
+ CREATE SCHEMA testns2;
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'USAGE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES REVOKE USAGE ON SCHEMAS FROM regress_user2;
+ CREATE SCHEMA testns3;
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'USAGE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_user2;
+ CREATE SCHEMA testns4;
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'USAGE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'CREATE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_user2;
+ CREATE SCHEMA testns5;
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'USAGE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
SET ROLE regress_user1;
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
SELECT has_function_privilege('regress_user2', 'testns.foo()', 'EXECUTE'); -- no
***************
*** 1384,1389 **** SELECT count(*)
--- 1442,1451 ----
DROP SCHEMA testns CASCADE;
NOTICE: drop cascades to table testns.acltest1
+ DROP SCHEMA testns2 CASCADE;
+ DROP SCHEMA testns3 CASCADE;
+ DROP SCHEMA testns4 CASCADE;
+ DROP SCHEMA testns5 CASCADE;
SELECT d.* -- check that entries went away
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
WHERE nspname IS NULL AND defaclnamespace != 0;
diff --git a/src/test/regress/sql/privileges.sqindex 00dc7bd..c2c1629 100644
*** a/src/test/regress/sql/privileges.sql
--- b/src/test/regress/sql/privileges.sql
***************
*** 807,812 **** SELECT has_table_privilege('regress_user1', 'testns.acltest1', 'INSERT'); -- no
--- 807,842 ----
ALTER DEFAULT PRIVILEGES FOR ROLE regress_user1 REVOKE EXECUTE ON FUNCTIONS FROM public;
+ ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_user2; -- error
+
+ ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_user2;
+
+ CREATE SCHEMA testns2;
+
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'USAGE'); -- yes
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'CREATE'); -- no
+
+ ALTER DEFAULT PRIVILEGES REVOKE USAGE ON SCHEMAS FROM regress_user2;
+
+ CREATE SCHEMA testns3;
+
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'USAGE'); -- no
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'CREATE'); -- no
+
+ ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_user2;
+
+ CREATE SCHEMA testns4;
+
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'USAGE'); -- yes
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'CREATE'); -- yes
+
+ ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_user2;
+
+ CREATE SCHEMA testns5;
+
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'USAGE'); -- no
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'CREATE'); -- no
+
SET ROLE regress_user1;
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
***************
*** 844,849 **** SELECT count(*)
--- 874,883 ----
WHERE nspname = 'testns';
DROP SCHEMA testns CASCADE;
+ DROP SCHEMA testns2 CASCADE;
+ DROP SCHEMA testns3 CASCADE;
+ DROP SCHEMA testns4 CASCADE;
+ DROP SCHEMA testns5 CASCADE;
SELECT d.* -- check that entries went away
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
On Tue, Nov 22, 2016 at 08:59:09AM -0200, Matheus de Oliveira wrote:
Hi all,
I noticed that we have no option to set default privileges for newly
created schemas, other than calling GRANT explicitly. At work I use ALTER
DEFAULT PRIVILEGE (ADP) command extensively, as the developers are
permitted to manage DDL on the databases, and all work fine except for when
a new schema is created. So,I'd like to propose this very simple patch
(attached) that adds the capability of using SCHEMAS, adding the following
syntax to ADP:ALTER DEFAULT PRIVILEGES
[ FOR { ROLE | USER } target_role [, ...] ]
abbreviated_grant_or_revokewhere abbreviated_grant_or_revoke is one of:
GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] }
ON SCHEMAS
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]REVOKE [ GRANT OPTION FOR ]
{ USAGE | CREATE | ALL [ PRIVILEGES ] }
ON SCHEMAS
FROM { [ GROUP ] role_name | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
I'd love to have this available.
Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: david(dot)fetter(at)gmail(dot)com
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Just sending the same patch but rebase with current master (it was broken
for gram.y after new commits).
Best regards,
Attachments:
postgresql-defacl-schema-v1.patchtext/x-patch; charset=US-ASCII; name=postgresql-defacl-schema-v1.patchDownload
diff --git a/doc/src/sgml/ref/alter_default_privileges.sgml b/doc/src/sgml/ref/alter_default_privileges.sgml
index 04064d3..7745792 100644
*** a/doc/src/sgml/ref/alter_default_privileges.sgml
--- b/doc/src/sgml/ref/alter_default_privileges.sgml
***************
*** 46,51 **** GRANT { USAGE | ALL [ PRIVILEGES ] }
--- 46,55 ----
ON TYPES
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+ GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] }
+ ON SCHEMAS
+ TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[, ...] | ALL [ PRIVILEGES ] }
***************
*** 71,76 **** REVOKE [ GRANT OPTION FOR ]
--- 75,86 ----
ON TYPES
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+
+ REVOKE [ GRANT OPTION FOR ]
+ { USAGE | CREATE | ALL [ PRIVILEGES ] }
+ ON SCHEMAS
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
***************
*** 125,130 **** REVOKE [ GRANT OPTION FOR ]
--- 135,142 ----
are altered for objects later created in that schema.
If <literal>IN SCHEMA</> is omitted, the global default privileges
are altered.
+ <literal>IN SCHEMA</> is not allowed when using <literal>ON SCHEMAS</>
+ as schemas can't be nested.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/catalog/aclchk.c b/src/backeindex c0df671..e1256f1 100644
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
***************
*** 948,953 **** ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s
--- 948,957 ----
all_privileges = ACL_ALL_RIGHTS_TYPE;
errormsg = gettext_noop("invalid privilege type %s for type");
break;
+ case ACL_OBJECT_NAMESPACE:
+ all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
+ errormsg = gettext_noop("invalid privilege type %s for schema");
+ break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) action->objtype);
***************
*** 1135,1140 **** SetDefaultACL(InternalDefaultACL *iacls)
--- 1139,1154 ----
this_privileges = ACL_ALL_RIGHTS_TYPE;
break;
+ case ACL_OBJECT_NAMESPACE:
+ if (OidIsValid(iacls->nspid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_GRANT_OPERATION),
+ errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
+ objtype = DEFACLOBJ_NAMESPACE;
+ if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
+ this_privileges = ACL_ALL_RIGHTS_NAMESPACE;
+ break;
+
default:
elog(ERROR, "unrecognized objtype: %d",
(int) iacls->objtype);
***************
*** 1361,1366 **** RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
--- 1375,1383 ----
case DEFACLOBJ_TYPE:
iacls.objtype = ACL_OBJECT_TYPE;
break;
+ case DEFACLOBJ_NAMESPACE:
+ iacls.objtype = ACL_OBJECT_NAMESPACE;
+ break;
default:
/* Shouldn't get here */
elog(ERROR, "unexpected default ACL type: %d",
***************
*** 5189,5194 **** get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
--- 5206,5215 ----
defaclobjtype = DEFACLOBJ_TYPE;
break;
+ case ACL_OBJECT_NAMESPACE:
+ defaclobjtype = DEFACLOBJ_NAMESPACE;
+ break;
+
default:
return NULL;
}
diff --git a/src/backend/catalog/obindex d531d17..23d6684 100644
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
***************
*** 1788,1798 **** get_object_address_defacl(List *objname, List *objargs, bool missing_ok)
case DEFACLOBJ_TYPE:
objtype_str = "types";
break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized default ACL object type %c", objtype),
! errhint("Valid object types are \"r\", \"S\", \"f\", and \"T\".")));
}
/*
--- 1788,1801 ----
case DEFACLOBJ_TYPE:
objtype_str = "types";
break;
+ case DEFACLOBJ_NAMESPACE:
+ objtype_str = "schemas";
+ break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized default ACL object type %c", objtype),
! errhint("Valid object types are \"r\", \"S\", \"f\", \"T\" and \"s\".")));
}
/*
***************
*** 3093,3098 **** getObjectDescription(const ObjectAddress *object)
--- 3096,3106 ----
_("default privileges on new types belonging to role %s"),
GetUserNameFromId(defacl->defaclrole, false));
break;
+ case DEFACLOBJ_NAMESPACE:
+ appendStringInfo(&buffer,
+ _("default privileges on new schemas belonging to role %s"),
+ GetUserNameFromId(defacl->defaclrole, false));
+ break;
default:
/* shouldn't get here */
appendStringInfo(&buffer,
***************
*** 4547,4552 **** getObjectIdentityParts(const ObjectAddress *object,
--- 4555,4564 ----
appendStringInfoString(&buffer,
" on types");
break;
+ case DEFACLOBJ_NAMESPACE:
+ appendStringInfoString(&buffer,
+ " on schemas");
+ break;
}
if (objname)
diff --git a/src/backend/catalog/pg_namespindex e5eed79..34e957f 100644
*** a/src/backend/catalog/pg_namespace.c
--- b/src/backend/catalog/pg_namespace.c
***************
*** 31,40 ****
* Create a namespace (schema) with the given name and owner OID.
*
* If isTemp is true, this schema is a per-backend schema for holding
! * temporary tables. Currently, the only effect of that is to prevent it
! * from being linked as a member of any active extension. (If someone
! * does CREATE TEMP TABLE in an extension script, we don't want the temp
! * schema to become part of the extension.)
* ---------------
*/
Oid
--- 31,41 ----
* Create a namespace (schema) with the given name and owner OID.
*
* If isTemp is true, this schema is a per-backend schema for holding
! * temporary tables. Currently, it is used to prevent it from being
! * linked as a member of any active extension. (If someone * does CREATE
! * TEMP TABLE in an extension script, we don't want the temp schema to
! * become part of the extension). And to avoid checking for default ACL
! * for temp namespace (as it is not necessary).
* ---------------
*/
Oid
***************
*** 49,54 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
--- 50,56 ----
TupleDesc tupDesc;
ObjectAddress myself;
int i;
+ Acl *nspacl;
/* sanity checks */
if (!nspName)
***************
*** 60,65 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
--- 62,73 ----
(errcode(ERRCODE_DUPLICATE_SCHEMA),
errmsg("schema \"%s\" already exists", nspName)));
+ if (!isTemp)
+ nspacl = get_user_default_acl(ACL_OBJECT_NAMESPACE, ownerId,
+ InvalidOid);
+ else
+ nspacl = NULL;
+
/* initialize nulls and values */
for (i = 0; i < Natts_pg_namespace; i++)
{
***************
*** 69,75 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
! nulls[Anum_pg_namespace_nspacl - 1] = true;
nspdesc = heap_open(NamespaceRelationId, RowExclusiveLock);
tupDesc = nspdesc->rd_att;
--- 77,86 ----
namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
! if (nspacl != NULL)
! values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl);
! else
! nulls[Anum_pg_namespace_nspacl - 1] = true;
nspdesc = heap_open(NamespaceRelationId, RowExclusiveLock);
tupDesc = nspdesc->rd_att;
diff --git a/src/backend/parser/gram.y b/index 367bc2e..64b3d08 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 631,637 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
! SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P START
STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING
--- 631,637 ----
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
! SAVEPOINT SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P START
STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING
***************
*** 6688,6693 **** defacl_privilege_target:
--- 6688,6694 ----
| FUNCTIONS { $$ = ACL_OBJECT_FUNCTION; }
| SEQUENCES { $$ = ACL_OBJECT_SEQUENCE; }
| TYPES_P { $$ = ACL_OBJECT_TYPE; }
+ | SCHEMAS { $$ = ACL_OBJECT_NAMESPACE; }
;
***************
*** 13860,13865 **** unreserved_keyword:
--- 13861,13867 ----
| RULE
| SAVEPOINT
| SCHEMA
+ | SCHEMAS
| SCROLL
| SEARCH
| SECOND_P
diff --git a/src/bin/pg_dump/dumindex 0d51668..ff486ff 100644
*** a/src/bin/pg_dump/dumputils.c
--- b/src/bin/pg_dump/dumputils.c
***************
*** 511,517 **** do { \
CONVERT_PRIV('X', "EXECUTE");
else if (strcmp(type, "LANGUAGE") == 0)
CONVERT_PRIV('U', "USAGE");
! else if (strcmp(type, "SCHEMA") == 0)
{
CONVERT_PRIV('C', "CREATE");
CONVERT_PRIV('U', "USAGE");
--- 511,519 ----
CONVERT_PRIV('X', "EXECUTE");
else if (strcmp(type, "LANGUAGE") == 0)
CONVERT_PRIV('U', "USAGE");
! else if (strcmp(type, "SCHEMA") == 0 ||
! strcmp(type, "SCHEMAS") == 0
! )
{
CONVERT_PRIV('C', "CREATE");
CONVERT_PRIV('U', "USAGE");
diff --git a/src/bin/pg_dump/pg_duindex 9f59f53..8f5d9c5 100644
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 13373,13378 **** dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
--- 13373,13381 ----
case DEFACLOBJ_TYPE:
type = "TYPES";
break;
+ case DEFACLOBJ_NAMESPACE:
+ type = "SCHEMAS";
+ break;
default:
/* shouldn't get here */
exit_horribly(NULL,
diff --git a/src/bin/psql/descriindex 1632104..15dd5f9 100644
*** a/src/bin/psql/describe.c
--- b/src/bin/psql/describe.c
***************
*** 984,990 **** listDefaultACLs(const char *pattern)
printfPQExpBuffer(&buf,
"SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
" n.nspname AS \"%s\",\n"
! " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
" ",
gettext_noop("Owner"),
gettext_noop("Schema"),
--- 984,990 ----
printfPQExpBuffer(&buf,
"SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
" n.nspname AS \"%s\",\n"
! " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
" ",
gettext_noop("Owner"),
gettext_noop("Schema"),
***************
*** 996,1001 **** listDefaultACLs(const char *pattern)
--- 996,1003 ----
gettext_noop("function"),
DEFACLOBJ_TYPE,
gettext_noop("type"),
+ DEFACLOBJ_NAMESPACE,
+ gettext_noop("schema"),
gettext_noop("Type"));
printACLColumn(&buf, "d.defaclacl");
diff --git a/src/include/catalindex 06aaaba..7b7d7b8 100644
*** a/src/include/catalog/pg_default_acl.h
--- b/src/include/catalog/pg_default_acl.h
***************
*** 70,74 **** typedef FormData_pg_default_acl *Form_pg_default_acl;
--- 70,75 ----
#define DEFACLOBJ_SEQUENCE 'S' /* sequence */
#define DEFACLOBJ_FUNCTION 'f' /* function */
#define DEFACLOBJ_TYPE 'T' /* type */
+ #define DEFACLOBJ_NAMESPACE 'n' /* namespace */
#endif /* PG_DEFAULT_ACL_H */
diff --git a/src/include/parser/kwlist.h b/index 77d873b..5dc0244 100644
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 339,344 **** PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
--- 339,345 ----
PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
+ PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
diff --git a/src/test/regress/expeindex f66b443..449b0e3 100644
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
***************
*** 1337,1342 **** SELECT has_table_privilege('regress_user1', 'testns.acltest1', 'INSERT'); -- no
--- 1337,1400 ----
(1 row)
ALTER DEFAULT PRIVILEGES FOR ROLE regress_user1 REVOKE EXECUTE ON FUNCTIONS FROM public;
+ ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_user2; -- error
+ ERROR: cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS
+ ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_user2;
+ CREATE SCHEMA testns2;
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'USAGE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES REVOKE USAGE ON SCHEMAS FROM regress_user2;
+ CREATE SCHEMA testns3;
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'USAGE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_user2;
+ CREATE SCHEMA testns4;
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'USAGE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'CREATE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_user2;
+ CREATE SCHEMA testns5;
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'USAGE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
SET ROLE regress_user1;
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
SELECT has_function_privilege('regress_user2', 'testns.foo()', 'EXECUTE'); -- no
***************
*** 1384,1389 **** SELECT count(*)
--- 1442,1451 ----
DROP SCHEMA testns CASCADE;
NOTICE: drop cascades to table testns.acltest1
+ DROP SCHEMA testns2 CASCADE;
+ DROP SCHEMA testns3 CASCADE;
+ DROP SCHEMA testns4 CASCADE;
+ DROP SCHEMA testns5 CASCADE;
SELECT d.* -- check that entries went away
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
WHERE nspname IS NULL AND defaclnamespace != 0;
diff --git a/src/test/regress/sql/privileges.sqindex 00dc7bd..c2c1629 100644
*** a/src/test/regress/sql/privileges.sql
--- b/src/test/regress/sql/privileges.sql
***************
*** 807,812 **** SELECT has_table_privilege('regress_user1', 'testns.acltest1', 'INSERT'); -- no
--- 807,842 ----
ALTER DEFAULT PRIVILEGES FOR ROLE regress_user1 REVOKE EXECUTE ON FUNCTIONS FROM public;
+ ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_user2; -- error
+
+ ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_user2;
+
+ CREATE SCHEMA testns2;
+
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'USAGE'); -- yes
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'CREATE'); -- no
+
+ ALTER DEFAULT PRIVILEGES REVOKE USAGE ON SCHEMAS FROM regress_user2;
+
+ CREATE SCHEMA testns3;
+
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'USAGE'); -- no
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'CREATE'); -- no
+
+ ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_user2;
+
+ CREATE SCHEMA testns4;
+
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'USAGE'); -- yes
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'CREATE'); -- yes
+
+ ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_user2;
+
+ CREATE SCHEMA testns5;
+
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'USAGE'); -- no
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'CREATE'); -- no
+
SET ROLE regress_user1;
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
***************
*** 844,849 **** SELECT count(*)
--- 874,883 ----
WHERE nspname = 'testns';
DROP SCHEMA testns CASCADE;
+ DROP SCHEMA testns2 CASCADE;
+ DROP SCHEMA testns3 CASCADE;
+ DROP SCHEMA testns4 CASCADE;
+ DROP SCHEMA testns5 CASCADE;
SELECT d.* -- check that entries went away
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
Hi,
The patch itself is really straight forward (I'm new to sending patches, so
I've chosen a simple one), and there is only one thing that concerns me (as
in, if I did it right/good). The difference in syntax for SCHEMAS and the
other objects is that IN SCHEMA option makes no sense here (as we don't have
nested schemas), and to solve that I simple added the error "cannot use IN
SCHEMA clause when using GRANT/REVOKE ON SCHEMAS".Does that look good to you?
To me, It looks fine.
Also, should I add translations for that error message in other languages (I
can do that without help of tools for pt_BR) or is that a latter process in
the releasing?
I think you should add it but i am not sure when it is done.
Other than that, I added a few regression tests (similar to others used for
ADP), and patched the documentation (my English is not that good, so I'm
open to suggestions). Anything else I forgot?
You have forgot to change the description section of "ADP". In the
description section you need to mention that privileges for schemas
too can be altered along with other database objects. Other than that,
I feel the patch looks good and has no bug.
--
With Regards,
Ashutosh Sharma.
EnterpriseDB: http://www.enterprisedb.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Jan 9, 2017 at 10:58 AM, Ashutosh Sharma <ashu.coek88@gmail.com>
wrote:
Also, should I add translations for that error message in other
languages (I
can do that without help of tools for pt_BR) or is that a latter process
in
the releasing?
I think you should add it but i am not sure when it is done.
I'll ask one of the guys who work with pt_BR translations (I know him in
person).
Other than that, I added a few regression tests (similar to others used
for
ADP), and patched the documentation (my English is not that good, so I'm
open to suggestions). Anything else I forgot?You have forgot to change the description section of "ADP". In the
description section you need to mention that privileges for schemas
too can be altered along with other database objects.
Oh... Indeed an oversight, thanks for pointing that out.
Other than that,
I feel the patch looks good and has no bug.
Attached a rebased version and with the docs update pointed by Ashutosh
Sharma.
Best regards,
--
Matheus de Oliveira
Attachments:
postgresql-defacl-schema-v1.patchtext/x-patch; charset=US-ASCII; name=postgresql-defacl-schema-v1.patchDownload
diff --git a/doc/src/sgml/ref/alter_default_privileges.sgml b/doc/src/sgml/ref/alter_default_privileges.sgml
index 04064d3..e3363f8 100644
*** a/doc/src/sgml/ref/alter_default_privileges.sgml
--- b/doc/src/sgml/ref/alter_default_privileges.sgml
***************
*** 46,51 **** GRANT { USAGE | ALL [ PRIVILEGES ] }
--- 46,55 ----
ON TYPES
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+ GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] }
+ ON SCHEMAS
+ TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[, ...] | ALL [ PRIVILEGES ] }
***************
*** 71,76 **** REVOKE [ GRANT OPTION FOR ]
--- 75,86 ----
ON TYPES
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+
+ REVOKE [ GRANT OPTION FOR ]
+ { USAGE | CREATE | ALL [ PRIVILEGES ] }
+ ON SCHEMAS
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
***************
*** 81,88 **** REVOKE [ GRANT OPTION FOR ]
<command>ALTER DEFAULT PRIVILEGES</> allows you to set the privileges
that will be applied to objects created in the future. (It does not
affect privileges assigned to already-existing objects.) Currently,
! only the privileges for tables (including views and foreign tables),
! sequences, functions, and types (including domains) can be altered.
</para>
<para>
--- 91,99 ----
<command>ALTER DEFAULT PRIVILEGES</> allows you to set the privileges
that will be applied to objects created in the future. (It does not
affect privileges assigned to already-existing objects.) Currently,
! only the privileges for schemas, tables (including views and foreign
! tables), sequences, functions, and types (including domains) can be
! altered.
</para>
<para>
***************
*** 125,130 **** REVOKE [ GRANT OPTION FOR ]
--- 136,143 ----
are altered for objects later created in that schema.
If <literal>IN SCHEMA</> is omitted, the global default privileges
are altered.
+ <literal>IN SCHEMA</> is not allowed when using <literal>ON SCHEMAS</>
+ as schemas can't be nested.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/catalog/aclchk.c b/src/backeindex 7803d0d..9d64ab6 100644
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
***************
*** 950,955 **** ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s
--- 950,959 ----
all_privileges = ACL_ALL_RIGHTS_TYPE;
errormsg = gettext_noop("invalid privilege type %s for type");
break;
+ case ACL_OBJECT_NAMESPACE:
+ all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
+ errormsg = gettext_noop("invalid privilege type %s for schema");
+ break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) action->objtype);
***************
*** 1137,1142 **** SetDefaultACL(InternalDefaultACL *iacls)
--- 1141,1156 ----
this_privileges = ACL_ALL_RIGHTS_TYPE;
break;
+ case ACL_OBJECT_NAMESPACE:
+ if (OidIsValid(iacls->nspid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_GRANT_OPERATION),
+ errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
+ objtype = DEFACLOBJ_NAMESPACE;
+ if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
+ this_privileges = ACL_ALL_RIGHTS_NAMESPACE;
+ break;
+
default:
elog(ERROR, "unrecognized objtype: %d",
(int) iacls->objtype);
***************
*** 1363,1368 **** RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
--- 1377,1385 ----
case DEFACLOBJ_TYPE:
iacls.objtype = ACL_OBJECT_TYPE;
break;
+ case DEFACLOBJ_NAMESPACE:
+ iacls.objtype = ACL_OBJECT_NAMESPACE;
+ break;
default:
/* Shouldn't get here */
elog(ERROR, "unexpected default ACL type: %d",
***************
*** 5191,5196 **** get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
--- 5208,5217 ----
defaclobjtype = DEFACLOBJ_TYPE;
break;
+ case ACL_OBJECT_NAMESPACE:
+ defaclobjtype = DEFACLOBJ_NAMESPACE;
+ break;
+
default:
return NULL;
}
diff --git a/src/backend/catalog/obindex 2b1808b..edb9edc 100644
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
***************
*** 1789,1799 **** get_object_address_defacl(List *objname, List *objargs, bool missing_ok)
case DEFACLOBJ_TYPE:
objtype_str = "types";
break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized default ACL object type %c", objtype),
! errhint("Valid object types are \"r\", \"S\", \"f\", and \"T\".")));
}
/*
--- 1789,1802 ----
case DEFACLOBJ_TYPE:
objtype_str = "types";
break;
+ case DEFACLOBJ_NAMESPACE:
+ objtype_str = "schemas";
+ break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized default ACL object type %c", objtype),
! errhint("Valid object types are \"r\", \"S\", \"f\", \"T\" and \"s\".")));
}
/*
***************
*** 3094,3099 **** getObjectDescription(const ObjectAddress *object)
--- 3097,3107 ----
_("default privileges on new types belonging to role %s"),
GetUserNameFromId(defacl->defaclrole, false));
break;
+ case DEFACLOBJ_NAMESPACE:
+ appendStringInfo(&buffer,
+ _("default privileges on new schemas belonging to role %s"),
+ GetUserNameFromId(defacl->defaclrole, false));
+ break;
default:
/* shouldn't get here */
appendStringInfo(&buffer,
***************
*** 4550,4555 **** getObjectIdentityParts(const ObjectAddress *object,
--- 4558,4567 ----
appendStringInfoString(&buffer,
" on types");
break;
+ case DEFACLOBJ_NAMESPACE:
+ appendStringInfoString(&buffer,
+ " on schemas");
+ break;
}
if (objname)
diff --git a/src/backend/catalog/pg_namespindex f048ad4..bad7ba1 100644
*** a/src/backend/catalog/pg_namespace.c
--- b/src/backend/catalog/pg_namespace.c
***************
*** 31,40 ****
* Create a namespace (schema) with the given name and owner OID.
*
* If isTemp is true, this schema is a per-backend schema for holding
! * temporary tables. Currently, the only effect of that is to prevent it
! * from being linked as a member of any active extension. (If someone
! * does CREATE TEMP TABLE in an extension script, we don't want the temp
! * schema to become part of the extension.)
* ---------------
*/
Oid
--- 31,41 ----
* Create a namespace (schema) with the given name and owner OID.
*
* If isTemp is true, this schema is a per-backend schema for holding
! * temporary tables. Currently, it is used to prevent it from being
! * linked as a member of any active extension. (If someone does CREATE
! * TEMP TABLE in an extension script, we don't want the temp schema to
! * become part of the extension). And to avoid checking for default ACL
! * for temp namespace (as it is not necessary).
* ---------------
*/
Oid
***************
*** 49,54 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
--- 50,56 ----
TupleDesc tupDesc;
ObjectAddress myself;
int i;
+ Acl *nspacl;
/* sanity checks */
if (!nspName)
***************
*** 60,65 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
--- 62,73 ----
(errcode(ERRCODE_DUPLICATE_SCHEMA),
errmsg("schema \"%s\" already exists", nspName)));
+ if (!isTemp)
+ nspacl = get_user_default_acl(ACL_OBJECT_NAMESPACE, ownerId,
+ InvalidOid);
+ else
+ nspacl = NULL;
+
/* initialize nulls and values */
for (i = 0; i < Natts_pg_namespace; i++)
{
***************
*** 69,75 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
! nulls[Anum_pg_namespace_nspacl - 1] = true;
nspdesc = heap_open(NamespaceRelationId, RowExclusiveLock);
tupDesc = nspdesc->rd_att;
--- 77,86 ----
namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
! if (nspacl != NULL)
! values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl);
! else
! nulls[Anum_pg_namespace_nspacl - 1] = true;
nspdesc = heap_open(NamespaceRelationId, RowExclusiveLock);
tupDesc = nspdesc->rd_att;
diff --git a/src/backend/parser/gram.y b/index 9eef550..a477fc82 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 647,653 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
! SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P START
STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING
--- 647,653 ----
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
! SAVEPOINT SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P START
STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING
***************
*** 7006,7011 **** defacl_privilege_target:
--- 7006,7012 ----
| FUNCTIONS { $$ = ACL_OBJECT_FUNCTION; }
| SEQUENCES { $$ = ACL_OBJECT_SEQUENCE; }
| TYPES_P { $$ = ACL_OBJECT_TYPE; }
+ | SCHEMAS { $$ = ACL_OBJECT_NAMESPACE; }
;
***************
*** 14206,14211 **** unreserved_keyword:
--- 14207,14213 ----
| RULE
| SAVEPOINT
| SCHEMA
+ | SCHEMAS
| SCROLL
| SEARCH
| SECOND_P
diff --git a/src/bin/pg_dump/dumindex 81ec650..a969014 100644
*** a/src/bin/pg_dump/dumputils.c
--- b/src/bin/pg_dump/dumputils.c
***************
*** 511,517 **** do { \
CONVERT_PRIV('X', "EXECUTE");
else if (strcmp(type, "LANGUAGE") == 0)
CONVERT_PRIV('U', "USAGE");
! else if (strcmp(type, "SCHEMA") == 0)
{
CONVERT_PRIV('C', "CREATE");
CONVERT_PRIV('U', "USAGE");
--- 511,519 ----
CONVERT_PRIV('X', "EXECUTE");
else if (strcmp(type, "LANGUAGE") == 0)
CONVERT_PRIV('U', "USAGE");
! else if (strcmp(type, "SCHEMA") == 0 ||
! strcmp(type, "SCHEMAS") == 0
! )
{
CONVERT_PRIV('C', "CREATE");
CONVERT_PRIV('U', "USAGE");
diff --git a/src/bin/pg_dump/pg_duindex 148e8e1..60090d9 100644
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 13580,13585 **** dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
--- 13580,13588 ----
case DEFACLOBJ_TYPE:
type = "TYPES";
break;
+ case DEFACLOBJ_NAMESPACE:
+ type = "SCHEMAS";
+ break;
default:
/* shouldn't get here */
exit_horribly(NULL,
diff --git a/src/bin/psql/descriindex ce19877..3866e35 100644
*** a/src/bin/psql/describe.c
--- b/src/bin/psql/describe.c
***************
*** 1020,1026 **** listDefaultACLs(const char *pattern)
printfPQExpBuffer(&buf,
"SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
" n.nspname AS \"%s\",\n"
! " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
" ",
gettext_noop("Owner"),
gettext_noop("Schema"),
--- 1020,1026 ----
printfPQExpBuffer(&buf,
"SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
" n.nspname AS \"%s\",\n"
! " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
" ",
gettext_noop("Owner"),
gettext_noop("Schema"),
***************
*** 1032,1037 **** listDefaultACLs(const char *pattern)
--- 1032,1039 ----
gettext_noop("function"),
DEFACLOBJ_TYPE,
gettext_noop("type"),
+ DEFACLOBJ_NAMESPACE,
+ gettext_noop("schema"),
gettext_noop("Type"));
printACLColumn(&buf, "d.defaclacl");
diff --git a/src/include/catalindex 42fb224..78bbeb6 100644
*** a/src/include/catalog/pg_default_acl.h
--- b/src/include/catalog/pg_default_acl.h
***************
*** 70,74 **** typedef FormData_pg_default_acl *Form_pg_default_acl;
--- 70,75 ----
#define DEFACLOBJ_SEQUENCE 'S' /* sequence */
#define DEFACLOBJ_FUNCTION 'f' /* function */
#define DEFACLOBJ_TYPE 'T' /* type */
+ #define DEFACLOBJ_NAMESPACE 'n' /* namespace */
#endif /* PG_DEFAULT_ACL_H */
diff --git a/src/include/parser/kwlist.h b/index 9978573..c40b719 100644
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 341,346 **** PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
--- 341,347 ----
PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
+ PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
diff --git a/src/test/regress/expeindex f66b443..449b0e3 100644
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
***************
*** 1337,1342 **** SELECT has_table_privilege('regress_user1', 'testns.acltest1', 'INSERT'); -- no
--- 1337,1400 ----
(1 row)
ALTER DEFAULT PRIVILEGES FOR ROLE regress_user1 REVOKE EXECUTE ON FUNCTIONS FROM public;
+ ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_user2; -- error
+ ERROR: cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS
+ ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_user2;
+ CREATE SCHEMA testns2;
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'USAGE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES REVOKE USAGE ON SCHEMAS FROM regress_user2;
+ CREATE SCHEMA testns3;
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'USAGE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_user2;
+ CREATE SCHEMA testns4;
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'USAGE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'CREATE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_user2;
+ CREATE SCHEMA testns5;
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'USAGE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
SET ROLE regress_user1;
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
SELECT has_function_privilege('regress_user2', 'testns.foo()', 'EXECUTE'); -- no
***************
*** 1384,1389 **** SELECT count(*)
--- 1442,1451 ----
DROP SCHEMA testns CASCADE;
NOTICE: drop cascades to table testns.acltest1
+ DROP SCHEMA testns2 CASCADE;
+ DROP SCHEMA testns3 CASCADE;
+ DROP SCHEMA testns4 CASCADE;
+ DROP SCHEMA testns5 CASCADE;
SELECT d.* -- check that entries went away
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
WHERE nspname IS NULL AND defaclnamespace != 0;
diff --git a/src/test/regress/sql/privileges.sqindex 00dc7bd..c2c1629 100644
*** a/src/test/regress/sql/privileges.sql
--- b/src/test/regress/sql/privileges.sql
***************
*** 807,812 **** SELECT has_table_privilege('regress_user1', 'testns.acltest1', 'INSERT'); -- no
--- 807,842 ----
ALTER DEFAULT PRIVILEGES FOR ROLE regress_user1 REVOKE EXECUTE ON FUNCTIONS FROM public;
+ ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_user2; -- error
+
+ ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_user2;
+
+ CREATE SCHEMA testns2;
+
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'USAGE'); -- yes
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'CREATE'); -- no
+
+ ALTER DEFAULT PRIVILEGES REVOKE USAGE ON SCHEMAS FROM regress_user2;
+
+ CREATE SCHEMA testns3;
+
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'USAGE'); -- no
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'CREATE'); -- no
+
+ ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_user2;
+
+ CREATE SCHEMA testns4;
+
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'USAGE'); -- yes
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'CREATE'); -- yes
+
+ ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_user2;
+
+ CREATE SCHEMA testns5;
+
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'USAGE'); -- no
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'CREATE'); -- no
+
SET ROLE regress_user1;
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
***************
*** 844,849 **** SELECT count(*)
--- 874,883 ----
WHERE nspname = 'testns';
DROP SCHEMA testns CASCADE;
+ DROP SCHEMA testns2 CASCADE;
+ DROP SCHEMA testns3 CASCADE;
+ DROP SCHEMA testns4 CASCADE;
+ DROP SCHEMA testns5 CASCADE;
SELECT d.* -- check that entries went away
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
On 10/01/17 17:33, Matheus de Oliveira wrote:
On Mon, Jan 9, 2017 at 10:58 AM, Ashutosh Sharma <ashu.coek88@gmail.com
<mailto:ashu.coek88@gmail.com>> wrote:Also, should I add translations for that error message in other languages (I
can do that without help of tools for pt_BR) or is that a latter process in
the releasing?I think you should add it but i am not sure when it is done.
I'll ask one of the guys who work with pt_BR translations (I know him in
person).
Translations are not handled by patch author but by translation project
so no need.
Attached a rebased version and with the docs update pointed by Ashutosh
Sharma.
The patch looks good, the only thing I am missing is tab completion
support for psql.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
* Petr Jelinek (petr.jelinek@2ndquadrant.com) wrote:
On 10/01/17 17:33, Matheus de Oliveira wrote:
On Mon, Jan 9, 2017 at 10:58 AM, Ashutosh Sharma <ashu.coek88@gmail.com
<mailto:ashu.coek88@gmail.com>> wrote:Also, should I add translations for that error message in other languages (I
can do that without help of tools for pt_BR) or is that a latter process in
the releasing?I think you should add it but i am not sure when it is done.
I'll ask one of the guys who work with pt_BR translations (I know him in
person).Translations are not handled by patch author but by translation project
so no need.Attached a rebased version and with the docs update pointed by Ashutosh
Sharma.The patch looks good, the only thing I am missing is tab completion
support for psql.
Awesome, glad to hear it. This is also on my list of patches that I'm
planning to look at, just so folks know.
Thanks!
Stephen
On Thu, Jan 19, 2017 at 9:35 AM, Stephen Frost <sfrost@snowman.net> wrote:
Awesome, glad to hear it. This is also on my list of patches that I'm
planning to look at, just so folks know.
There is a patch, no new reviews, so moved to CF 2017-03.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 1/18/17 7:18 PM, Petr Jelinek wrote:
On 10/01/17 17:33, Matheus de Oliveira wrote:
On Mon, Jan 9, 2017 at 10:58 AM, Ashutosh Sharma <ashu.coek88@gmail.com
<mailto:ashu.coek88@gmail.com>> wrote:Also, should I add translations for that error message in other languages (I
can do that without help of tools for pt_BR) or is that a latter process in
the releasing?I think you should add it but i am not sure when it is done.
I'll ask one of the guys who work with pt_BR translations (I know him in
person).Translations are not handled by patch author but by translation project
so no need.Attached a rebased version and with the docs update pointed by Ashutosh
Sharma.The patch looks good, the only thing I am missing is tab completion
support for psql.
It looks like this patch is still waiting on an update for tab
completion in psql.
Do you know when will have that patch ready?
--
-David
david@pgmasters.net
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi Matheus,
On 3/2/17 8:27 AM, David Steele wrote:
On 1/18/17 7:18 PM, Petr Jelinek wrote:
The patch looks good, the only thing I am missing is tab completion
support for psql.It looks like this patch is still waiting on an update for tab
completion in psql.Do you know when will have that patch ready?
It's been a while since there was a new patch or any activity on this
thread.
If you need more time to produce a patch, please post an explanation for
the delay and a schedule for the new patch. If no patch or explanation
is is posted by 2017-03-16 AoE I will mark this submission
"Returned with Feedback".
Thanks,
--
-David
david@pgmasters.net
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 3/13/17 11:15 AM, David Steele wrote:
Hi Matheus,
On 3/2/17 8:27 AM, David Steele wrote:
On 1/18/17 7:18 PM, Petr Jelinek wrote:
The patch looks good, the only thing I am missing is tab completion
support for psql.It looks like this patch is still waiting on an update for tab
completion in psql.Do you know when will have that patch ready?
It's been a while since there was a new patch or any activity on this
thread.If you need more time to produce a patch, please post an explanation for
the delay and a schedule for the new patch. If no patch or explanation
is is posted by 2017-03-16 AoE I will mark this submission
"Returned with Feedback".
I have marked this submission "Returned with Feedback". Please feel
free to resubmit when you have a new version.
--
-David
david@pgmasters.net
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Mar 2, 2017 at 10:27 AM, David Steele <david@pgmasters.net> wrote:
It looks like this patch is still waiting on an update for tab
completion in psql.
Hi All,
Sorry about the long delay... It was so simple to add it to tab-complete.c
that is a shame I didn't do it before, very sorry about that.
Attached the new version of the patch that is basically the same as
previously with the addition to tab completion for psql and rebased with
master.
Hope it is enough. Thank you all.
--
Matheus de Oliveira
Attachments:
postgresql-defacl-schema-v2.patchtext/x-patch; charset=US-ASCII; name=postgresql-defacl-schema-v2.patchDownload
diff --git a/doc/src/sgml/ref/alter_default_privileges.sgml b/doc/src/sgml/ref/alter_default_privileges.sgml
index 04064d3..e3363f8 100644
*** a/doc/src/sgml/ref/alter_default_privileges.sgml
--- b/doc/src/sgml/ref/alter_default_privileges.sgml
***************
*** 46,51 **** GRANT { USAGE | ALL [ PRIVILEGES ] }
--- 46,55 ----
ON TYPES
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+ GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] }
+ ON SCHEMAS
+ TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[, ...] | ALL [ PRIVILEGES ] }
***************
*** 71,76 **** REVOKE [ GRANT OPTION FOR ]
--- 75,86 ----
ON TYPES
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+
+ REVOKE [ GRANT OPTION FOR ]
+ { USAGE | CREATE | ALL [ PRIVILEGES ] }
+ ON SCHEMAS
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
***************
*** 81,88 **** REVOKE [ GRANT OPTION FOR ]
<command>ALTER DEFAULT PRIVILEGES</> allows you to set the privileges
that will be applied to objects created in the future. (It does not
affect privileges assigned to already-existing objects.) Currently,
! only the privileges for tables (including views and foreign tables),
! sequences, functions, and types (including domains) can be altered.
</para>
<para>
--- 91,99 ----
<command>ALTER DEFAULT PRIVILEGES</> allows you to set the privileges
that will be applied to objects created in the future. (It does not
affect privileges assigned to already-existing objects.) Currently,
! only the privileges for schemas, tables (including views and foreign
! tables), sequences, functions, and types (including domains) can be
! altered.
</para>
<para>
***************
*** 125,130 **** REVOKE [ GRANT OPTION FOR ]
--- 136,143 ----
are altered for objects later created in that schema.
If <literal>IN SCHEMA</> is omitted, the global default privileges
are altered.
+ <literal>IN SCHEMA</> is not allowed when using <literal>ON SCHEMAS</>
+ as schemas can't be nested.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/catalog/aclchk.c b/src/backeindex d01930f..2d535c2 100644
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
***************
*** 959,964 **** ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s
--- 959,968 ----
all_privileges = ACL_ALL_RIGHTS_TYPE;
errormsg = gettext_noop("invalid privilege type %s for type");
break;
+ case ACL_OBJECT_NAMESPACE:
+ all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
+ errormsg = gettext_noop("invalid privilege type %s for schema");
+ break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) action->objtype);
***************
*** 1146,1151 **** SetDefaultACL(InternalDefaultACL *iacls)
--- 1150,1165 ----
this_privileges = ACL_ALL_RIGHTS_TYPE;
break;
+ case ACL_OBJECT_NAMESPACE:
+ if (OidIsValid(iacls->nspid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_GRANT_OPERATION),
+ errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
+ objtype = DEFACLOBJ_NAMESPACE;
+ if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
+ this_privileges = ACL_ALL_RIGHTS_NAMESPACE;
+ break;
+
default:
elog(ERROR, "unrecognized objtype: %d",
(int) iacls->objtype);
***************
*** 1369,1374 **** RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
--- 1383,1391 ----
case DEFACLOBJ_TYPE:
iacls.objtype = ACL_OBJECT_TYPE;
break;
+ case DEFACLOBJ_NAMESPACE:
+ iacls.objtype = ACL_OBJECT_NAMESPACE;
+ break;
default:
/* Shouldn't get here */
elog(ERROR, "unexpected default ACL type: %d",
***************
*** 5259,5264 **** get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
--- 5276,5285 ----
defaclobjtype = DEFACLOBJ_TYPE;
break;
+ case ACL_OBJECT_NAMESPACE:
+ defaclobjtype = DEFACLOBJ_NAMESPACE;
+ break;
+
default:
return NULL;
}
diff --git a/src/backend/catalog/obindex 2948d64..1eb7930 100644
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
***************
*** 1843,1853 **** get_object_address_defacl(List *object, bool missing_ok)
case DEFACLOBJ_TYPE:
objtype_str = "types";
break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized default ACL object type %c", objtype),
! errhint("Valid object types are \"r\", \"S\", \"f\", and \"T\".")));
}
/*
--- 1843,1856 ----
case DEFACLOBJ_TYPE:
objtype_str = "types";
break;
+ case DEFACLOBJ_NAMESPACE:
+ objtype_str = "schemas";
+ break;
default:
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized default ACL object type %c", objtype),
! errhint("Valid object types are \"r\", \"S\", \"f\", \"T\" and \"s\".")));
}
/*
***************
*** 3255,3260 **** getObjectDescription(const ObjectAddress *object)
--- 3258,3268 ----
_("default privileges on new types belonging to role %s"),
GetUserNameFromId(defacl->defaclrole, false));
break;
+ case DEFACLOBJ_NAMESPACE:
+ appendStringInfo(&buffer,
+ _("default privileges on new schemas belonging to role %s"),
+ GetUserNameFromId(defacl->defaclrole, false));
+ break;
default:
/* shouldn't get here */
appendStringInfo(&buffer,
***************
*** 4762,4767 **** getObjectIdentityParts(const ObjectAddress *object,
--- 4770,4779 ----
appendStringInfoString(&buffer,
" on types");
break;
+ case DEFACLOBJ_NAMESPACE:
+ appendStringInfoString(&buffer,
+ " on schemas");
+ break;
}
if (objname)
diff --git a/src/backend/catalog/pg_namespindex 5672536..613b963 100644
*** a/src/backend/catalog/pg_namespace.c
--- b/src/backend/catalog/pg_namespace.c
***************
*** 31,40 ****
* Create a namespace (schema) with the given name and owner OID.
*
* If isTemp is true, this schema is a per-backend schema for holding
! * temporary tables. Currently, the only effect of that is to prevent it
! * from being linked as a member of any active extension. (If someone
! * does CREATE TEMP TABLE in an extension script, we don't want the temp
! * schema to become part of the extension.)
* ---------------
*/
Oid
--- 31,41 ----
* Create a namespace (schema) with the given name and owner OID.
*
* If isTemp is true, this schema is a per-backend schema for holding
! * temporary tables. Currently, it is used to prevent it from being
! * linked as a member of any active extension. (If someone does CREATE
! * TEMP TABLE in an extension script, we don't want the temp schema to
! * become part of the extension). And to avoid checking for default ACL
! * for temp namespace (as it is not necessary).
* ---------------
*/
Oid
***************
*** 49,54 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
--- 50,56 ----
TupleDesc tupDesc;
ObjectAddress myself;
int i;
+ Acl *nspacl;
/* sanity checks */
if (!nspName)
***************
*** 60,65 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
--- 62,73 ----
(errcode(ERRCODE_DUPLICATE_SCHEMA),
errmsg("schema \"%s\" already exists", nspName)));
+ if (!isTemp)
+ nspacl = get_user_default_acl(ACL_OBJECT_NAMESPACE, ownerId,
+ InvalidOid);
+ else
+ nspacl = NULL;
+
/* initialize nulls and values */
for (i = 0; i < Natts_pg_namespace; i++)
{
***************
*** 69,75 **** NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
! nulls[Anum_pg_namespace_nspacl - 1] = true;
nspdesc = heap_open(NamespaceRelationId, RowExclusiveLock);
tupDesc = nspdesc->rd_att;
--- 77,86 ----
namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = ObjectIdGetDatum(ownerId);
! if (nspacl != NULL)
! values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(nspacl);
! else
! nulls[Anum_pg_namespace_nspacl - 1] = true;
nspdesc = heap_open(NamespaceRelationId, RowExclusiveLock);
tupDesc = nspdesc->rd_att;
diff --git a/src/backend/parser/gram.y b/index 19dd77d..20865c0 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 668,674 **** static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
! SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
SIMILAR SIMPLE SKIP SLOT SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P
START STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P
--- 668,674 ----
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROW ROWS RULE
! SAVEPOINT SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
SIMILAR SIMPLE SKIP SLOT SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P
START STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P
***************
*** 7035,7040 **** defacl_privilege_target:
--- 7035,7041 ----
| FUNCTIONS { $$ = ACL_OBJECT_FUNCTION; }
| SEQUENCES { $$ = ACL_OBJECT_SEQUENCE; }
| TYPES_P { $$ = ACL_OBJECT_TYPE; }
+ | SCHEMAS { $$ = ACL_OBJECT_NAMESPACE; }
;
***************
*** 14713,14718 **** unreserved_keyword:
--- 14714,14720 ----
| RULE
| SAVEPOINT
| SCHEMA
+ | SCHEMAS
| SCROLL
| SEARCH
| SECOND_P
diff --git a/src/bin/pg_dump/dumindex b41f2b9..c74153a 100644
*** a/src/bin/pg_dump/dumputils.c
--- b/src/bin/pg_dump/dumputils.c
***************
*** 520,526 **** do { \
CONVERT_PRIV('X', "EXECUTE");
else if (strcmp(type, "LANGUAGE") == 0)
CONVERT_PRIV('U', "USAGE");
! else if (strcmp(type, "SCHEMA") == 0)
{
CONVERT_PRIV('C', "CREATE");
CONVERT_PRIV('U', "USAGE");
--- 520,528 ----
CONVERT_PRIV('X', "EXECUTE");
else if (strcmp(type, "LANGUAGE") == 0)
CONVERT_PRIV('U', "USAGE");
! else if (strcmp(type, "SCHEMA") == 0 ||
! strcmp(type, "SCHEMAS") == 0
! )
{
CONVERT_PRIV('C', "CREATE");
CONVERT_PRIV('U', "USAGE");
diff --git a/src/bin/pg_dump/pg_duindex ba34cc1..262f553 100644
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 14295,14300 **** dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
--- 14295,14303 ----
case DEFACLOBJ_TYPE:
type = "TYPES";
break;
+ case DEFACLOBJ_NAMESPACE:
+ type = "SCHEMAS";
+ break;
default:
/* shouldn't get here */
exit_horribly(NULL,
diff --git a/src/bin/psql/descriindex bcf6752..b0f3e5e 100644
*** a/src/bin/psql/describe.c
--- b/src/bin/psql/describe.c
***************
*** 1028,1034 **** listDefaultACLs(const char *pattern)
printfPQExpBuffer(&buf,
"SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
" n.nspname AS \"%s\",\n"
! " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
" ",
gettext_noop("Owner"),
gettext_noop("Schema"),
--- 1028,1034 ----
printfPQExpBuffer(&buf,
"SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
" n.nspname AS \"%s\",\n"
! " CASE d.defaclobjtype WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' WHEN '%c' THEN '%s' END AS \"%s\",\n"
" ",
gettext_noop("Owner"),
gettext_noop("Schema"),
***************
*** 1040,1045 **** listDefaultACLs(const char *pattern)
--- 1040,1047 ----
gettext_noop("function"),
DEFACLOBJ_TYPE,
gettext_noop("type"),
+ DEFACLOBJ_NAMESPACE,
+ gettext_noop("schema"),
gettext_noop("Type"));
printACLColumn(&buf, "d.defaclacl");
diff --git a/src/bin/psql/tab-index f749406..dc2794d 100644
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
***************
*** 2796,2802 **** psql_completion(const char *text, int start, int end)
* to the kinds of objects supported.
*/
if (HeadMatches3("ALTER","DEFAULT","PRIVILEGES"))
! COMPLETE_WITH_LIST4("TABLES", "SEQUENCES", "FUNCTIONS", "TYPES");
else
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf,
" UNION SELECT 'ALL FUNCTIONS IN SCHEMA'"
--- 2796,2802 ----
* to the kinds of objects supported.
*/
if (HeadMatches3("ALTER","DEFAULT","PRIVILEGES"))
! COMPLETE_WITH_LIST5("TABLES", "SEQUENCES", "FUNCTIONS", "TYPES", "SCHEMAS");
else
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvmf,
" UNION SELECT 'ALL FUNCTIONS IN SCHEMA'"
diff --git a/src/include/catalog/pindex 42fb224..78bbeb6 100644
*** a/src/include/catalog/pg_default_acl.h
--- b/src/include/catalog/pg_default_acl.h
***************
*** 70,74 **** typedef FormData_pg_default_acl *Form_pg_default_acl;
--- 70,75 ----
#define DEFACLOBJ_SEQUENCE 'S' /* sequence */
#define DEFACLOBJ_FUNCTION 'f' /* function */
#define DEFACLOBJ_TYPE 'T' /* type */
+ #define DEFACLOBJ_NAMESPACE 'n' /* namespace */
#endif /* PG_DEFAULT_ACL_H */
diff --git a/src/include/parser/kwlist.h b/index 6cd36c7..cd21a78 100644
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 344,349 **** PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
--- 344,350 ----
PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD)
PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD)
+ PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD)
PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD)
PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD)
PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD)
diff --git a/src/test/regress/expeindex f349980..c6e7031 100644
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
***************
*** 1356,1361 **** SELECT has_table_privilege('regress_user1', 'testns.acltest1', 'INSERT'); -- no
--- 1356,1419 ----
(1 row)
ALTER DEFAULT PRIVILEGES FOR ROLE regress_user1 REVOKE EXECUTE ON FUNCTIONS FROM public;
+ ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_user2; -- error
+ ERROR: cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS
+ ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_user2;
+ CREATE SCHEMA testns2;
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'USAGE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES REVOKE USAGE ON SCHEMAS FROM regress_user2;
+ CREATE SCHEMA testns3;
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'USAGE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_user2;
+ CREATE SCHEMA testns4;
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'USAGE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'CREATE'); -- yes
+ has_schema_privilege
+ ----------------------
+ t
+ (1 row)
+
+ ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_user2;
+ CREATE SCHEMA testns5;
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'USAGE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'CREATE'); -- no
+ has_schema_privilege
+ ----------------------
+ f
+ (1 row)
+
SET ROLE regress_user1;
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
SELECT has_function_privilege('regress_user2', 'testns.foo()', 'EXECUTE'); -- no
***************
*** 1403,1408 **** SELECT count(*)
--- 1461,1470 ----
DROP SCHEMA testns CASCADE;
NOTICE: drop cascades to table testns.acltest1
+ DROP SCHEMA testns2 CASCADE;
+ DROP SCHEMA testns3 CASCADE;
+ DROP SCHEMA testns4 CASCADE;
+ DROP SCHEMA testns5 CASCADE;
SELECT d.* -- check that entries went away
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
WHERE nspname IS NULL AND defaclnamespace != 0;
diff --git a/src/test/regress/sql/privileges.sqindex 166e903..3821595 100644
*** a/src/test/regress/sql/privileges.sql
--- b/src/test/regress/sql/privileges.sql
***************
*** 816,821 **** SELECT has_table_privilege('regress_user1', 'testns.acltest1', 'INSERT'); -- no
--- 816,851 ----
ALTER DEFAULT PRIVILEGES FOR ROLE regress_user1 REVOKE EXECUTE ON FUNCTIONS FROM public;
+ ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON SCHEMAS TO regress_user2; -- error
+
+ ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO regress_user2;
+
+ CREATE SCHEMA testns2;
+
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'USAGE'); -- yes
+ SELECT has_schema_privilege('regress_user2', 'testns2', 'CREATE'); -- no
+
+ ALTER DEFAULT PRIVILEGES REVOKE USAGE ON SCHEMAS FROM regress_user2;
+
+ CREATE SCHEMA testns3;
+
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'USAGE'); -- no
+ SELECT has_schema_privilege('regress_user2', 'testns3', 'CREATE'); -- no
+
+ ALTER DEFAULT PRIVILEGES GRANT ALL ON SCHEMAS TO regress_user2;
+
+ CREATE SCHEMA testns4;
+
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'USAGE'); -- yes
+ SELECT has_schema_privilege('regress_user2', 'testns4', 'CREATE'); -- yes
+
+ ALTER DEFAULT PRIVILEGES REVOKE ALL ON SCHEMAS FROM regress_user2;
+
+ CREATE SCHEMA testns5;
+
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'USAGE'); -- no
+ SELECT has_schema_privilege('regress_user2', 'testns5', 'CREATE'); -- no
+
SET ROLE regress_user1;
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
***************
*** 853,858 **** SELECT count(*)
--- 883,892 ----
WHERE nspname = 'testns';
DROP SCHEMA testns CASCADE;
+ DROP SCHEMA testns2 CASCADE;
+ DROP SCHEMA testns3 CASCADE;
+ DROP SCHEMA testns4 CASCADE;
+ DROP SCHEMA testns5 CASCADE;
SELECT d.* -- check that entries went away
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
Thank you, pushed
Matheus de Oliveira wrote:
On Thu, Mar 2, 2017 at 10:27 AM, David Steele <david@pgmasters.net
<mailto:david@pgmasters.net>> wrote:It looks like this patch is still waiting on an update for tab
completion in psql.Hi All,
Sorry about the long delay... It was so simple to add it to tab-complete.c that
is a shame I didn't do it before, very sorry about that.Attached the new version of the patch that is basically the same as previously
with the addition to tab completion for psql and rebased with master.Hope it is enough. Thank you all.
--
Matheus de Oliveira
--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers