Commit 72920557 authored by Peter Eisentraut's avatar Peter Eisentraut

Add support for privileges on types

This adds support for the more or less SQL-conforming USAGE privilege
on types and domains.  The intent is to be able restrict which users
can create dependencies on types, which restricts the way in which
owners can alter types.

reviewed by Yeb Havinga
parent 05e992e9
...@@ -284,6 +284,8 @@ ...@@ -284,6 +284,8 @@
the attributes of composite data types defined in the database. the attributes of composite data types defined in the database.
(Note that the view does not give information about table columns, (Note that the view does not give information about table columns,
which are sometimes called attributes in PostgreSQL contexts.) which are sometimes called attributes in PostgreSQL contexts.)
Only those attributes are shown that the current user has access to (by way
of being the owner of or having some privilege on the type).
</para> </para>
<table> <table>
...@@ -1915,8 +1917,10 @@ ...@@ -1915,8 +1917,10 @@
<title><literal>domain_constraints</literal></title> <title><literal>domain_constraints</literal></title>
<para> <para>
The view <literal>domain_constraints</literal> contains all The view <literal>domain_constraints</literal> contains all constraints
constraints belonging to domains defined in the current database. belonging to domains defined in the current database. Only those domains
are shown that the current user has access to (by way of being the owner or
having some privilege).
</para> </para>
<table> <table>
...@@ -2052,8 +2056,9 @@ ...@@ -2052,8 +2056,9 @@
<title><literal>domains</literal></title> <title><literal>domains</literal></title>
<para> <para>
The view <literal>domains</literal> contains all domains defined in The view <literal>domains</literal> contains all domains defined in the
the current database. current database. Only those domains are shown that the current user has
access to (by way of being the owner or having some privilege).
</para> </para>
<table> <table>
...@@ -5778,15 +5783,13 @@ ORDER BY c.ordinal_position; ...@@ -5778,15 +5783,13 @@ ORDER BY c.ordinal_position;
<title><literal>udt_privileges</literal></title> <title><literal>udt_privileges</literal></title>
<para> <para>
The view <literal>udt_privileges</literal> is intended to identify The view <literal>udt_privileges</literal> identifies
<literal>USAGE</literal> privileges granted on user-defined types <literal>USAGE</literal> privileges granted on user-defined types to a
to a currently enabled role or by a currently enabled role. Since currently enabled role or by a currently enabled role. There is one row for
data types do not have real privileges each combination of column, grantor, and grantee. This view shows only
in <productname>PostgreSQL</productname>, this view shows implicit composite types (see under <xref linkend="infoschema-user-defined-types">
non-grantable <literal>USAGE</literal> privileges granted by the for why); see
owner to <literal>PUBLIC</literal> for all types, including <xref linkend="infoschema-usage-privileges"> for domain privileges.
built-in ones (except domains,
see <xref linkend="infoschema-usage-privileges"> for that).
</para> </para>
<table> <table>
...@@ -5861,10 +5864,10 @@ ORDER BY c.ordinal_position; ...@@ -5861,10 +5864,10 @@ ORDER BY c.ordinal_position;
</para> </para>
<para> <para>
Since collations and domains do not have real privileges Since collations do not have real privileges
in <productname>PostgreSQL</productname>, this view shows implicit in <productname>PostgreSQL</productname>, this view shows implicit
non-grantable <literal>USAGE</literal> privileges granted by the non-grantable <literal>USAGE</literal> privileges granted by the
owner to <literal>PUBLIC</literal> for all collations and domains. The other owner to <literal>PUBLIC</literal> for all collations. The other
object types, however, show real privileges. object types, however, show real privileges.
</para> </para>
...@@ -5940,6 +5943,8 @@ ORDER BY c.ordinal_position; ...@@ -5940,6 +5943,8 @@ ORDER BY c.ordinal_position;
<para> <para>
The view <literal>user_defined_types</literal> currently contains The view <literal>user_defined_types</literal> currently contains
all composite types defined in the current database. all composite types defined in the current database.
Only those types are shown that the current user has access to (by way
of being the owner or having some privilege).
</para> </para>
<para> <para>
......
...@@ -42,6 +42,10 @@ GRANT { EXECUTE | ALL [ PRIVILEGES ] } ...@@ -42,6 +42,10 @@ GRANT { EXECUTE | ALL [ PRIVILEGES ] }
ON FUNCTIONS ON FUNCTIONS
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ] TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON TYPES
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
REVOKE [ GRANT OPTION FOR ] REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[, ...] | ALL [ PRIVILEGES ] } [, ...] | ALL [ PRIVILEGES ] }
...@@ -61,6 +65,12 @@ REVOKE [ GRANT OPTION FOR ] ...@@ -61,6 +65,12 @@ REVOKE [ GRANT OPTION FOR ]
ON FUNCTIONS ON FUNCTIONS
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ] [ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON TYPES
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -72,7 +82,7 @@ REVOKE [ GRANT OPTION FOR ] ...@@ -72,7 +82,7 @@ REVOKE [ GRANT OPTION FOR ]
that will be applied to objects created in the future. (It does not that will be applied to objects created in the future. (It does not
affect privileges assigned to already-existing objects.) Currently, affect privileges assigned to already-existing objects.) Currently,
only the privileges for tables (including views and foreign tables), only the privileges for tables (including views and foreign tables),
sequences, and functions can be altered. sequences, functions, and types (including domains) can be altered.
</para> </para>
<para> <para>
......
...@@ -157,6 +157,8 @@ ALTER FOREIGN TABLE <replaceable class="PARAMETER">name</replaceable> ...@@ -157,6 +157,8 @@ ALTER FOREIGN TABLE <replaceable class="PARAMETER">name</replaceable>
the table's schema. (These restrictions enforce that altering the owner the table's schema. (These restrictions enforce that altering the owner
doesn't do anything you couldn't do by dropping and recreating the table. doesn't do anything you couldn't do by dropping and recreating the table.
However, a superuser can alter ownership of any table anyway.) However, a superuser can alter ownership of any table anyway.)
To add a column or alter a column type, you must also
have <literal>USAGE</literal> privilege on the data type.
</para> </para>
</refsect1> </refsect1>
......
...@@ -594,6 +594,9 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable> ...@@ -594,6 +594,9 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
the table's schema. (These restrictions enforce that altering the owner the table's schema. (These restrictions enforce that altering the owner
doesn't do anything you couldn't do by dropping and recreating the table. doesn't do anything you couldn't do by dropping and recreating the table.
However, a superuser can alter ownership of any table anyway.) However, a superuser can alter ownership of any table anyway.)
To add a column or alter a column type or use the <literal>OF</literal>
clause, you must also have <literal>USAGE</literal> privilege on the data
type.
</para> </para>
</refsect1> </refsect1>
......
...@@ -156,6 +156,8 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replacea ...@@ -156,6 +156,8 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replacea
the type's schema. (These restrictions enforce that altering the owner the type's schema. (These restrictions enforce that altering the owner
doesn't do anything you couldn't do by dropping and recreating the type. doesn't do anything you couldn't do by dropping and recreating the type.
However, a superuser can alter ownership of any type anyway.) However, a superuser can alter ownership of any type anyway.)
To add an attribute or alter an attribute type, you must also
have <literal>USAGE</literal> privilege on the data type.
</para> </para>
</refsect1> </refsect1>
......
...@@ -163,6 +163,13 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1; ...@@ -163,6 +163,13 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
than</quote> or <quote>greater than</quote> strategy member of a B-tree than</quote> or <quote>greater than</quote> strategy member of a B-tree
index operator class. index operator class.
</para> </para>
<para>
To be able to create an aggregate function, you must
have <literal>USAGE</literal> privilege on the argument types, the state
type, and the return type, as well as <literal>EXECUTE</literal> privilege
on the transition and final functions.
</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
......
...@@ -159,10 +159,11 @@ SELECT CAST ( 2 AS numeric ) + 4.0; ...@@ -159,10 +159,11 @@ SELECT CAST ( 2 AS numeric ) + 4.0;
</note> </note>
<para> <para>
To be able to create a cast, you must own the source or the target To be able to create a cast, you must own the source or the target data type
data type. To create a binary-coercible cast, you must be superuser. and have <literal>USAGE</literal> privilege on the other type. To create a
(This restriction is made because an erroneous binary-coercible cast binary-coercible cast, you must be superuser. (This restriction is made
conversion can easily crash the server.) because an erroneous binary-coercible cast conversion can easily crash the
server.)
</para> </para>
</refsect1> </refsect1>
......
...@@ -59,6 +59,11 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea ...@@ -59,6 +59,11 @@ CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replacea
Define a domain rather than setting up each table's constraint Define a domain rather than setting up each table's constraint
individually. individually.
</para> </para>
<para>
To be able to create a domain, you must have <literal>USAGE</literal>
privilege on the underlying type.
</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
......
...@@ -52,6 +52,11 @@ CREATE FOREIGN TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name ...@@ -52,6 +52,11 @@ CREATE FOREIGN TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name
the foreign table. Therefore, foreign tables cannot have the same the foreign table. Therefore, foreign tables cannot have the same
name as any existing data type in the same schema. name as any existing data type in the same schema.
</para> </para>
<para>
To be able to create a table, you must have <literal>USAGE</literal>
privilege on all column types.
</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
......
...@@ -92,6 +92,11 @@ CREATE [ OR REPLACE ] FUNCTION ...@@ -92,6 +92,11 @@ CREATE [ OR REPLACE ] FUNCTION
<para> <para>
The user that creates the function becomes the owner of the function. The user that creates the function becomes the owner of the function.
</para> </para>
<para>
To be able to create a function, you must have <literal>USAGE</literal>
privilege on the argument types and the return type.
</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
......
...@@ -103,6 +103,13 @@ CREATE OPERATOR <replaceable>name</replaceable> ( ...@@ -103,6 +103,13 @@ CREATE OPERATOR <replaceable>name</replaceable> (
The other clauses specify optional operator optimization clauses. The other clauses specify optional operator optimization clauses.
Their meaning is detailed in <xref linkend="xoper-optimization">. Their meaning is detailed in <xref linkend="xoper-optimization">.
</para> </para>
<para>
To be able to create an operator, you must have <literal>USAGE</literal>
privilege on the argument types and the return type, as well
as <literal>EXECUTE</literal> privilege on the underlying function. If a
commutator or negator operator is specified, you must own these operators.
</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
......
...@@ -124,6 +124,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI ...@@ -124,6 +124,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
a column constraint is only a notational convenience for use when the a column constraint is only a notational convenience for use when the
constraint only affects one column. constraint only affects one column.
</para> </para>
<para>
To be able to create a table, you must have <literal>USAGE</literal>
privilege on all column types or the type in the <literal>OF</literal>
clause, respectively.
</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
......
...@@ -104,6 +104,11 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -104,6 +104,11 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
A stand-alone composite type is useful, for example, as the argument or A stand-alone composite type is useful, for example, as the argument or
return type of a function. return type of a function.
</para> </para>
<para>
To be able to create a composite type, you must
have <literal>USAGE</literal> privilege on all attribute types.
</para>
</refsect2> </refsect2>
<refsect2 id="SQL-CREATETYPE-enum"> <refsect2 id="SQL-CREATETYPE-enum">
......
...@@ -42,6 +42,10 @@ GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] } ...@@ -42,6 +42,10 @@ GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
ON DATABASE <replaceable>database_name</replaceable> [, ...] ON DATABASE <replaceable>database_name</replaceable> [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ] TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] } GRANT { USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...] ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ] TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
...@@ -71,6 +75,10 @@ GRANT { CREATE | ALL [ PRIVILEGES ] } ...@@ -71,6 +75,10 @@ GRANT { CREATE | ALL [ PRIVILEGES ] }
ON TABLESPACE <replaceable>tablespace_name</replaceable> [, ...] ON TABLESPACE <replaceable>tablespace_name</replaceable> [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ] TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON TYPE <replaceable>type_name</replaceable> [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replaceable class="PARAMETER">role_name</replaceable> [, ...] [ WITH ADMIN OPTION ] GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replaceable class="PARAMETER">role_name</replaceable> [, ...] [ WITH ADMIN OPTION ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -335,6 +343,15 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace ...@@ -335,6 +343,15 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace
For sequences, this privilege allows the use of the For sequences, this privilege allows the use of the
<function>currval</function> and <function>nextval</function> functions. <function>currval</function> and <function>nextval</function> functions.
</para> </para>
<para>
For types and domains, this privilege allow the use of the type or
domain in the creation of tables, functions, and other schema objects.
(Note that it does not control general <quote>usage</quote> of the type,
such as values of the type appearing in queries. It only prevents
objects from being created that depend on the type. The main purpose of
the privilege is controlling which users create dependencies on a type,
which could prevent the owner from changing the type later.)
</para>
<para> <para>
For foreign-data wrappers, this privilege enables the grantee For foreign-data wrappers, this privilege enables the grantee
to create new servers using that foreign-data wrapper. to create new servers using that foreign-data wrapper.
...@@ -616,7 +633,7 @@ GRANT admins TO joe; ...@@ -616,7 +633,7 @@ GRANT admins TO joe;
<para> <para>
The SQL standard provides for a <literal>USAGE</literal> privilege The SQL standard provides for a <literal>USAGE</literal> privilege
on other kinds of objects: character sets, collations, on other kinds of objects: character sets, collations,
translations, domains. translations.
</para> </para>
<para> <para>
......
...@@ -1048,7 +1048,7 @@ testdb=&gt; ...@@ -1048,7 +1048,7 @@ testdb=&gt;
pattern or the <literal>S</literal> modifier to include system pattern or the <literal>S</literal> modifier to include system
objects. objects.
If <literal>+</literal> is appended to the command name, each object If <literal>+</literal> is appended to the command name, each object
is listed with its associated description. is listed with its associated permissions and description.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1387,8 +1387,8 @@ testdb=&gt; ...@@ -1387,8 +1387,8 @@ testdb=&gt;
If <replaceable class="parameter">pattern</replaceable> is If <replaceable class="parameter">pattern</replaceable> is
specified, only types whose names match the pattern are listed. specified, only types whose names match the pattern are listed.
If <literal>+</literal> is appended to the command name, each type is If <literal>+</literal> is appended to the command name, each type is
listed with its internal name and size, as well as its allowed values listed with its internal name and size, its allowed values
if it is an <type>enum</> type. if it is an <type>enum</> type, and its associated permissions.
By default, only user-created objects are shown; supply a By default, only user-created objects are shown; supply a
pattern or the <literal>S</literal> modifier to include system pattern or the <literal>S</literal> modifier to include system
objects. objects.
......
...@@ -50,6 +50,12 @@ REVOKE [ GRANT OPTION FOR ] ...@@ -50,6 +50,12 @@ REVOKE [ GRANT OPTION FOR ]
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ] [ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ] REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] } { USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...] ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...]
...@@ -93,6 +99,12 @@ REVOKE [ GRANT OPTION FOR ] ...@@ -93,6 +99,12 @@ REVOKE [ GRANT OPTION FOR ]
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ] [ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON TYPE <replaceable>type_name</replaceable> [, ...]
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ ADMIN OPTION FOR ] REVOKE [ ADMIN OPTION FOR ]
<replaceable class="PARAMETER">role_name</replaceable> [, ...] FROM <replaceable class="PARAMETER">role_name</replaceable> [, ...] <replaceable class="PARAMETER">role_name</replaceable> [, ...] FROM <replaceable class="PARAMETER">role_name</replaceable> [, ...]
[ CASCADE | RESTRICT ] [ CASCADE | RESTRICT ]
......
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
#include "postgres.h" #include "postgres.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "miscadmin.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/resowner.h" #include "utils/resowner.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -557,6 +559,7 @@ BuildDescForRelation(List *schema) ...@@ -557,6 +559,7 @@ BuildDescForRelation(List *schema)
foreach(l, schema) foreach(l, schema)
{ {
ColumnDef *entry = lfirst(l); ColumnDef *entry = lfirst(l);
AclResult aclresult;
/* /*
* for each entry in the list, get the name and type information from * for each entry in the list, get the name and type information from
...@@ -567,6 +570,12 @@ BuildDescForRelation(List *schema) ...@@ -567,6 +570,12 @@ BuildDescForRelation(List *schema)
attname = entry->colname; attname = entry->colname;
typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod); typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
aclresult = pg_type_aclcheck(atttypid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(atttypid));
attcollation = GetColumnDefCollation(NULL, entry, atttypid); attcollation = GetColumnDefCollation(NULL, entry, atttypid);
attdim = list_length(entry->typeName->arrayBounds); attdim = list_length(entry->typeName->arrayBounds);
......
This diff is collapsed.
...@@ -357,7 +357,9 @@ CREATE VIEW attributes AS ...@@ -357,7 +357,9 @@ CREATE VIEW attributes AS
ON a.attcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default') ON a.attcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default')
WHERE a.attnum > 0 AND NOT a.attisdropped WHERE a.attnum > 0 AND NOT a.attisdropped
AND c.relkind in ('c'); AND c.relkind in ('c')
AND (pg_has_role(c.relowner, 'USAGE')
OR has_type_privilege(c.reltype, 'USAGE'));
GRANT SELECT ON attributes TO PUBLIC; GRANT SELECT ON attributes TO PUBLIC;
...@@ -868,7 +870,9 @@ CREATE VIEW domain_constraints AS ...@@ -868,7 +870,9 @@ CREATE VIEW domain_constraints AS
FROM pg_namespace rs, pg_namespace n, pg_constraint con, pg_type t FROM pg_namespace rs, pg_namespace n, pg_constraint con, pg_type t
WHERE rs.oid = con.connamespace WHERE rs.oid = con.connamespace
AND n.oid = t.typnamespace AND n.oid = t.typnamespace
AND t.oid = con.contypid; AND t.oid = con.contypid
AND (pg_has_role(t.typowner, 'USAGE')
OR has_type_privilege(t.oid, 'USAGE'));
GRANT SELECT ON domain_constraints TO PUBLIC; GRANT SELECT ON domain_constraints TO PUBLIC;
...@@ -978,7 +982,8 @@ CREATE VIEW domains AS ...@@ -978,7 +982,8 @@ CREATE VIEW domains AS
LEFT JOIN (pg_collation co JOIN pg_namespace nco ON (co.collnamespace = nco.oid)) LEFT JOIN (pg_collation co JOIN pg_namespace nco ON (co.collnamespace = nco.oid))
ON t.typcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default') ON t.typcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default')
; WHERE (pg_has_role(t.typowner, 'USAGE')
OR has_type_privilege(t.oid, 'USAGE'));
GRANT SELECT ON domains TO PUBLIC; GRANT SELECT ON domains TO PUBLIC;
...@@ -2024,20 +2029,38 @@ GRANT SELECT ON triggers TO PUBLIC; ...@@ -2024,20 +2029,38 @@ GRANT SELECT ON triggers TO PUBLIC;
*/ */
CREATE VIEW udt_privileges AS CREATE VIEW udt_privileges AS
SELECT CAST(null AS sql_identifier) AS grantor, SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
CAST('PUBLIC' AS sql_identifier) AS grantee, CAST(grantee.rolname AS sql_identifier) AS grantee,
CAST(current_database() AS sql_identifier) AS udt_catalog, CAST(current_database() AS sql_identifier) AS udt_catalog,
CAST(n.nspname AS sql_identifier) AS udt_schema, CAST(n.nspname AS sql_identifier) AS udt_schema,
CAST(t.typname AS sql_identifier) AS udt_name, CAST(t.typname AS sql_identifier) AS udt_name,
CAST('TYPE USAGE' AS character_data) AS privilege_type, -- sic CAST('TYPE USAGE' AS character_data) AS privilege_type, -- sic
CAST('NO' AS yes_or_no) AS is_grantable CAST(
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, t.typowner, 'USAGE')
OR t.grantable
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
FROM pg_authid u, pg_namespace n, pg_type t FROM (
SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(typacl)).* FROM pg_type
) AS t (oid, typname, typnamespace, typtype, typowner, grantor, grantee, prtype, grantable),
pg_namespace n,
pg_authid u_grantor,
(
SELECT oid, rolname FROM pg_authid
UNION ALL
SELECT 0::oid, 'PUBLIC'
) AS grantee (oid, rolname)
WHERE u.oid = t.typowner WHERE t.typnamespace = n.oid
AND n.oid = t.typnamespace AND t.typtype = 'c'
AND t.typtype <> 'd' AND t.grantee = grantee.oid
AND NOT (t.typelem <> 0 AND t.typlen = -1); AND t.grantor = u_grantor.oid
AND t.prtype IN ('USAGE')
AND (pg_has_role(u_grantor.oid, 'USAGE')
OR pg_has_role(grantee.oid, 'USAGE')
OR grantee.rolname = 'PUBLIC');
GRANT SELECT ON udt_privileges TO PUBLIC; GRANT SELECT ON udt_privileges TO PUBLIC;
...@@ -2091,23 +2114,39 @@ CREATE VIEW usage_privileges AS ...@@ -2091,23 +2114,39 @@ CREATE VIEW usage_privileges AS
UNION ALL UNION ALL
/* domains */ /* domains */
-- Domains have no real privileges, so we represent all domains with implicit usage privilege here. SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
SELECT CAST(u.rolname AS sql_identifier) AS grantor, CAST(grantee.rolname AS sql_identifier) AS grantee,
CAST('PUBLIC' AS sql_identifier) AS grantee,
CAST(current_database() AS sql_identifier) AS object_catalog, CAST(current_database() AS sql_identifier) AS object_catalog,
CAST(n.nspname AS sql_identifier) AS object_schema, CAST(n.nspname AS sql_identifier) AS object_schema,
CAST(t.typname AS sql_identifier) AS object_name, CAST(t.typname AS sql_identifier) AS object_name,
CAST('DOMAIN' AS character_data) AS object_type, CAST('DOMAIN' AS character_data) AS object_type,
CAST('USAGE' AS character_data) AS privilege_type, CAST('USAGE' AS character_data) AS privilege_type,
CAST('NO' AS yes_or_no) AS is_grantable CAST(
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, t.typowner, 'USAGE')
OR t.grantable
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
FROM pg_authid u, FROM (
SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(typacl)).* FROM pg_type
) AS t (oid, typname, typnamespace, typtype, typowner, grantor, grantee, prtype, grantable),
pg_namespace n, pg_namespace n,
pg_type t pg_authid u_grantor,
(
SELECT oid, rolname FROM pg_authid
UNION ALL
SELECT 0::oid, 'PUBLIC'
) AS grantee (oid, rolname)
WHERE u.oid = t.typowner WHERE t.typnamespace = n.oid
AND t.typnamespace = n.oid
AND t.typtype = 'd' AND t.typtype = 'd'
AND t.grantee = grantee.oid
AND t.grantor = u_grantor.oid
AND t.prtype IN ('USAGE')
AND (pg_has_role(u_grantor.oid, 'USAGE')
OR pg_has_role(grantee.oid, 'USAGE')
OR grantee.rolname = 'PUBLIC')
UNION ALL UNION ALL
...@@ -2237,10 +2276,13 @@ CREATE VIEW user_defined_types AS ...@@ -2237,10 +2276,13 @@ CREATE VIEW user_defined_types AS
CAST(null AS sql_identifier) AS source_dtd_identifier, CAST(null AS sql_identifier) AS source_dtd_identifier,
CAST(null AS sql_identifier) AS ref_dtd_identifier CAST(null AS sql_identifier) AS ref_dtd_identifier
FROM pg_namespace n, pg_class c FROM pg_namespace n, pg_class c, pg_type t
WHERE n.oid = c.relnamespace WHERE n.oid = c.relnamespace
AND c.relkind = 'c'; AND t.typrelid = c.oid
AND c.relkind = 'c'
AND (pg_has_role(t.typowner, 'USAGE')
OR has_type_privilege(t.oid, 'USAGE'));
GRANT SELECT ON user_defined_types TO PUBLIC; GRANT SELECT ON user_defined_types TO PUBLIC;
......
...@@ -71,6 +71,7 @@ AggregateCreate(const char *aggName, ...@@ -71,6 +71,7 @@ AggregateCreate(const char *aggName,
int i; int i;
ObjectAddress myself, ObjectAddress myself,
referenced; referenced;
AclResult aclresult;
/* sanity checks (caller should have caught these) */ /* sanity checks (caller should have caught these) */
if (!aggName) if (!aggName)
...@@ -200,6 +201,28 @@ AggregateCreate(const char *aggName, ...@@ -200,6 +201,28 @@ AggregateCreate(const char *aggName,
false, -1); false, -1);
} }
/*
* permission checks on used types
*/
for (i = 0; i < numArgs; i++)
{
aclresult = pg_type_aclcheck(aggArgTypes[i], GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(aggArgTypes[i]));
}
aclresult = pg_type_aclcheck(aggTransType, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(aggTransType));
aclresult = pg_type_aclcheck(finaltype, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(finaltype));
/* /*
* Everything looks okay. Try to create the pg_proc entry for the * Everything looks okay. Try to create the pg_proc entry for the
* aggregate. (This could fail if there's already a conflicting entry.) * aggregate. (This could fail if there's already a conflicting entry.)
......
...@@ -117,6 +117,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) ...@@ -117,6 +117,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid); values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
nulls[Anum_pg_type_typdefaultbin - 1] = true; nulls[Anum_pg_type_typdefaultbin - 1] = true;
nulls[Anum_pg_type_typdefault - 1] = true; nulls[Anum_pg_type_typdefault - 1] = true;
nulls[Anum_pg_type_typacl - 1] = true;
/* /*
* create a new type tuple * create a new type tuple
...@@ -224,6 +225,7 @@ TypeCreate(Oid newTypeOid, ...@@ -224,6 +225,7 @@ TypeCreate(Oid newTypeOid,
Datum values[Natts_pg_type]; Datum values[Natts_pg_type];
NameData name; NameData name;
int i; int i;
Acl *typacl = NULL;
/* /*
* We assume that the caller validated the arguments individually, but did * We assume that the caller validated the arguments individually, but did
...@@ -369,6 +371,13 @@ TypeCreate(Oid newTypeOid, ...@@ -369,6 +371,13 @@ TypeCreate(Oid newTypeOid,
else else
nulls[Anum_pg_type_typdefault - 1] = true; nulls[Anum_pg_type_typdefault - 1] = true;
typacl = get_user_default_acl(ACL_OBJECT_TYPE, ownerId,
typeNamespace);
if (typacl != NULL)
values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
else
nulls[Anum_pg_type_typacl - 1] = true;
/* /*
* open pg_type and prepare to insert or update a row. * open pg_type and prepare to insert or update a row.
* *
......
...@@ -87,9 +87,11 @@ compute_return_type(TypeName *returnType, Oid languageOid, ...@@ -87,9 +87,11 @@ compute_return_type(TypeName *returnType, Oid languageOid,
{ {
Oid rettype; Oid rettype;
Type typtup; Type typtup;
AclResult aclresult;
typtup = LookupTypeName(NULL, returnType, NULL); typtup = LookupTypeName(NULL, returnType, NULL);
if (typtup) if (typtup)
{ {
if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
...@@ -150,6 +152,11 @@ compute_return_type(TypeName *returnType, Oid languageOid, ...@@ -150,6 +152,11 @@ compute_return_type(TypeName *returnType, Oid languageOid,
Assert(OidIsValid(rettype)); Assert(OidIsValid(rettype));
} }
aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(rettype));
*prorettype_p = rettype; *prorettype_p = rettype;
*returnsSet_p = returnType->setof; *returnsSet_p = returnType->setof;
} }
...@@ -207,6 +214,7 @@ examine_parameter_list(List *parameters, Oid languageOid, ...@@ -207,6 +214,7 @@ examine_parameter_list(List *parameters, Oid languageOid,
bool isinput = false; bool isinput = false;
Oid toid; Oid toid;
Type typtup; Type typtup;
AclResult aclresult;
typtup = LookupTypeName(NULL, t, NULL); typtup = LookupTypeName(NULL, t, NULL);
if (typtup) if (typtup)
...@@ -237,6 +245,11 @@ examine_parameter_list(List *parameters, Oid languageOid, ...@@ -237,6 +245,11 @@ examine_parameter_list(List *parameters, Oid languageOid,
toid = InvalidOid; /* keep compiler quiet */ toid = InvalidOid; /* keep compiler quiet */
} }
aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(toid));
if (t->setof) if (t->setof)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
...@@ -1429,6 +1442,7 @@ CreateCast(CreateCastStmt *stmt) ...@@ -1429,6 +1442,7 @@ CreateCast(CreateCastStmt *stmt)
bool nulls[Natts_pg_cast]; bool nulls[Natts_pg_cast];
ObjectAddress myself, ObjectAddress myself,
referenced; referenced;
AclResult aclresult;
sourcetypeid = typenameTypeId(NULL, stmt->sourcetype); sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
targettypeid = typenameTypeId(NULL, stmt->targettype); targettypeid = typenameTypeId(NULL, stmt->targettype);
...@@ -1457,6 +1471,16 @@ CreateCast(CreateCastStmt *stmt) ...@@ -1457,6 +1471,16 @@ CreateCast(CreateCastStmt *stmt)
format_type_be(sourcetypeid), format_type_be(sourcetypeid),
format_type_be(targettypeid)))); format_type_be(targettypeid))));
aclresult = pg_type_aclcheck(sourcetypeid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(sourcetypeid));
aclresult = pg_type_aclcheck(targettypeid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(targettypeid));
/* Detemine the cast method */ /* Detemine the cast method */
if (stmt->func != NULL) if (stmt->func != NULL)
castmethod = COERCION_METHOD_FUNCTION; castmethod = COERCION_METHOD_FUNCTION;
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include "parser/parse_func.h" #include "parser/parse_func.h"
#include "parser/parse_oper.h" #include "parser/parse_oper.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/rel.h" #include "utils/rel.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -73,6 +74,7 @@ DefineOperator(List *names, List *parameters) ...@@ -73,6 +74,7 @@ DefineOperator(List *names, List *parameters)
TypeName *typeName2 = NULL; /* second type name */ TypeName *typeName2 = NULL; /* second type name */
Oid typeId1 = InvalidOid; /* types converted to OID */ Oid typeId1 = InvalidOid; /* types converted to OID */
Oid typeId2 = InvalidOid; Oid typeId2 = InvalidOid;
Oid rettype;
List *commutatorName = NIL; /* optional commutator operator name */ List *commutatorName = NIL; /* optional commutator operator name */
List *negatorName = NIL; /* optional negator operator name */ List *negatorName = NIL; /* optional negator operator name */
List *restrictionName = NIL; /* optional restrict. sel. procedure */ List *restrictionName = NIL; /* optional restrict. sel. procedure */
...@@ -175,6 +177,22 @@ DefineOperator(List *names, List *parameters) ...@@ -175,6 +177,22 @@ DefineOperator(List *names, List *parameters)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("at least one of leftarg or rightarg must be specified"))); errmsg("at least one of leftarg or rightarg must be specified")));
if (typeName1)
{
aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(typeId1));
}
if (typeName2)
{
aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(typeId2));
}
/* /*
* Look up the operator's underlying function. * Look up the operator's underlying function.
*/ */
...@@ -206,6 +224,12 @@ DefineOperator(List *names, List *parameters) ...@@ -206,6 +224,12 @@ DefineOperator(List *names, List *parameters)
aclcheck_error(aclresult, ACL_KIND_PROC, aclcheck_error(aclresult, ACL_KIND_PROC,
NameListToString(functionName)); NameListToString(functionName));
rettype = get_func_rettype(functionOid);
aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(rettype));
/* /*
* Look up restriction estimator if specified * Look up restriction estimator if specified
*/ */
......
...@@ -506,7 +506,16 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId) ...@@ -506,7 +506,16 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
(void) heap_reloptions(relkind, reloptions, true); (void) heap_reloptions(relkind, reloptions, true);
if (stmt->ofTypename) if (stmt->ofTypename)
{
AclResult aclresult;
ofTypeId = typenameTypeId(NULL, stmt->ofTypename); ofTypeId = typenameTypeId(NULL, stmt->ofTypename);
aclresult = pg_type_aclcheck(ofTypeId, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(ofTypeId));
}
else else
ofTypeId = InvalidOid; ofTypeId = InvalidOid;
...@@ -4326,6 +4335,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, ...@@ -4326,6 +4335,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
Expr *defval; Expr *defval;
List *children; List *children;
ListCell *child; ListCell *child;
AclResult aclresult;
/* At top level, permission check was done in ATPrepCmd, else do it */ /* At top level, permission check was done in ATPrepCmd, else do it */
if (recursing) if (recursing)
...@@ -4429,6 +4439,12 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, ...@@ -4429,6 +4439,12 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
typeTuple = typenameType(NULL, colDef->typeName, &typmod); typeTuple = typenameType(NULL, colDef->typeName, &typmod);
tform = (Form_pg_type) GETSTRUCT(typeTuple); tform = (Form_pg_type) GETSTRUCT(typeTuple);
typeOid = HeapTupleGetOid(typeTuple); typeOid = HeapTupleGetOid(typeTuple);
aclresult = pg_type_aclcheck(typeOid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(typeOid));
collOid = GetColumnDefCollation(NULL, colDef, typeOid); collOid = GetColumnDefCollation(NULL, colDef, typeOid);
/* make sure datatype is legal for a column */ /* make sure datatype is legal for a column */
...@@ -6973,6 +6989,7 @@ ATPrepAlterColumnType(List **wqueue, ...@@ -6973,6 +6989,7 @@ ATPrepAlterColumnType(List **wqueue,
Oid targetcollid; Oid targetcollid;
NewColumnValue *newval; NewColumnValue *newval;
ParseState *pstate = make_parsestate(NULL); ParseState *pstate = make_parsestate(NULL);
AclResult aclresult;
if (rel->rd_rel->reloftype && !recursing) if (rel->rd_rel->reloftype && !recursing)
ereport(ERROR, ereport(ERROR,
...@@ -7006,6 +7023,11 @@ ATPrepAlterColumnType(List **wqueue, ...@@ -7006,6 +7023,11 @@ ATPrepAlterColumnType(List **wqueue,
/* Look up the target type */ /* Look up the target type */
typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod); typenameTypeIdAndMod(NULL, typeName, &targettype, &targettypmod);
aclresult = pg_type_aclcheck(targettype, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(targettype));
/* And the collation */ /* And the collation */
targetcollid = GetColumnDefCollation(NULL, def, targettype); targetcollid = GetColumnDefCollation(NULL, def, targettype);
......
...@@ -756,6 +756,11 @@ DefineDomain(CreateDomainStmt *stmt) ...@@ -756,6 +756,11 @@ DefineDomain(CreateDomainStmt *stmt)
errmsg("\"%s\" is not a valid base type for a domain", errmsg("\"%s\" is not a valid base type for a domain",
TypeNameToString(stmt->typeName)))); TypeNameToString(stmt->typeName))));
aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(basetypeoid));
/* /*
* Identify the collation if any * Identify the collation if any
*/ */
......
...@@ -2490,6 +2490,21 @@ OpenIntoRel(QueryDesc *queryDesc) ...@@ -2490,6 +2490,21 @@ OpenIntoRel(QueryDesc *queryDesc)
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("ON COMMIT can only be used on temporary tables"))); errmsg("ON COMMIT can only be used on temporary tables")));
{
AclResult aclresult;
int i;
for (i = 0; i < intoTupDesc->natts; i++)
{
Oid atttypid = intoTupDesc->attrs[i]->atttypid;
aclresult = pg_type_aclcheck(atttypid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TYPE,
format_type_be(atttypid));
}
}
/* /*
* If a column name list was specified in CREATE TABLE AS, override the * If a column name list was specified in CREATE TABLE AS, override the
* column names derived from the query. (Too few column names are OK, too * column names derived from the query. (Too few column names are OK, too
......
...@@ -558,7 +558,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType, ...@@ -558,7 +558,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
TABLE TABLES TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP TABLE TABLES TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP
TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
TRUNCATE TRUSTED TYPE_P TRUNCATE TRUSTED TYPE_P TYPES_P
UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNLOGGED UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNLOGGED
UNTIL UPDATE USER USING UNTIL UPDATE USER USING
...@@ -5434,6 +5434,14 @@ privilege_target: ...@@ -5434,6 +5434,14 @@ privilege_target:
n->objs = $2; n->objs = $2;
$$ = n; $$ = n;
} }
| DOMAIN_P any_name_list
{
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->targtype = ACL_TARGET_OBJECT;
n->objtype = ACL_OBJECT_DOMAIN;
n->objs = $2;
$$ = n;
}
| LANGUAGE name_list | LANGUAGE name_list
{ {
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
...@@ -5466,6 +5474,14 @@ privilege_target: ...@@ -5466,6 +5474,14 @@ privilege_target:
n->objs = $2; n->objs = $2;
$$ = n; $$ = n;
} }
| TYPE_P any_name_list
{
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->targtype = ACL_TARGET_OBJECT;
n->objtype = ACL_OBJECT_TYPE;
n->objs = $2;
$$ = n;
}
| ALL TABLES IN_P SCHEMA name_list | ALL TABLES IN_P SCHEMA name_list
{ {
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
...@@ -5680,6 +5696,7 @@ defacl_privilege_target: ...@@ -5680,6 +5696,7 @@ defacl_privilege_target:
TABLES { $$ = ACL_OBJECT_RELATION; } TABLES { $$ = ACL_OBJECT_RELATION; }
| FUNCTIONS { $$ = ACL_OBJECT_FUNCTION; } | FUNCTIONS { $$ = ACL_OBJECT_FUNCTION; }
| SEQUENCES { $$ = ACL_OBJECT_SEQUENCE; } | SEQUENCES { $$ = ACL_OBJECT_SEQUENCE; }
| TYPES_P { $$ = ACL_OBJECT_TYPE; }
; ;
......
...@@ -109,6 +109,8 @@ static Oid convert_server_name(text *servername); ...@@ -109,6 +109,8 @@ static Oid convert_server_name(text *servername);
static AclMode convert_server_priv_string(text *priv_type_text); static AclMode convert_server_priv_string(text *priv_type_text);
static Oid convert_tablespace_name(text *tablespacename); static Oid convert_tablespace_name(text *tablespacename);
static AclMode convert_tablespace_priv_string(text *priv_type_text); static AclMode convert_tablespace_priv_string(text *priv_type_text);
static Oid convert_type_name(text *typename);
static AclMode convert_type_priv_string(text *priv_type_text);
static AclMode convert_role_priv_string(text *priv_type_text); static AclMode convert_role_priv_string(text *priv_type_text);
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode); static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
...@@ -782,6 +784,11 @@ acldefault(GrantObjectType objtype, Oid ownerId) ...@@ -782,6 +784,11 @@ acldefault(GrantObjectType objtype, Oid ownerId)
world_default = ACL_NO_RIGHTS; world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER; owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
break; break;
case ACL_OBJECT_DOMAIN:
case ACL_OBJECT_TYPE:
world_default = ACL_USAGE;
owner_default = ACL_ALL_RIGHTS_TYPE;
break;
default: default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype); elog(ERROR, "unrecognized objtype: %d", (int) objtype);
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */ world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
...@@ -4126,6 +4133,206 @@ convert_tablespace_priv_string(text *priv_type_text) ...@@ -4126,6 +4133,206 @@ convert_tablespace_priv_string(text *priv_type_text)
return convert_any_priv_string(priv_type_text, tablespace_priv_map); return convert_any_priv_string(priv_type_text, tablespace_priv_map);
} }
/*
* has_type_privilege variants
* These are all named "has_type_privilege" at the SQL level.
* They take various combinations of type name, type OID,
* user name, user OID, or implicit user = current_user.
*
* The result is a boolean value: true if user has the indicated
* privilege, false if not, or NULL if object doesn't exist.
*/
/*
* has_type_privilege_name_name
* Check user privileges on a type given
* name username, text typename, and text priv name.
*/
Datum
has_type_privilege_name_name(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
text *typename = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
Oid typeoid;
AclMode mode;
AclResult aclresult;
roleid = get_role_oid_or_public(NameStr(*username));
typeoid = convert_type_name(typename);
mode = convert_type_priv_string(priv_type_text);
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_type_privilege_name
* Check user privileges on a type given
* text typename and text priv name.
* current_user is assumed
*/
Datum
has_type_privilege_name(PG_FUNCTION_ARGS)
{
text *typename = PG_GETARG_TEXT_P(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
Oid typeoid;
AclMode mode;
AclResult aclresult;
roleid = GetUserId();
typeoid = convert_type_name(typename);
mode = convert_type_priv_string(priv_type_text);
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_type_privilege_name_id
* Check user privileges on a type given
* name usename, type oid, and text priv name.
*/
Datum
has_type_privilege_name_id(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
Oid typeoid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
AclMode mode;
AclResult aclresult;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_type_priv_string(priv_type_text);
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
PG_RETURN_NULL();
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_type_privilege_id
* Check user privileges on a type given
* type oid, and text priv name.
* current_user is assumed
*/
Datum
has_type_privilege_id(PG_FUNCTION_ARGS)
{
Oid typeoid = PG_GETARG_OID(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
AclMode mode;
AclResult aclresult;
roleid = GetUserId();
mode = convert_type_priv_string(priv_type_text);
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
PG_RETURN_NULL();
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_type_privilege_id_name
* Check user privileges on a type given
* roleid, text typename, and text priv name.
*/
Datum
has_type_privilege_id_name(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
text *typename = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid typeoid;
AclMode mode;
AclResult aclresult;
typeoid = convert_type_name(typename);
mode = convert_type_priv_string(priv_type_text);
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_type_privilege_id_id
* Check user privileges on a type given
* roleid, type oid, and text priv name.
*/
Datum
has_type_privilege_id_id(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
Oid typeoid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
AclMode mode;
AclResult aclresult;
mode = convert_type_priv_string(priv_type_text);
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
PG_RETURN_NULL();
aclresult = pg_type_aclcheck(typeoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* Support routines for has_type_privilege family.
*/
/*
* Given a type name expressed as a string, look it up and return Oid
*/
static Oid
convert_type_name(text *typename)
{
char *typname = text_to_cstring(typename);
Oid oid;
oid = DatumGetObjectId(DirectFunctionCall1(regtypein,
CStringGetDatum(typname)));
if (!OidIsValid(oid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type \"%s\" does not exist", typname)));
return oid;
}
/*
* convert_type_priv_string
* Convert text string to AclMode value.
*/
static AclMode
convert_type_priv_string(text *priv_type_text)
{
static const priv_map type_priv_map[] = {
{"USAGE", ACL_USAGE},
{"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
{NULL, 0}
};
return convert_any_priv_string(priv_type_text, type_priv_map);
}
/* /*
* pg_has_role variants * pg_has_role variants
* These are all named "pg_has_role" at the SQL level. * These are all named "pg_has_role" at the SQL level.
......
...@@ -504,6 +504,11 @@ describeTypes(const char *pattern, bool verbose, bool showSystem) ...@@ -504,6 +504,11 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
" ) AS \"%s\",\n", " ) AS \"%s\",\n",
gettext_noop("Elements")); gettext_noop("Elements"));
} }
if (verbose && pset.sversion >= 90200)
{
printACLColumn(&buf, "t.typacl");
appendPQExpBuffer(&buf, ",\n ");
}
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
" pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n", " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n",
...@@ -2813,9 +2818,16 @@ listDomains(const char *pattern, bool verbose, bool showSystem) ...@@ -2813,9 +2818,16 @@ listDomains(const char *pattern, bool verbose, bool showSystem)
gettext_noop("Check")); gettext_noop("Check"));
if (verbose) if (verbose)
{
if (pset.sversion >= 90200)
{
appendPQExpBuffer(&buf, ",\n ");
printACLColumn(&buf, "t.typacl");
}
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
",\n d.description as \"%s\"", ",\n d.description as \"%s\"",
gettext_noop("Description")); gettext_noop("Description"));
}
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
"\nFROM pg_catalog.pg_type t\n" "\nFROM pg_catalog.pg_type t\n"
......
...@@ -2241,13 +2241,15 @@ psql_completion(char *text, int start, int end) ...@@ -2241,13 +2241,15 @@ psql_completion(char *text, int start, int end)
pg_strcasecmp(prev_wd, "ON") == 0) pg_strcasecmp(prev_wd, "ON") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf, COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsvf,
" UNION SELECT 'DATABASE'" " UNION SELECT 'DATABASE'"
" UNION SELECT 'DOMAIN'"
" UNION SELECT 'FOREIGN DATA WRAPPER'" " UNION SELECT 'FOREIGN DATA WRAPPER'"
" UNION SELECT 'FOREIGN SERVER'" " UNION SELECT 'FOREIGN SERVER'"
" UNION SELECT 'FUNCTION'" " UNION SELECT 'FUNCTION'"
" UNION SELECT 'LANGUAGE'" " UNION SELECT 'LANGUAGE'"
" UNION SELECT 'LARGE OBJECT'" " UNION SELECT 'LARGE OBJECT'"
" UNION SELECT 'SCHEMA'" " UNION SELECT 'SCHEMA'"
" UNION SELECT 'TABLESPACE'"); " UNION SELECT 'TABLESPACE'"
" UNION SELECT 'TYPE'");
else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 || else if ((pg_strcasecmp(prev4_wd, "GRANT") == 0 ||
pg_strcasecmp(prev4_wd, "REVOKE") == 0) && pg_strcasecmp(prev4_wd, "REVOKE") == 0) &&
pg_strcasecmp(prev2_wd, "ON") == 0 && pg_strcasecmp(prev2_wd, "ON") == 0 &&
...@@ -2266,6 +2268,8 @@ psql_completion(char *text, int start, int end) ...@@ -2266,6 +2268,8 @@ psql_completion(char *text, int start, int end)
{ {
if (pg_strcasecmp(prev_wd, "DATABASE") == 0) if (pg_strcasecmp(prev_wd, "DATABASE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_databases); COMPLETE_WITH_QUERY(Query_for_list_of_databases);
else if (pg_strcasecmp(prev_wd, "DOMAIN") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0) else if (pg_strcasecmp(prev_wd, "FUNCTION") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL); COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0) else if (pg_strcasecmp(prev_wd, "LANGUAGE") == 0)
...@@ -2274,6 +2278,8 @@ psql_completion(char *text, int start, int end) ...@@ -2274,6 +2278,8 @@ psql_completion(char *text, int start, int end)
COMPLETE_WITH_QUERY(Query_for_list_of_schemas); COMPLETE_WITH_QUERY(Query_for_list_of_schemas);
else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0) else if (pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces); COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
else if (pg_strcasecmp(prev_wd, "TYPE") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
else if (pg_strcasecmp(prev4_wd, "GRANT") == 0) else if (pg_strcasecmp(prev4_wd, "GRANT") == 0)
COMPLETE_WITH_CONST("TO"); COMPLETE_WITH_CONST("TO");
else else
......
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201112191 #define CATALOG_VERSION_NO 201112192
#endif #endif
...@@ -133,7 +133,7 @@ typedef FormData_pg_class *Form_pg_class; ...@@ -133,7 +133,7 @@ typedef FormData_pg_class *Form_pg_class;
*/ */
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ )); DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 30 0 t f f f f 3 _null_ _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 _null_ _null_ )); DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 _null_ _null_ ));
DESCR(""); DESCR("");
......
...@@ -71,5 +71,6 @@ typedef FormData_pg_default_acl *Form_pg_default_acl; ...@@ -71,5 +71,6 @@ typedef FormData_pg_default_acl *Form_pg_default_acl;
#define DEFACLOBJ_RELATION 'r' /* table, view */ #define DEFACLOBJ_RELATION 'r' /* table, view */
#define DEFACLOBJ_SEQUENCE 'S' /* sequence */ #define DEFACLOBJ_SEQUENCE 'S' /* sequence */
#define DEFACLOBJ_FUNCTION 'f' /* function */ #define DEFACLOBJ_FUNCTION 'f' /* function */
#define DEFACLOBJ_TYPE 'T' /* type */
#endif /* PG_DEFAULT_ACL_H */ #endif /* PG_DEFAULT_ACL_H */
...@@ -3311,6 +3311,19 @@ DESCR("current user privilege on server by server name"); ...@@ -3311,6 +3311,19 @@ DESCR("current user privilege on server by server name");
DATA(insert OID = 3011 ( has_server_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_server_privilege_id _null_ _null_ _null_ )); DATA(insert OID = 3011 ( has_server_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_server_privilege_id _null_ _null_ _null_ ));
DESCR("current user privilege on server by server oid"); DESCR("current user privilege on server by server oid");
DATA(insert OID = 3138 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ has_type_privilege_name_name _null_ _null_ _null_ ));
DESCR("user privilege on type by username, type name");
DATA(insert OID = 3139 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ has_type_privilege_name_id _null_ _null_ _null_ ));
DESCR("user privilege on type by username, type oid");
DATA(insert OID = 3140 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ has_type_privilege_id_name _null_ _null_ _null_ ));
DESCR("user privilege on type by user oid, type name");
DATA(insert OID = 3141 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ has_type_privilege_id_id _null_ _null_ _null_ ));
DESCR("user privilege on type by user oid, type oid");
DATA(insert OID = 3142 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 16 "25 25" _null_ _null_ _null_ _null_ has_type_privilege_name _null_ _null_ _null_ ));
DESCR("current user privilege on type by type name");
DATA(insert OID = 3143 ( has_type_privilege PGNSP PGUID 12 1 0 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_type_privilege_id _null_ _null_ _null_ ));
DESCR("current user privilege on type by type oid");
DATA(insert OID = 2705 ( pg_has_role PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 19 25" _null_ _null_ _null_ _null_ pg_has_role_name_name _null_ _null_ _null_ )); DATA(insert OID = 2705 ( pg_has_role PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 19 25" _null_ _null_ _null_ _null_ pg_has_role_name_name _null_ _null_ _null_ ));
DESCR("user privilege on role by username, role name"); DESCR("user privilege on role by username, role name");
DATA(insert OID = 2706 ( pg_has_role PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ pg_has_role_name_id _null_ _null_ _null_ )); DATA(insert OID = 2706 ( pg_has_role PGNSP PGUID 12 1 0 0 0 f f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ pg_has_role_name_id _null_ _null_ _null_ ));
......
This diff is collapsed.
...@@ -1282,13 +1282,15 @@ typedef enum GrantObjectType ...@@ -1282,13 +1282,15 @@ typedef enum GrantObjectType
ACL_OBJECT_RELATION, /* table, view */ ACL_OBJECT_RELATION, /* table, view */
ACL_OBJECT_SEQUENCE, /* sequence */ ACL_OBJECT_SEQUENCE, /* sequence */
ACL_OBJECT_DATABASE, /* database */ ACL_OBJECT_DATABASE, /* database */
ACL_OBJECT_DOMAIN, /* domain */
ACL_OBJECT_FDW, /* foreign-data wrapper */ ACL_OBJECT_FDW, /* foreign-data wrapper */
ACL_OBJECT_FOREIGN_SERVER, /* foreign server */ ACL_OBJECT_FOREIGN_SERVER, /* foreign server */
ACL_OBJECT_FUNCTION, /* function */ ACL_OBJECT_FUNCTION, /* function */
ACL_OBJECT_LANGUAGE, /* procedural language */ ACL_OBJECT_LANGUAGE, /* procedural language */
ACL_OBJECT_LARGEOBJECT, /* largeobject */ ACL_OBJECT_LARGEOBJECT, /* largeobject */
ACL_OBJECT_NAMESPACE, /* namespace */ ACL_OBJECT_NAMESPACE, /* namespace */
ACL_OBJECT_TABLESPACE /* tablespace */ ACL_OBJECT_TABLESPACE, /* tablespace */
ACL_OBJECT_TYPE /* type */
} GrantObjectType; } GrantObjectType;
typedef struct GrantStmt typedef struct GrantStmt
......
...@@ -373,6 +373,7 @@ PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD) ...@@ -373,6 +373,7 @@ PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD)
PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD) PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD)
PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD) PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD)
PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD) PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD)
PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD) PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD)
PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD) PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD)
PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD) PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD)
......
...@@ -155,6 +155,7 @@ typedef ArrayType Acl; ...@@ -155,6 +155,7 @@ typedef ArrayType Acl;
#define ACL_ALL_RIGHTS_LARGEOBJECT (ACL_SELECT|ACL_UPDATE) #define ACL_ALL_RIGHTS_LARGEOBJECT (ACL_SELECT|ACL_UPDATE)
#define ACL_ALL_RIGHTS_NAMESPACE (ACL_USAGE|ACL_CREATE) #define ACL_ALL_RIGHTS_NAMESPACE (ACL_USAGE|ACL_CREATE)
#define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE) #define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE)
#define ACL_ALL_RIGHTS_TYPE (ACL_USAGE)
/* operation codes for pg_*_aclmask */ /* operation codes for pg_*_aclmask */
typedef enum typedef enum
...@@ -275,6 +276,8 @@ extern AclMode pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid, ...@@ -275,6 +276,8 @@ extern AclMode pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid,
AclMode mask, AclMaskHow how); AclMode mask, AclMaskHow how);
extern AclMode pg_foreign_server_aclmask(Oid srv_oid, Oid roleid, extern AclMode pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
AclMode mask, AclMaskHow how); AclMode mask, AclMaskHow how);
extern AclMode pg_type_aclmask(Oid type_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, extern AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
Oid roleid, AclMode mode); Oid roleid, AclMode mode);
...@@ -290,6 +293,7 @@ extern AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode); ...@@ -290,6 +293,7 @@ extern AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode);
extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode); extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode);
extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode); extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode);
extern AclResult pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode); extern AclResult pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode);
extern AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode);
extern void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, extern void aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
const char *objectname); const char *objectname);
......
...@@ -94,6 +94,12 @@ extern Datum has_tablespace_privilege_id_name(PG_FUNCTION_ARGS); ...@@ -94,6 +94,12 @@ extern Datum has_tablespace_privilege_id_name(PG_FUNCTION_ARGS);
extern Datum has_tablespace_privilege_id_id(PG_FUNCTION_ARGS); extern Datum has_tablespace_privilege_id_id(PG_FUNCTION_ARGS);
extern Datum has_tablespace_privilege_name(PG_FUNCTION_ARGS); extern Datum has_tablespace_privilege_name(PG_FUNCTION_ARGS);
extern Datum has_tablespace_privilege_id(PG_FUNCTION_ARGS); extern Datum has_tablespace_privilege_id(PG_FUNCTION_ARGS);
extern Datum has_type_privilege_name_name(PG_FUNCTION_ARGS);
extern Datum has_type_privilege_name_id(PG_FUNCTION_ARGS);
extern Datum has_type_privilege_id_name(PG_FUNCTION_ARGS);
extern Datum has_type_privilege_id_id(PG_FUNCTION_ARGS);
extern Datum has_type_privilege_name(PG_FUNCTION_ARGS);
extern Datum has_type_privilege_id(PG_FUNCTION_ARGS);
extern Datum pg_has_role_name_name(PG_FUNCTION_ARGS); extern Datum pg_has_role_name_name(PG_FUNCTION_ARGS);
extern Datum pg_has_role_name_id(PG_FUNCTION_ARGS); extern Datum pg_has_role_name_id(PG_FUNCTION_ARGS);
extern Datum pg_has_role_id_name(PG_FUNCTION_ARGS); extern Datum pg_has_role_id_name(PG_FUNCTION_ARGS);
......
...@@ -509,6 +509,102 @@ ERROR: must be owner of function testfunc1 ...@@ -509,6 +509,102 @@ ERROR: must be owner of function testfunc1
DROP FUNCTION testfunc1(int); -- ok DROP FUNCTION testfunc1(int); -- ok
-- restore to sanity -- restore to sanity
GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC; GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC;
-- privileges on types
-- switch to superuser
\c -
CREATE TYPE testtype1 AS (a int, b text);
REVOKE USAGE ON TYPE testtype1 FROM PUBLIC;
GRANT USAGE ON TYPE testtype1 TO regressuser2;
GRANT USAGE ON TYPE _testtype1 TO regressuser2; -- fail
ERROR: cannot set privileges of array types
HINT: Set the privileges of the element type instead.
GRANT USAGE ON DOMAIN testtype1 TO regressuser2; -- fail
ERROR: "testtype1" is not a domain
CREATE DOMAIN testdomain1 AS int;
REVOKE USAGE on DOMAIN testdomain1 FROM PUBLIC;
GRANT USAGE ON DOMAIN testdomain1 TO regressuser2;
GRANT USAGE ON TYPE testdomain1 TO regressuser2; -- ok
SET SESSION AUTHORIZATION regressuser1;
-- commands that should fail
CREATE AGGREGATE testagg1a(testdomain1) (sfunc = int4_sum, stype = bigint);
ERROR: permission denied for type testdomain1
CREATE DOMAIN testdomain2a AS testdomain1;
ERROR: permission denied for type testdomain1
CREATE DOMAIN testdomain3a AS int;
CREATE FUNCTION castfunc(int) RETURNS testdomain3a AS $$ SELECT $1::testdomain3a $$ LANGUAGE SQL;
CREATE CAST (testdomain1 AS testdomain3a) WITH FUNCTION castfunc(int);
ERROR: permission denied for type testdomain1
DROP FUNCTION castfunc(int) CASCADE;
DROP DOMAIN testdomain3a;
CREATE FUNCTION testfunc5a(a testdomain1) RETURNS int LANGUAGE SQL AS $$ SELECT $1 $$;
ERROR: permission denied for type testdomain1
CREATE FUNCTION testfunc6a(b int) RETURNS testdomain1 LANGUAGE SQL AS $$ SELECT $1::testdomain1 $$;
ERROR: permission denied for type testdomain1
CREATE OPERATOR !+! (PROCEDURE = int4pl, LEFTARG = testdomain1, RIGHTARG = testdomain1);
ERROR: permission denied for type testdomain1
CREATE TABLE test5a (a int, b testdomain1);
ERROR: permission denied for type testdomain1
CREATE TABLE test6a OF testtype1;
ERROR: permission denied for type testtype1
CREATE TABLE test10a (a int[], b testtype1[]);
ERROR: permission denied for type testtype1[]
CREATE TABLE test9a (a int, b int);
ALTER TABLE test9a ADD COLUMN c testdomain1;
ERROR: permission denied for type testdomain1
ALTER TABLE test9a ALTER COLUMN b TYPE testdomain1;
ERROR: permission denied for type testdomain1
CREATE TYPE test7a AS (a int, b testdomain1);
ERROR: permission denied for type testdomain1
CREATE TYPE test8a AS (a int, b int);
ALTER TYPE test8a ADD ATTRIBUTE c testdomain1;
ERROR: permission denied for type testdomain1
ALTER TYPE test8a ALTER ATTRIBUTE b TYPE testdomain1;
ERROR: permission denied for type testdomain1
CREATE TABLE test11a AS (SELECT 1::testdomain1 AS a);
ERROR: permission denied for type testdomain1
REVOKE ALL ON TYPE testtype1 FROM PUBLIC;
ERROR: permission denied for type testtype1
SET SESSION AUTHORIZATION regressuser2;
-- commands that should succeed
CREATE AGGREGATE testagg1b(testdomain1) (sfunc = int4_sum, stype = bigint);
CREATE DOMAIN testdomain2b AS testdomain1;
CREATE DOMAIN testdomain3b AS int;
CREATE FUNCTION castfunc(int) RETURNS testdomain3b AS $$ SELECT $1::testdomain3b $$ LANGUAGE SQL;
CREATE CAST (testdomain1 AS testdomain3b) WITH FUNCTION castfunc(int);
CREATE FUNCTION testfunc5b(a testdomain1) RETURNS int LANGUAGE SQL AS $$ SELECT $1 $$;
CREATE FUNCTION testfunc6b(b int) RETURNS testdomain1 LANGUAGE SQL AS $$ SELECT $1::testdomain1 $$;
CREATE OPERATOR !! (PROCEDURE = testfunc5b, RIGHTARG = testdomain1);
CREATE TABLE test5b (a int, b testdomain1);
CREATE TABLE test6b OF testtype1;
CREATE TABLE test10b (a int[], b testtype1[]);
CREATE TABLE test9b (a int, b int);
ALTER TABLE test9b ADD COLUMN c testdomain1;
ALTER TABLE test9b ALTER COLUMN b TYPE testdomain1;
CREATE TYPE test7b AS (a int, b testdomain1);
CREATE TYPE test8b AS (a int, b int);
ALTER TYPE test8b ADD ATTRIBUTE c testdomain1;
ALTER TYPE test8b ALTER ATTRIBUTE b TYPE testdomain1;
CREATE TABLE test11b AS (SELECT 1::testdomain1 AS a);
REVOKE ALL ON TYPE testtype1 FROM PUBLIC;
WARNING: no privileges could be revoked for "testtype1"
\c -
DROP AGGREGATE testagg1b(testdomain1);
DROP DOMAIN testdomain2b;
DROP OPERATOR !! (NONE, testdomain1);
DROP FUNCTION testfunc5b(a testdomain1);
DROP FUNCTION testfunc6b(b int);
DROP TABLE test5b;
DROP TABLE test6b;
DROP TABLE test9b;
DROP TABLE test10b;
DROP TYPE test7b;
DROP TYPE test8b;
DROP CAST (testdomain1 AS testdomain3b);
DROP FUNCTION castfunc(int) CASCADE;
DROP DOMAIN testdomain3b;
DROP TABLE test11b;
DROP TYPE testtype1; -- ok
DROP DOMAIN testdomain1; -- ok
-- truncate -- truncate
SET SESSION AUTHORIZATION regressuser5; SET SESSION AUTHORIZATION regressuser5;
TRUNCATE atest2; -- ok TRUNCATE atest2; -- ok
...@@ -1144,13 +1240,31 @@ SELECT has_function_privilege('regressuser2', 'testns.foo()', 'EXECUTE'); -- yes ...@@ -1144,13 +1240,31 @@ SELECT has_function_privilege('regressuser2', 'testns.foo()', 'EXECUTE'); -- yes
(1 row) (1 row)
DROP FUNCTION testns.foo(); DROP FUNCTION testns.foo();
ALTER DEFAULT PRIVILEGES FOR ROLE regressuser1 REVOKE USAGE ON TYPES FROM public;
CREATE DOMAIN testns.testdomain1 AS int;
SELECT has_type_privilege('regressuser2', 'testns.testdomain1', 'USAGE'); -- no
has_type_privilege
--------------------
f
(1 row)
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON TYPES to public;
DROP DOMAIN testns.testdomain1;
CREATE DOMAIN testns.testdomain1 AS int;
SELECT has_type_privilege('regressuser2', 'testns.testdomain1', 'USAGE'); -- yes
has_type_privilege
--------------------
t
(1 row)
DROP DOMAIN testns.testdomain1;
RESET ROLE; RESET ROLE;
SELECT count(*) SELECT count(*)
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
WHERE nspname = 'testns'; WHERE nspname = 'testns';
count count
------- -------
2 3
(1 row) (1 row)
DROP SCHEMA testns CASCADE; DROP SCHEMA testns CASCADE;
......
...@@ -338,6 +338,115 @@ DROP FUNCTION testfunc1(int); -- ok ...@@ -338,6 +338,115 @@ DROP FUNCTION testfunc1(int); -- ok
-- restore to sanity -- restore to sanity
GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC; GRANT ALL PRIVILEGES ON LANGUAGE sql TO PUBLIC;
-- privileges on types
-- switch to superuser
\c -
CREATE TYPE testtype1 AS (a int, b text);
REVOKE USAGE ON TYPE testtype1 FROM PUBLIC;
GRANT USAGE ON TYPE testtype1 TO regressuser2;
GRANT USAGE ON TYPE _testtype1 TO regressuser2; -- fail
GRANT USAGE ON DOMAIN testtype1 TO regressuser2; -- fail
CREATE DOMAIN testdomain1 AS int;
REVOKE USAGE on DOMAIN testdomain1 FROM PUBLIC;
GRANT USAGE ON DOMAIN testdomain1 TO regressuser2;
GRANT USAGE ON TYPE testdomain1 TO regressuser2; -- ok
SET SESSION AUTHORIZATION regressuser1;
-- commands that should fail
CREATE AGGREGATE testagg1a(testdomain1) (sfunc = int4_sum, stype = bigint);
CREATE DOMAIN testdomain2a AS testdomain1;
CREATE DOMAIN testdomain3a AS int;
CREATE FUNCTION castfunc(int) RETURNS testdomain3a AS $$ SELECT $1::testdomain3a $$ LANGUAGE SQL;
CREATE CAST (testdomain1 AS testdomain3a) WITH FUNCTION castfunc(int);
DROP FUNCTION castfunc(int) CASCADE;
DROP DOMAIN testdomain3a;
CREATE FUNCTION testfunc5a(a testdomain1) RETURNS int LANGUAGE SQL AS $$ SELECT $1 $$;
CREATE FUNCTION testfunc6a(b int) RETURNS testdomain1 LANGUAGE SQL AS $$ SELECT $1::testdomain1 $$;
CREATE OPERATOR !+! (PROCEDURE = int4pl, LEFTARG = testdomain1, RIGHTARG = testdomain1);
CREATE TABLE test5a (a int, b testdomain1);
CREATE TABLE test6a OF testtype1;
CREATE TABLE test10a (a int[], b testtype1[]);
CREATE TABLE test9a (a int, b int);
ALTER TABLE test9a ADD COLUMN c testdomain1;
ALTER TABLE test9a ALTER COLUMN b TYPE testdomain1;
CREATE TYPE test7a AS (a int, b testdomain1);
CREATE TYPE test8a AS (a int, b int);
ALTER TYPE test8a ADD ATTRIBUTE c testdomain1;
ALTER TYPE test8a ALTER ATTRIBUTE b TYPE testdomain1;
CREATE TABLE test11a AS (SELECT 1::testdomain1 AS a);
REVOKE ALL ON TYPE testtype1 FROM PUBLIC;
SET SESSION AUTHORIZATION regressuser2;
-- commands that should succeed
CREATE AGGREGATE testagg1b(testdomain1) (sfunc = int4_sum, stype = bigint);
CREATE DOMAIN testdomain2b AS testdomain1;
CREATE DOMAIN testdomain3b AS int;
CREATE FUNCTION castfunc(int) RETURNS testdomain3b AS $$ SELECT $1::testdomain3b $$ LANGUAGE SQL;
CREATE CAST (testdomain1 AS testdomain3b) WITH FUNCTION castfunc(int);
CREATE FUNCTION testfunc5b(a testdomain1) RETURNS int LANGUAGE SQL AS $$ SELECT $1 $$;
CREATE FUNCTION testfunc6b(b int) RETURNS testdomain1 LANGUAGE SQL AS $$ SELECT $1::testdomain1 $$;
CREATE OPERATOR !! (PROCEDURE = testfunc5b, RIGHTARG = testdomain1);
CREATE TABLE test5b (a int, b testdomain1);
CREATE TABLE test6b OF testtype1;
CREATE TABLE test10b (a int[], b testtype1[]);
CREATE TABLE test9b (a int, b int);
ALTER TABLE test9b ADD COLUMN c testdomain1;
ALTER TABLE test9b ALTER COLUMN b TYPE testdomain1;
CREATE TYPE test7b AS (a int, b testdomain1);
CREATE TYPE test8b AS (a int, b int);
ALTER TYPE test8b ADD ATTRIBUTE c testdomain1;
ALTER TYPE test8b ALTER ATTRIBUTE b TYPE testdomain1;
CREATE TABLE test11b AS (SELECT 1::testdomain1 AS a);
REVOKE ALL ON TYPE testtype1 FROM PUBLIC;
\c -
DROP AGGREGATE testagg1b(testdomain1);
DROP DOMAIN testdomain2b;
DROP OPERATOR !! (NONE, testdomain1);
DROP FUNCTION testfunc5b(a testdomain1);
DROP FUNCTION testfunc6b(b int);
DROP TABLE test5b;
DROP TABLE test6b;
DROP TABLE test9b;
DROP TABLE test10b;
DROP TYPE test7b;
DROP TYPE test8b;
DROP CAST (testdomain1 AS testdomain3b);
DROP FUNCTION castfunc(int) CASCADE;
DROP DOMAIN testdomain3b;
DROP TABLE test11b;
DROP TYPE testtype1; -- ok
DROP DOMAIN testdomain1; -- ok
-- truncate -- truncate
SET SESSION AUTHORIZATION regressuser5; SET SESSION AUTHORIZATION regressuser5;
TRUNCATE atest2; -- ok TRUNCATE atest2; -- ok
...@@ -626,6 +735,21 @@ SELECT has_function_privilege('regressuser2', 'testns.foo()', 'EXECUTE'); -- yes ...@@ -626,6 +735,21 @@ SELECT has_function_privilege('regressuser2', 'testns.foo()', 'EXECUTE'); -- yes
DROP FUNCTION testns.foo(); DROP FUNCTION testns.foo();
ALTER DEFAULT PRIVILEGES FOR ROLE regressuser1 REVOKE USAGE ON TYPES FROM public;
CREATE DOMAIN testns.testdomain1 AS int;
SELECT has_type_privilege('regressuser2', 'testns.testdomain1', 'USAGE'); -- no
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT USAGE ON TYPES to public;
DROP DOMAIN testns.testdomain1;
CREATE DOMAIN testns.testdomain1 AS int;
SELECT has_type_privilege('regressuser2', 'testns.testdomain1', 'USAGE'); -- yes
DROP DOMAIN testns.testdomain1;
RESET ROLE; RESET ROLE;
SELECT count(*) SELECT count(*)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment