Commit 7449427a authored by Tom Lane's avatar Tom Lane

Clean up some loose ends from the column privileges patch: add

has_column_privilege and has_any_column_privilege SQL functions; fix the
information_schema views that are supposed to pay attention to column
privileges; adjust pg_stats to show stats for any column you have select
privilege on; and fix COPY to allow copying a subset of columns if the user
has suitable per-column privileges for all the columns.

To improve efficiency of some of the information_schema views, extend the
has_xxx_privilege functions to allow inquiring about the OR of a set of
privileges in just one call.  This is just exposing capability that already
existed in the underlying aclcheck routines.

In passing, make the information_schema views report the owner's own
privileges as being grantable, since Postgres assumes this even when the grant
option bit is not set in the ACL.  This is a longstanding oversight.

Also, make the new has_xxx_privilege functions for foreign data objects follow
the same coding conventions used by the older ones.

Stephen Frost and Tom Lane
parent 0274e1b9
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.470 2009/01/15 18:19:58 heikki Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.471 2009/02/06 21:15:11 tgl Exp $ -->
<chapter id="functions">
<title>Functions and Operators</title>
......@@ -11599,6 +11599,38 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, ..
</thead>
<tbody>
<row>
<entry><literal><function>has_any_column_privilege</function>(<parameter>user</parameter>,
<parameter>table</parameter>,
<parameter>privilege</parameter>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>does user have privilege for any column of table</entry>
</row>
<row>
<entry><literal><function>has_any_column_privilege</function>(<parameter>table</parameter>,
<parameter>privilege</parameter>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>does current user have privilege for any column of table</entry>
</row>
<row>
<entry><literal><function>has_column_privilege</function>(<parameter>user</parameter>,
<parameter>table</parameter>,
<parameter>column</parameter>,
<parameter>privilege</parameter>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>does user have privilege for column</entry>
</row>
<row>
<entry><literal><function>has_column_privilege</function>(<parameter>table</parameter>,
<parameter>column</parameter>,
<parameter>privilege</parameter>)</literal>
</entry>
<entry><type>boolean</type></entry>
<entry>does current user have privilege for column</entry>
</row>
<row>
<entry><literal><function>has_database_privilege</function>(<parameter>user</parameter>,
<parameter>database</parameter>,
......@@ -11738,6 +11770,12 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, ..
</tgroup>
</table>
<indexterm>
<primary>has_any_column_privilege</primary>
</indexterm>
<indexterm>
<primary>has_column_privilege</primary>
</indexterm>
<indexterm>
<primary>has_database_privilege</primary>
</indexterm>
......@@ -11766,11 +11804,71 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, ..
<primary>pg_has_role</primary>
</indexterm>
<para>
<function>has_table_privilege</function> checks whether a user
can access a table in a particular way. The user can be
specified by name or by OID
(<literal>pg_authid.oid</literal>), or if the argument is
omitted
<function>current_user</function> is assumed. The table can be specified
by name or by OID. (Thus, there are actually six variants of
<function>has_table_privilege</function>, which can be distinguished by
the number and types of their arguments.) When specifying by name,
the name can be schema-qualified if necessary.
The desired access privilege type
is specified by a text string, which must evaluate to one of the
values <literal>SELECT</literal>, <literal>INSERT</literal>,
<literal>UPDATE</literal>, <literal>DELETE</literal>, <literal>TRUNCATE</>,
<literal>REFERENCES</literal>, or <literal>TRIGGER</literal>. Optionally,
<literal>WITH GRANT OPTION</> can be added to a privilege type to test
whether the privilege is held with grant option. Also, multiple privilege
types can be listed separated by commas, in which case the result will
be <literal>true</> if any of the listed privileges is held.
(Case of the privilege string is not significant, and extra whitespace
is allowed between but not within privilege names.)
Some examples:
<programlisting>
SELECT has_table_privilege('myschema.mytable', 'select');
SELECT has_table_privilege('joe', 'mytable', 'INSERT, SELECT WITH GRANT OPTION');
</programlisting>
</para>
<para>
<function>has_any_column_privilege</function> checks whether a user can
access any column of a table in a particular way. The possibilities for
its arguments are the same as for <function>has_table_privilege</>,
except that the desired access privilege type must evaluate to some
combination of
<literal>SELECT</literal>,
<literal>INSERT</literal>,
<literal>UPDATE</literal>, or
<literal>REFERENCES</literal>. Note that having any of these privileges
at the table level implicitly grants it for each column of the table,
so <function>has_any_column_privilege</function> will always return
<literal>true</> if <function>has_table_privilege</> does for the same
arguments. But <function>has_any_column_privilege</> also succeeds if
there is a column-level grant of the privilege for at least one column.
</para>
<para>
<function>has_column_privilege</function> checks whether a user
can access a column in a particular way. The possibilities for its
arguments are analogous to <function>has_table_privilege</function>,
with the addition that the column can be specified either by name
or attribute number.
The desired access privilege type must evaluate to some combination of
<literal>SELECT</literal>,
<literal>INSERT</literal>,
<literal>UPDATE</literal>, or
<literal>REFERENCES</literal>. Note that having any of these privileges
at the table level implicitly grants it for each column of the table.
</para>
<para>
<function>has_database_privilege</function> checks whether a user
can access a database in a particular way. The possibilities for its
arguments are analogous to <function>has_table_privilege</function>.
The desired access privilege type must evaluate to
The desired access privilege type must evaluate to some combination of
<literal>CREATE</literal>,
<literal>CONNECT</literal>,
<literal>TEMPORARY</literal>, or
......@@ -11813,7 +11911,7 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
<function>has_schema_privilege</function> checks whether a user
can access a schema in a particular way. The possibilities for its
arguments are analogous to <function>has_table_privilege</function>.
The desired access privilege type must evaluate to
The desired access privilege type must evaluate to some combination of
<literal>CREATE</literal> or
<literal>USAGE</literal>.
</para>
......@@ -11826,29 +11924,6 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
<literal>USAGE</literal>.
</para>
<para>
<function>has_table_privilege</function> checks whether a user
can access a table in a particular way. The user can be
specified by name or by OID
(<literal>pg_authid.oid</literal>), or if the argument is
omitted
<function>current_user</function> is assumed. The table can be specified
by name or by OID. (Thus, there are actually six variants of
<function>has_table_privilege</function>, which can be distinguished by
the number and types of their arguments.) When specifying by name,
the name can be schema-qualified if necessary.
The desired access privilege type
is specified by a text string, which must evaluate to one of the
values <literal>SELECT</literal>, <literal>INSERT</literal>,
<literal>UPDATE</literal>, <literal>DELETE</literal>, <literal>TRUNCATE</>,
<literal>REFERENCES</literal>, or <literal>TRIGGER</literal>.
(Case of the string is not significant, however.)
An example is:
<programlisting>
SELECT has_table_privilege('myschema.mytable', 'select');
</programlisting>
</para>
<para>
<function>has_tablespace_privilege</function> checks whether a user
can access a tablespace in a particular way. The possibilities for its
......@@ -11861,7 +11936,7 @@ SELECT has_table_privilege('myschema.mytable', 'select');
<function>pg_has_role</function> checks whether a user
can access a role in a particular way. The possibilities for its
arguments are analogous to <function>has_table_privilege</function>.
The desired access privilege type must evaluate to
The desired access privilege type must evaluate to some combination of
<literal>MEMBER</literal> or
<literal>USAGE</literal>.
<literal>MEMBER</literal> denotes direct or indirect membership in
......@@ -11870,12 +11945,6 @@ SELECT has_table_privilege('myschema.mytable', 'select');
are immediately available without doing <command>SET ROLE</>.
</para>
<para>
To test whether a user holds a grant option on the privilege,
append <literal>WITH GRANT OPTION</literal> to the privilege key
word; for example <literal>'UPDATE WITH GRANT OPTION'</literal>.
</para>
<para>
<xref linkend="functions-info-schema-table"> shows functions that
determine whether a certain object is <firstterm>visible</> in the
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/information_schema.sgml,v 1.37 2009/01/20 09:10:20 petere Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/information_schema.sgml,v 1.38 2009/02/06 21:15:11 tgl Exp $ -->
<chapter id="information-schema">
<title>The Information Schema</title>
......@@ -686,18 +686,11 @@
</para>
<para>
In <productname>PostgreSQL</productname>, you can only grant
privileges on entire tables, not individual columns. Therefore,
this view contains the same information as
<literal>table_privileges</literal>, just represented through one
row for each column in each appropriate table, but it only covers
If a privilege has been granted on an entire table, it will show up in
this view as a grant for each column, but only for the
privilege types where column granularity is possible:
<literal>SELECT</literal>, <literal>INSERT</literal>,
<literal>UPDATE</literal>, <literal>REFERENCES</literal>. If you
want to make your applications fit for possible future
developments, it is generally the right choice to use this view
instead of <literal>table_privileges</literal> if one of those
privilege types is concerned.
<literal>UPDATE</literal>, <literal>REFERENCES</literal>.
</para>
<table>
......@@ -2727,8 +2720,10 @@ ORDER BY c.ordinal_position;
<para>
The view <literal>referential_constraints</literal> contains all
referential (foreign key) constraints in the current database that
belong to a table owned by a currently enabled role.
referential (foreign key) constraints in the current database.
Only those constraints are shown for which the current user has
write access to the referencing table (by way of being the
owner or having some privilege other than SELECT).
</para>
<table>
......@@ -3157,8 +3152,8 @@ ORDER BY c.ordinal_position;
<para>
The view <literal>routine_privileges</literal> identifies all
privileges granted to a currently enabled role or by a currently
enabled role. There is one row for each combination of function,
privileges granted on functions to a currently enabled role or by a
currently enabled role. There is one row for each combination of function,
grantor, and grantee.
</para>
......@@ -4500,7 +4495,7 @@ ORDER BY c.ordinal_position;
<para>
The view <literal>table_constraints</literal> contains all
constraints belonging to tables that the current user owns or has
some privilege on.
some non-SELECT privilege on.
</para>
<table>
......@@ -4777,7 +4772,7 @@ ORDER BY c.ordinal_position;
<para>
The view <literal>triggers</literal> contains all triggers defined
in the current database on tables that the current user owns or has
some privilege on.
some non-SELECT privilege on.
</para>
<table>
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.152 2009/01/22 20:16:00 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.153 2009/02/06 21:15:11 tgl Exp $
*
* NOTES
* See acl.h.
......@@ -2292,22 +2292,7 @@ pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
Oid ownerId;
/*
* Must get the relation's tuple from pg_class (only needed for ownerId)
*/
classTuple = SearchSysCache(RELOID,
ObjectIdGetDatum(table_oid),
0, 0, 0);
if (!HeapTupleIsValid(classTuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation with OID %u does not exist",
table_oid)));
classForm = (Form_pg_class) GETSTRUCT(classTuple);
ownerId = classForm->relowner;
/*
* Next, get the column's ACL from pg_attribute
* First, get the column's ACL from its pg_attribute entry
*/
attTuple = SearchSysCache(ATTNUM,
ObjectIdGetDatum(table_oid),
......@@ -2330,17 +2315,41 @@ pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
&isNull);
/*
* Here we hard-wire knowledge that the default ACL for a column
* grants no privileges, so that we can fall out quickly in the
* very common case where attacl is null.
*/
if (isNull)
{
/* No ACL, so build default ACL */
acl = acldefault(ACL_OBJECT_COLUMN, ownerId);
aclDatum = (Datum) 0;
ReleaseSysCache(attTuple);
return 0;
}
else
/*
* Must get the relation's ownerId from pg_class. Since we already found
* a pg_attribute entry, the only likely reason for this to fail is that
* a concurrent DROP of the relation committed since then (which could
* only happen if we don't have lock on the relation). We prefer to
* report "no privileges" rather than failing in such a case, so as to
* avoid unwanted failures in has_column_privilege() tests.
*/
classTuple = SearchSysCache(RELOID,
ObjectIdGetDatum(table_oid),
0, 0, 0);
if (!HeapTupleIsValid(classTuple))
{
/* detoast column's ACL if necessary */
acl = DatumGetAclP(aclDatum);
ReleaseSysCache(attTuple);
return 0;
}
classForm = (Form_pg_class) GETSTRUCT(classTuple);
ownerId = classForm->relowner;
ReleaseSysCache(classTuple);
/* detoast column's ACL if necessary */
acl = DatumGetAclP(aclDatum);
result = aclmask(acl, roleid, ownerId, mask, how);
......@@ -2349,7 +2358,6 @@ pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
pfree(acl);
ReleaseSysCache(attTuple);
ReleaseSysCache(classTuple);
return result;
}
......@@ -2922,7 +2930,7 @@ pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
* ACLCHECK_NO_PRIV).
*
* If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
* privileges identified by 'mode' on all non-dropped columns in the relation
* privileges identified by 'mode' on each non-dropped column in the relation
* (and there must be at least one such column); otherwise returns a suitable
* error code (in practice, always ACLCHECK_NO_PRIV).
*
......@@ -2942,15 +2950,16 @@ pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
AttrNumber nattrs;
AttrNumber curr_att;
/* Must fetch pg_class row to check number of attributes */
/*
* Must fetch pg_class row to check number of attributes. As in
* pg_attribute_aclmask, we prefer to return "no privileges" instead
* of throwing an error if we get any unexpected lookup errors.
*/
classTuple = SearchSysCache(RELOID,
ObjectIdGetDatum(table_oid),
0, 0, 0);
if (!HeapTupleIsValid(classTuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation with OID %u does not exist",
table_oid)));
return ACLCHECK_NO_PRIV;
classForm = (Form_pg_class) GETSTRUCT(classTuple);
nattrs = classForm->relnatts;
......@@ -2966,26 +2975,36 @@ pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
for (curr_att = 1; curr_att <= nattrs; curr_att++)
{
HeapTuple attTuple;
bool isdropped;
AclMode attmask;
attTuple = SearchSysCache(ATTNUM,
ObjectIdGetDatum(table_oid),
Int16GetDatum(curr_att),
0, 0);
if (!HeapTupleIsValid(attTuple))
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
curr_att, table_oid);
isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
ReleaseSysCache(attTuple);
continue;
/* ignore dropped columns */
if (isdropped)
if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
{
ReleaseSysCache(attTuple);
continue;
}
/*
* Here we hard-wire knowledge that the default ACL for a column
* grants no privileges, so that we can fall out quickly in the
* very common case where attacl is null.
*/
if (heap_attisnull(attTuple, Anum_pg_attribute_attacl))
attmask = 0;
else
attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
mode, ACLMASK_ANY);
ReleaseSysCache(attTuple);
if (pg_attribute_aclmask(table_oid, curr_att, roleid,
mode, ACLMASK_ANY) != 0)
if (attmask != 0)
{
result = ACLCHECK_OK;
if (how == ACLMASK_ANY)
......
......@@ -4,7 +4,7 @@
*
* Copyright (c) 2003-2009, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.50 2009/01/20 09:10:20 petere Exp $
* $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.51 2009/02/06 21:15:11 tgl Exp $
*/
/*
......@@ -494,8 +494,13 @@ CREATE VIEW column_privileges AS
CAST(a.attname AS sql_identifier) AS column_name,
CAST(pr.type AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(c.relacl,
makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, c.relowner, 'USAGE')
OR aclcontains(c.relacl,
makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
OR aclcontains(a.attacl,
makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
FROM pg_attribute a,
......@@ -507,18 +512,20 @@ CREATE VIEW column_privileges AS
UNION ALL
SELECT 0::oid, 'PUBLIC'
) AS grantee (oid, rolname),
(SELECT 'SELECT' UNION ALL
SELECT 'INSERT' UNION ALL
SELECT 'UPDATE' UNION ALL
SELECT 'REFERENCES') AS pr (type)
(VALUES ('SELECT'),
('INSERT'),
('UPDATE'),
('REFERENCES')) AS pr (type)
WHERE a.attrelid = c.oid
AND c.relnamespace = nc.oid
AND a.attnum > 0
AND NOT a.attisdropped
AND c.relkind IN ('r', 'v')
AND aclcontains(c.relacl,
makeaclitem(grantee.oid, u_grantor.oid, pr.type, false))
AND (aclcontains(c.relacl,
makeaclitem(grantee.oid, u_grantor.oid, pr.type, false))
OR aclcontains(a.attacl,
makeaclitem(grantee.oid, u_grantor.oid, pr.type, false)))
AND (pg_has_role(u_grantor.oid, 'USAGE')
OR pg_has_role(grantee.oid, 'USAGE')
OR grantee.rolname = 'PUBLIC');
......@@ -674,10 +681,8 @@ CREATE VIEW columns AS
AND a.attnum > 0 AND NOT a.attisdropped AND c.relkind in ('r', 'v')
AND (pg_has_role(c.relowner, 'USAGE')
OR has_table_privilege(c.oid, 'SELECT')
OR has_table_privilege(c.oid, 'INSERT')
OR has_table_privilege(c.oid, 'UPDATE')
OR has_table_privilege(c.oid, 'REFERENCES') );
OR has_column_privilege(c.oid, a.attnum,
'SELECT, INSERT, UPDATE, REFERENCES'));
GRANT SELECT ON columns TO PUBLIC;
......@@ -954,8 +959,8 @@ CREATE VIEW key_column_usage AS
END AS cardinal_number)
AS position_in_unique_constraint
FROM pg_attribute a,
(SELECT r.oid AS roid, r.relname, nc.nspname AS nc_nspname,
nr.nspname AS nr_nspname,
(SELECT r.oid AS roid, r.relname, r.relowner,
nc.nspname AS nc_nspname, nr.nspname AS nr_nspname,
c.oid AS coid, c.conname, c.contype, c.confkey, c.confrelid,
_pg_expandarray(c.conkey) AS x
FROM pg_namespace nr, pg_class r, pg_namespace nc,
......@@ -965,15 +970,13 @@ CREATE VIEW key_column_usage AS
AND nc.oid = c.connamespace
AND c.contype IN ('p', 'u', 'f')
AND r.relkind = 'r'
AND (NOT pg_is_other_temp_schema(nr.oid))
AND (pg_has_role(r.relowner, 'USAGE')
OR has_table_privilege(r.oid, 'SELECT')
OR has_table_privilege(r.oid, 'INSERT')
OR has_table_privilege(r.oid, 'UPDATE')
OR has_table_privilege(r.oid, 'REFERENCES')) ) AS ss
AND (NOT pg_is_other_temp_schema(nr.oid)) ) AS ss
WHERE ss.roid = a.attrelid
AND a.attnum = (ss.x).x
AND NOT a.attisdropped;
AND NOT a.attisdropped
AND (pg_has_role(relowner, 'USAGE')
OR has_column_privilege(roid, a.attnum,
'SELECT, INSERT, UPDATE, REFERENCES'));
GRANT SELECT ON key_column_usage TO PUBLIC;
......@@ -1114,7 +1117,10 @@ CREATE VIEW referential_constraints AS
WHERE c.relkind = 'r'
AND con.contype = 'f'
AND (pkc.contype IN ('p', 'u') OR pkc.contype IS NULL)
AND pg_has_role(c.relowner, 'USAGE');
AND (pg_has_role(c.relowner, 'USAGE')
-- SELECT privilege omitted, per SQL standard
OR has_table_privilege(c.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
OR has_any_column_privilege(c.oid, 'INSERT, UPDATE, REFERENCES') );
GRANT SELECT ON referential_constraints TO PUBLIC;
......@@ -1133,8 +1139,13 @@ CREATE VIEW role_column_grants AS
CAST(a.attname AS sql_identifier) AS column_name,
CAST(pr.type AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(c.relacl,
makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, true))
CASE WHEN
-- object owner always has grant options
pg_has_role(g_grantee.oid, c.relowner, 'USAGE')
OR aclcontains(c.relacl,
makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, true))
OR aclcontains(a.attacl,
makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
FROM pg_attribute a,
......@@ -1142,18 +1153,20 @@ CREATE VIEW role_column_grants AS
pg_namespace nc,
pg_authid u_grantor,
pg_authid g_grantee,
(SELECT 'SELECT' UNION ALL
SELECT 'INSERT' UNION ALL
SELECT 'UPDATE' UNION ALL
SELECT 'REFERENCES') AS pr (type)
(VALUES ('SELECT'),
('INSERT'),
('UPDATE'),
('REFERENCES')) AS pr (type)
WHERE a.attrelid = c.oid
AND c.relnamespace = nc.oid
AND a.attnum > 0
AND NOT a.attisdropped
AND c.relkind IN ('r', 'v')
AND aclcontains(c.relacl,
makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, false))
AND (aclcontains(c.relacl,
makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, false))
OR aclcontains(a.attacl,
makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, false)))
AND (u_grantor.rolname IN (SELECT role_name FROM enabled_roles)
OR g_grantee.rolname IN (SELECT role_name FROM enabled_roles));
......@@ -1176,8 +1189,11 @@ CREATE VIEW role_routine_grants AS
CAST(p.proname AS sql_identifier) AS routine_name,
CAST('EXECUTE' AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(p.proacl,
makeaclitem(g_grantee.oid, u_grantor.oid, 'EXECUTE', true))
CASE WHEN
-- object owner always has grant options
pg_has_role(g_grantee.oid, p.proowner, 'USAGE')
OR aclcontains(p.proacl,
makeaclitem(g_grantee.oid, u_grantor.oid, 'EXECUTE', true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
FROM pg_proc p,
......@@ -1207,8 +1223,11 @@ CREATE VIEW role_table_grants AS
CAST(c.relname AS sql_identifier) AS table_name,
CAST(pr.type AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(c.relacl,
makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, true))
CASE WHEN
-- object owner always has grant options
pg_has_role(g_grantee.oid, c.relowner, 'USAGE')
OR aclcontains(c.relacl,
makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable,
CAST('NO' AS character_data) AS with_hierarchy
......@@ -1216,13 +1235,13 @@ CREATE VIEW role_table_grants AS
pg_namespace nc,
pg_authid u_grantor,
pg_authid g_grantee,
(SELECT 'SELECT' UNION ALL
SELECT 'INSERT' UNION ALL
SELECT 'UPDATE' UNION ALL
SELECT 'DELETE' UNION ALL
SELECT 'TRUNCATE' UNION ALL
SELECT 'REFERENCES' UNION ALL
SELECT 'TRIGGER') AS pr (type)
(VALUES ('SELECT'),
('INSERT'),
('UPDATE'),
('DELETE'),
('TRUNCATE'),
('REFERENCES'),
('TRIGGER')) AS pr (type)
WHERE c.relnamespace = nc.oid
AND c.relkind IN ('r', 'v')
......@@ -1258,8 +1277,11 @@ CREATE VIEW role_usage_grants AS
CAST('FOREIGN DATA WRAPPER' AS character_data) AS object_type,
CAST('USAGE' AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(fdw.fdwacl,
makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', true))
CASE WHEN
-- object owner always has grant options
pg_has_role(g_grantee.oid, fdw.fdwowner, 'USAGE')
OR aclcontains(fdw.fdwacl,
makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
FROM pg_foreign_data_wrapper fdw,
......@@ -1282,8 +1304,11 @@ CREATE VIEW role_usage_grants AS
CAST('FOREIGN SERVER' AS character_data) AS object_type,
CAST('USAGE' AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(srv.srvacl,
makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', true))
CASE WHEN
-- object owner always has grant options
pg_has_role(g_grantee.oid, srv.srvowner, 'USAGE')
OR aclcontains(srv.srvacl,
makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
FROM pg_foreign_server srv,
......@@ -1330,8 +1355,11 @@ CREATE VIEW routine_privileges AS
CAST(p.proname AS sql_identifier) AS routine_name,
CAST('EXECUTE' AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(p.proacl,
makeaclitem(grantee.oid, u_grantor.oid, 'EXECUTE', true))
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, p.proowner, 'USAGE')
OR aclcontains(p.proacl,
makeaclitem(grantee.oid, u_grantor.oid, 'EXECUTE', true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
FROM pg_proc p,
......@@ -1531,8 +1559,7 @@ CREATE VIEW sequences AS
AND c.relkind = 'S'
AND (NOT pg_is_other_temp_schema(nc.oid))
AND (pg_has_role(c.relowner, 'USAGE')
OR has_table_privilege(c.oid, 'SELECT')
OR has_table_privilege(c.oid, 'UPDATE') );
OR has_table_privilege(c.oid, 'SELECT, UPDATE') );
GRANT SELECT ON sequences TO PUBLIC;
......@@ -1763,12 +1790,8 @@ CREATE VIEW table_constraints AS
AND (NOT pg_is_other_temp_schema(nr.oid))
AND (pg_has_role(r.relowner, 'USAGE')
-- SELECT privilege omitted, per SQL standard
OR has_table_privilege(r.oid, 'INSERT')
OR has_table_privilege(r.oid, 'UPDATE')
OR has_table_privilege(r.oid, 'DELETE')
OR has_table_privilege(r.oid, 'TRUNCATE')
OR has_table_privilege(r.oid, 'REFERENCES')
OR has_table_privilege(r.oid, 'TRIGGER') )
OR has_table_privilege(r.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
OR has_any_column_privilege(r.oid, 'INSERT, UPDATE, REFERENCES') )
UNION
......@@ -1796,13 +1819,9 @@ CREATE VIEW table_constraints AS
AND r.relkind = 'r'
AND (NOT pg_is_other_temp_schema(nr.oid))
AND (pg_has_role(r.relowner, 'USAGE')
OR has_table_privilege(r.oid, 'SELECT')
OR has_table_privilege(r.oid, 'INSERT')
OR has_table_privilege(r.oid, 'UPDATE')
OR has_table_privilege(r.oid, 'DELETE')
OR has_table_privilege(r.oid, 'TRUNCATE')
OR has_table_privilege(r.oid, 'REFERENCES')
OR has_table_privilege(r.oid, 'TRIGGER') );
-- SELECT privilege omitted, per SQL standard
OR has_table_privilege(r.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
OR has_any_column_privilege(r.oid, 'INSERT, UPDATE, REFERENCES') );
GRANT SELECT ON table_constraints TO PUBLIC;
......@@ -1828,8 +1847,11 @@ CREATE VIEW table_privileges AS
CAST(c.relname AS sql_identifier) AS table_name,
CAST(pr.type AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(c.relacl,
makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, c.relowner, 'USAGE')
OR aclcontains(c.relacl,
makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable,
CAST('NO' AS character_data) AS with_hierarchy
......@@ -1841,13 +1863,13 @@ CREATE VIEW table_privileges AS
UNION ALL
SELECT 0::oid, 'PUBLIC'
) AS grantee (oid, rolname),
(SELECT 'SELECT' UNION ALL
SELECT 'INSERT' UNION ALL
SELECT 'UPDATE' UNION ALL
SELECT 'DELETE' UNION ALL
SELECT 'TRUNCATE' UNION ALL
SELECT 'REFERENCES' UNION ALL
SELECT 'TRIGGER') AS pr (type)
(VALUES ('SELECT'),
('INSERT'),
('UPDATE'),
('DELETE'),
('TRUNCATE'),
('REFERENCES'),
('TRIGGER')) AS pr (type)
WHERE c.relnamespace = nc.oid
AND c.relkind IN ('r', 'v')
......@@ -1901,13 +1923,8 @@ CREATE VIEW tables AS
AND c.relkind IN ('r', 'v')
AND (NOT pg_is_other_temp_schema(nc.oid))
AND (pg_has_role(c.relowner, 'USAGE')
OR has_table_privilege(c.oid, 'SELECT')
OR has_table_privilege(c.oid, 'INSERT')
OR has_table_privilege(c.oid, 'UPDATE')
OR has_table_privilege(c.oid, 'DELETE')
OR has_table_privilege(c.oid, 'TRUNCATE')
OR has_table_privilege(c.oid, 'REFERENCES')
OR has_table_privilege(c.oid, 'TRIGGER') );
OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') );
GRANT SELECT ON tables TO PUBLIC;
......@@ -2013,9 +2030,9 @@ CREATE VIEW triggers AS
CAST(null AS time_stamp) AS created
FROM pg_namespace n, pg_class c, pg_trigger t,
(SELECT 4, 'INSERT' UNION ALL
SELECT 8, 'DELETE' UNION ALL
SELECT 16, 'UPDATE') AS em (num, text)
(VALUES (4, 'INSERT'),
(8, 'DELETE'),
(16, 'UPDATE')) AS em (num, text)
WHERE n.oid = c.relnamespace
AND c.oid = t.tgrelid
......@@ -2024,12 +2041,8 @@ CREATE VIEW triggers AS
AND (NOT pg_is_other_temp_schema(n.oid))
AND (pg_has_role(c.relowner, 'USAGE')
-- SELECT privilege omitted, per SQL standard
OR has_table_privilege(c.oid, 'INSERT')
OR has_table_privilege(c.oid, 'UPDATE')
OR has_table_privilege(c.oid, 'DELETE')
OR has_table_privilege(c.oid, 'TRUNCATE')
OR has_table_privilege(c.oid, 'REFERENCES')
OR has_table_privilege(c.oid, 'TRIGGER') );
OR has_table_privilege(c.oid, 'INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
OR has_any_column_privilege(c.oid, 'INSERT, UPDATE, REFERENCES') );
GRANT SELECT ON triggers TO PUBLIC;
......@@ -2079,8 +2092,11 @@ CREATE VIEW usage_privileges AS
CAST('FOREIGN DATA WRAPPER' AS character_data) AS object_type,
CAST('USAGE' AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(fdw.fdwacl,
makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', true))
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, fdw.fdwowner, 'USAGE')
OR aclcontains(fdw.fdwacl,
makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
FROM pg_foreign_data_wrapper fdw,
......@@ -2108,8 +2124,11 @@ CREATE VIEW usage_privileges AS
CAST('FOREIGN SERVER' AS character_data) AS object_type,
CAST('USAGE' AS character_data) AS privilege_type,
CAST(
CASE WHEN aclcontains(srv.srvacl,
makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', true))
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, srv.srvowner, 'USAGE')
OR aclcontains(srv.srvacl,
makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
FROM pg_foreign_server srv,
......@@ -2279,13 +2298,8 @@ CREATE VIEW views AS
AND c.relkind = 'v'
AND (NOT pg_is_other_temp_schema(nc.oid))
AND (pg_has_role(c.relowner, 'USAGE')
OR has_table_privilege(c.oid, 'SELECT')
OR has_table_privilege(c.oid, 'INSERT')
OR has_table_privilege(c.oid, 'UPDATE')
OR has_table_privilege(c.oid, 'DELETE')
OR has_table_privilege(c.oid, 'TRUNCATE')
OR has_table_privilege(c.oid, 'REFERENCES')
OR has_table_privilege(c.oid, 'TRIGGER') );
OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') );
GRANT SELECT ON views TO PUBLIC;
......
......@@ -3,7 +3,7 @@
*
* Copyright (c) 1996-2009, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.58 2009/01/01 17:23:37 momjian Exp $
* $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.59 2009/02/06 21:15:11 tgl Exp $
*/
CREATE VIEW pg_roles AS
......@@ -137,7 +137,7 @@ CREATE VIEW pg_stats AS
FROM pg_statistic s JOIN pg_class c ON (c.oid = s.starelid)
JOIN pg_attribute a ON (c.oid = attrelid AND attnum = s.staattnum)
LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
WHERE has_table_privilege(c.oid, 'select');
WHERE NOT attisdropped AND has_column_privilege(c.oid, a.attnum, 'select');
REVOKE ALL on pg_statistic FROM public;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.304 2009/01/02 20:42:00 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.305 2009/02/06 21:15:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -711,7 +711,7 @@ CopyLoadRawBuf(CopyState cstate)
* or write to a file.
*
* Do not allow the copy if user doesn't have proper permission to access
* the table.
* the table or the specifically requested columns.
*/
uint64
DoCopy(const CopyStmt *stmt, const char *queryString)
......@@ -723,7 +723,8 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
List *force_quote = NIL;
List *force_notnull = NIL;
AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT);
AclResult aclresult;
AclMode relPerms;
AclMode remainingPerms;
ListCell *option;
TupleDesc tupDesc;
int num_phys_attrs;
......@@ -973,13 +974,31 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
cstate->rel = heap_openrv(stmt->relation,
(is_from ? RowExclusiveLock : AccessShareLock));
tupDesc = RelationGetDescr(cstate->rel);
/* Check relation permissions. */
aclresult = pg_class_aclcheck(RelationGetRelid(cstate->rel),
GetUserId(),
required_access);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_CLASS,
RelationGetRelationName(cstate->rel));
relPerms = pg_class_aclmask(RelationGetRelid(cstate->rel), GetUserId(),
required_access, ACLMASK_ALL);
remainingPerms = required_access & ~relPerms;
if (remainingPerms != 0)
{
/* We don't have table permissions, check per-column permissions */
List *attnums;
ListCell *cur;
attnums = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
foreach(cur, attnums)
{
int attnum = lfirst_int(cur);
if (pg_attribute_aclcheck(RelationGetRelid(cstate->rel),
attnum,
GetUserId(),
remainingPerms) != ACLCHECK_OK)
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
RelationGetRelationName(cstate->rel));
}
}
/* check read-only transaction */
if (XactReadOnly && is_from &&
......@@ -994,8 +1013,6 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("table \"%s\" does not have OIDs",
RelationGetRelationName(cstate->rel))));
tupDesc = RelationGetDescr(cstate->rel);
}
else
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.146 2009/01/22 20:16:06 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.147 2009/02/06 21:15:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -32,6 +32,12 @@
#include "utils/syscache.h"
typedef struct
{
const char *name;
AclMode value;
} priv_map;
/*
* We frequently need to test whether a given role is a member of some other
* role. In most of these tests the "given role" is the same, namely the
......@@ -77,17 +83,25 @@ static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
static int oidComparator(const void *arg1, const void *arg2);
static AclMode convert_priv_string(text *priv_type_text);
static AclMode convert_any_priv_string(text *priv_type_text,
const priv_map *privileges);
static Oid convert_table_name(text *tablename);
static AclMode convert_table_priv_string(text *priv_type_text);
static AttrNumber convert_column_name(Oid tableoid, text *column);
static AclMode convert_column_priv_string(text *priv_type_text);
static Oid convert_database_name(text *databasename);
static AclMode convert_database_priv_string(text *priv_type_text);
static Oid convert_foreign_data_wrapper_name(text *fdwname);
static AclMode convert_foreign_data_wrapper_priv_string(text *priv_type_text);
static Oid convert_function_name(text *functionname);
static AclMode convert_function_priv_string(text *priv_type_text);
static Oid convert_language_name(text *languagename);
static AclMode convert_language_priv_string(text *priv_type_text);
static Oid convert_schema_name(text *schemaname);
static AclMode convert_schema_priv_string(text *priv_type_text);
static Oid convert_server_name(text *servername);
static AclMode convert_server_priv_string(text *priv_type_text);
static Oid convert_tablespace_name(text *tablespacename);
static AclMode convert_tablespace_priv_string(text *priv_type_text);
static AclMode convert_role_priv_string(text *priv_type_text);
......@@ -1419,6 +1433,63 @@ convert_priv_string(text *priv_type_text)
}
/*
* convert_any_priv_string: recognize privilege strings for has_foo_privilege
*
* We accept a comma-separated list of case-insensitive privilege names,
* producing a bitmask of the OR'd privilege bits. We are liberal about
* whitespace between items, not so much about whitespace within items.
* The allowed privilege names are given as an array of priv_map structs,
* terminated by one with a NULL name pointer.
*/
static AclMode
convert_any_priv_string(text *priv_type_text,
const priv_map *privileges)
{
AclMode result = 0;
char *priv_type = text_to_cstring(priv_type_text);
char *chunk;
char *next_chunk;
/* We rely on priv_type being a private, modifiable string */
for (chunk = priv_type; chunk; chunk = next_chunk)
{
int chunk_len;
const priv_map *this_priv;
/* Split string at commas */
next_chunk = strchr(chunk, ',');
if (next_chunk)
*next_chunk++ = '\0';
/* Drop leading/trailing whitespace in this chunk */
while (*chunk && isspace((unsigned char) *chunk))
chunk++;
chunk_len = strlen(chunk);
while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
chunk_len--;
chunk[chunk_len] = '\0';
/* Match to the privileges list */
for (this_priv = privileges; this_priv->name; this_priv++)
{
if (pg_strcasecmp(this_priv->name, chunk) == 0)
{
result |= this_priv->value;
break;
}
}
if (!this_priv->name)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", chunk)));
}
pfree(priv_type);
return result;
}
/*
* has_table_privilege variants
* These are all named "has_table_privilege" at the SQL level.
......@@ -1610,352 +1681,923 @@ convert_table_name(text *tablename)
static AclMode
convert_table_priv_string(text *priv_type_text)
{
char *priv_type = text_to_cstring(priv_type_text);
/*
* Return mode from priv_type string
*/
if (pg_strcasecmp(priv_type, "SELECT") == 0)
return ACL_SELECT;
if (pg_strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_SELECT);
if (pg_strcasecmp(priv_type, "INSERT") == 0)
return ACL_INSERT;
if (pg_strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_INSERT);
if (pg_strcasecmp(priv_type, "UPDATE") == 0)
return ACL_UPDATE;
if (pg_strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
if (pg_strcasecmp(priv_type, "DELETE") == 0)
return ACL_DELETE;
if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_DELETE);
if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
return ACL_TRUNCATE;
if (pg_strcasecmp(priv_type, "TRUNCATE WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_TRUNCATE);
if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
return ACL_REFERENCES;
if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
return ACL_TRIGGER;
if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
if (pg_strcasecmp(priv_type, "RULE") == 0)
return 0; /* ignore old RULE privileges */
if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
return 0;
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
return ACL_NO_RIGHTS; /* keep compiler quiet */
static const priv_map table_priv_map[] = {
{ "SELECT", ACL_SELECT },
{ "SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT) },
{ "INSERT", ACL_INSERT },
{ "INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT) },
{ "UPDATE", ACL_UPDATE },
{ "UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE) },
{ "DELETE", ACL_DELETE },
{ "DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE) },
{ "TRUNCATE", ACL_TRUNCATE },
{ "TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE) },
{ "REFERENCES", ACL_REFERENCES },
{ "REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES) },
{ "TRIGGER", ACL_TRIGGER },
{ "TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER) },
{ "RULE", 0 }, /* ignore old RULE privileges */
{ "RULE WITH GRANT OPTION", 0 },
{ NULL, 0 }
};
return convert_any_priv_string(priv_type_text, table_priv_map);
}
/*
* has_database_privilege variants
* These are all named "has_database_privilege" at the SQL level.
* They take various combinations of database name, database OID,
* has_any_column_privilege variants
* These are all named "has_any_column_privilege" at the SQL level.
* They take various combinations of relation name, relation 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.
* privilege for any column of the table, false if not. The variants
* that take a relation OID return NULL if the OID doesn't exist.
*/
/*
* has_database_privilege_name_name
* Check user privileges on a database given
* name username, text databasename, and text priv name.
* has_any_column_privilege_name_name
* Check user privileges on any column of a table given
* name username, text tablename, and text priv name.
*/
Datum
has_database_privilege_name_name(PG_FUNCTION_ARGS)
has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
text *databasename = PG_GETARG_TEXT_P(1);
Name rolename = PG_GETARG_NAME(0);
text *tablename = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
Oid databaseoid;
Oid tableoid;
AclMode mode;
AclResult aclresult;
roleid = get_roleid_checked(NameStr(*username));
databaseoid = convert_database_name(databasename);
mode = convert_database_priv_string(priv_type_text);
roleid = get_roleid_checked(NameStr(*rolename));
tableoid = convert_table_name(tablename);
mode = convert_column_priv_string(priv_type_text);
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
/* First check at table level, then examine each column if needed */
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (aclresult != ACLCHECK_OK)
aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
ACLMASK_ANY);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_name
* Check user privileges on a database given
* text databasename and text priv name.
* has_any_column_privilege_name
* Check user privileges on any column of a table given
* text tablename and text priv name.
* current_user is assumed
*/
Datum
has_database_privilege_name(PG_FUNCTION_ARGS)
has_any_column_privilege_name(PG_FUNCTION_ARGS)
{
text *databasename = PG_GETARG_TEXT_P(0);
text *tablename = PG_GETARG_TEXT_P(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
Oid databaseoid;
Oid tableoid;
AclMode mode;
AclResult aclresult;
roleid = GetUserId();
databaseoid = convert_database_name(databasename);
mode = convert_database_priv_string(priv_type_text);
tableoid = convert_table_name(tablename);
mode = convert_column_priv_string(priv_type_text);
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
/* First check at table level, then examine each column if needed */
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (aclresult != ACLCHECK_OK)
aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
ACLMASK_ANY);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_name_id
* Check user privileges on a database given
* name usename, database oid, and text priv name.
* has_any_column_privilege_name_id
* Check user privileges on any column of a table given
* name usename, table oid, and text priv name.
*/
Datum
has_database_privilege_name_id(PG_FUNCTION_ARGS)
has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
Oid databaseoid = PG_GETARG_OID(1);
Oid tableoid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
AclMode mode;
AclResult aclresult;
roleid = get_roleid_checked(NameStr(*username));
mode = convert_database_priv_string(priv_type_text);
mode = convert_column_priv_string(priv_type_text);
if (!SearchSysCacheExists(DATABASEOID,
ObjectIdGetDatum(databaseoid),
if (!SearchSysCacheExists(RELOID,
ObjectIdGetDatum(tableoid),
0, 0, 0))
PG_RETURN_NULL();
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
/* First check at table level, then examine each column if needed */
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (aclresult != ACLCHECK_OK)
aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
ACLMASK_ANY);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_id
* Check user privileges on a database given
* database oid, and text priv name.
* has_any_column_privilege_id
* Check user privileges on any column of a table given
* table oid, and text priv name.
* current_user is assumed
*/
Datum
has_database_privilege_id(PG_FUNCTION_ARGS)
has_any_column_privilege_id(PG_FUNCTION_ARGS)
{
Oid databaseoid = PG_GETARG_OID(0);
Oid tableoid = PG_GETARG_OID(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
AclMode mode;
AclResult aclresult;
roleid = GetUserId();
mode = convert_database_priv_string(priv_type_text);
mode = convert_column_priv_string(priv_type_text);
if (!SearchSysCacheExists(DATABASEOID,
ObjectIdGetDatum(databaseoid),
if (!SearchSysCacheExists(RELOID,
ObjectIdGetDatum(tableoid),
0, 0, 0))
PG_RETURN_NULL();
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
/* First check at table level, then examine each column if needed */
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (aclresult != ACLCHECK_OK)
aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
ACLMASK_ANY);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_id_name
* Check user privileges on a database given
* roleid, text databasename, and text priv name.
* has_any_column_privilege_id_name
* Check user privileges on any column of a table given
* roleid, text tablename, and text priv name.
*/
Datum
has_database_privilege_id_name(PG_FUNCTION_ARGS)
has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
text *databasename = PG_GETARG_TEXT_P(1);
text *tablename = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid databaseoid;
Oid tableoid;
AclMode mode;
AclResult aclresult;
databaseoid = convert_database_name(databasename);
mode = convert_database_priv_string(priv_type_text);
tableoid = convert_table_name(tablename);
mode = convert_column_priv_string(priv_type_text);
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
/* First check at table level, then examine each column if needed */
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (aclresult != ACLCHECK_OK)
aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
ACLMASK_ANY);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_id_id
* Check user privileges on a database given
* roleid, database oid, and text priv name.
* has_any_column_privilege_id_id
* Check user privileges on any column of a table given
* roleid, table oid, and text priv name.
*/
Datum
has_database_privilege_id_id(PG_FUNCTION_ARGS)
has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
Oid databaseoid = PG_GETARG_OID(1);
Oid tableoid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
AclMode mode;
AclResult aclresult;
mode = convert_database_priv_string(priv_type_text);
mode = convert_column_priv_string(priv_type_text);
if (!SearchSysCacheExists(DATABASEOID,
ObjectIdGetDatum(databaseoid),
if (!SearchSysCacheExists(RELOID,
ObjectIdGetDatum(tableoid),
0, 0, 0))
PG_RETURN_NULL();
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
/* First check at table level, then examine each column if needed */
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (aclresult != ACLCHECK_OK)
aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
ACLMASK_ANY);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* Support routines for has_database_privilege family.
*/
/*
* Given a database name expressed as a string, look it up and return Oid
* has_column_privilege variants
* These are all named "has_column_privilege" at the SQL level.
* They take various combinations of relation name, relation OID,
* column name, column attnum, 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. The variants that take a relation OID
* and an integer attnum return NULL (rather than throwing an error)
* if the column doesn't exist or is dropped.
*/
static Oid
convert_database_name(text *databasename)
{
char *dbname = text_to_cstring(databasename);
Oid oid;
oid = get_database_oid(dbname);
if (!OidIsValid(oid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", dbname)));
return oid;
}
/*
* convert_database_priv_string
* Convert text string to AclMode value.
* column_privilege_check: check column privileges, but don't throw an error
* for dropped column or table
*
* Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
*/
static AclMode
convert_database_priv_string(text *priv_type_text)
static int
column_privilege_check(Oid tableoid, AttrNumber attnum,
Oid roleid, AclMode mode)
{
char *priv_type = text_to_cstring(priv_type_text);
AclResult aclresult;
HeapTuple attTuple;
Form_pg_attribute attributeForm;
/*
* Return mode from priv_type string
* First check if we have the privilege at the table level. We check
* existence of the pg_class row before risking calling pg_class_aclcheck.
* Note: it might seem there's a race condition against concurrent DROP,
* but really it's safe because there will be no syscache flush between
* here and there. So if we see the row in the syscache, so will
* pg_class_aclcheck.
*/
if (pg_strcasecmp(priv_type, "CREATE") == 0)
return ACL_CREATE;
if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_CREATE);
if (!SearchSysCacheExists(RELOID,
ObjectIdGetDatum(tableoid),
0, 0, 0))
return -1;
if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
return ACL_CREATE_TEMP;
if (pg_strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (pg_strcasecmp(priv_type, "TEMP") == 0)
return ACL_CREATE_TEMP;
if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
if (aclresult == ACLCHECK_OK)
return true;
if (pg_strcasecmp(priv_type, "CONNECT") == 0)
return ACL_CONNECT;
if (pg_strcasecmp(priv_type, "CONNECT WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_CONNECT);
/*
* No table privilege, so try per-column privileges. Again, we have to
* check for dropped attribute first, and we rely on the syscache not to
* notice a concurrent drop before pg_attribute_aclcheck fetches the row.
*/
attTuple = SearchSysCache(ATTNUM,
ObjectIdGetDatum(tableoid),
Int16GetDatum(attnum),
0, 0);
if (!HeapTupleIsValid(attTuple))
return -1;
attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
if (attributeForm->attisdropped)
{
ReleaseSysCache(attTuple);
return -1;
}
ReleaseSysCache(attTuple);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
return ACL_NO_RIGHTS; /* keep compiler quiet */
}
aclresult = pg_attribute_aclcheck(tableoid, attnum, roleid, mode);
return (aclresult == ACLCHECK_OK);
}
/*
* has_foreign_data_wrapper_privilege variants
* These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
* They take various combinations of foreign-data wrapper name,
* fdw 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. The variants that take an OID return
* NULL if the OID doesn't exist.
* has_column_privilege_name_name_name
* Check user privileges on a column given
* name username, text tablename, text colname, and text priv name.
*/
Datum
has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
{
Name rolename = PG_GETARG_NAME(0);
text *tablename = PG_GETARG_TEXT_P(1);
text *column = PG_GETARG_TEXT_P(2);
text *priv_type_text = PG_GETARG_TEXT_P(3);
Oid roleid;
Oid tableoid;
AttrNumber colattnum;
AclMode mode;
int privresult;
roleid = get_roleid_checked(NameStr(*rolename));
tableoid = convert_table_name(tablename);
colattnum = convert_column_name(tableoid, column);
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_foreign_data_wrapper_privilege
* Check user privileges on a foreign-data wrapper.
* has_column_privilege_name_name_attnum
* Check user privileges on a column given
* name username, text tablename, int attnum, and text priv name.
*/
static Datum
has_foreign_data_wrapper_privilege(Oid roleid, Oid fdwid, text *priv_type_text)
Datum
has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
{
AclResult aclresult;
AclMode mode = ACL_NO_RIGHTS;
char *priv_type = text_to_cstring(priv_type_text);
if (pg_strcasecmp(priv_type, "USAGE") == 0)
mode = ACL_USAGE;
else if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
mode = ACL_GRANT_OPTION_FOR(ACL_USAGE);
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
Name rolename = PG_GETARG_NAME(0);
text *tablename = PG_GETARG_TEXT_P(1);
AttrNumber colattnum = PG_GETARG_INT16(2);
text *priv_type_text = PG_GETARG_TEXT_P(3);
Oid roleid;
Oid tableoid;
AclMode mode;
int privresult;
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
roleid = get_roleid_checked(NameStr(*rolename));
tableoid = convert_table_name(tablename);
mode = convert_column_priv_string(priv_type_text);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_foreign_data_wrapper_privilege_name_name
* Check user privileges on a foreign-data wrapper given
* name username, text fdwname, and text priv name.
* has_column_privilege_name_id_name
* Check user privileges on a column given
* name username, table oid, text colname, and text priv name.
*/
Datum
has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(1));
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid tableoid = PG_GETARG_OID(1);
text *column = PG_GETARG_TEXT_P(2);
text *priv_type_text = PG_GETARG_TEXT_P(3);
Oid roleid;
AttrNumber colattnum;
AclMode mode;
int privresult;
roleid = get_roleid_checked(NameStr(*username));
colattnum = convert_column_name(tableoid, column);
mode = convert_column_priv_string(priv_type_text);
return has_foreign_data_wrapper_privilege(get_roleid_checked(NameStr(*username)),
GetForeignDataWrapperOidByName(fdwname, false),
priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_foreign_data_wrapper_privilege_name
* Check user privileges on a foreign-data wrapper given
* text fdwname and text priv name.
* has_column_privilege_name_id_attnum
* Check user privileges on a column given
* name username, table oid, int attnum, and text priv name.
*/
Datum
has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
Oid tableoid = PG_GETARG_OID(1);
AttrNumber colattnum = PG_GETARG_INT16(2);
text *priv_type_text = PG_GETARG_TEXT_P(3);
Oid roleid;
AclMode mode;
int privresult;
roleid = get_roleid_checked(NameStr(*username));
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_column_privilege_id_name_name
* Check user privileges on a column given
* oid roleid, text tablename, text colname, and text priv name.
*/
Datum
has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
text *tablename = PG_GETARG_TEXT_P(1);
text *column = PG_GETARG_TEXT_P(2);
text *priv_type_text = PG_GETARG_TEXT_P(3);
Oid tableoid;
AttrNumber colattnum;
AclMode mode;
int privresult;
tableoid = convert_table_name(tablename);
colattnum = convert_column_name(tableoid, column);
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_column_privilege_id_name_attnum
* Check user privileges on a column given
* oid roleid, text tablename, int attnum, and text priv name.
*/
Datum
has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
text *tablename = PG_GETARG_TEXT_P(1);
AttrNumber colattnum = PG_GETARG_INT16(2);
text *priv_type_text = PG_GETARG_TEXT_P(3);
Oid tableoid;
AclMode mode;
int privresult;
tableoid = convert_table_name(tablename);
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_column_privilege_id_id_name
* Check user privileges on a column given
* oid roleid, table oid, text colname, and text priv name.
*/
Datum
has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
Oid tableoid = PG_GETARG_OID(1);
text *column = PG_GETARG_TEXT_P(2);
text *priv_type_text = PG_GETARG_TEXT_P(3);
AttrNumber colattnum;
AclMode mode;
int privresult;
colattnum = convert_column_name(tableoid, column);
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_column_privilege_id_id_attnum
* Check user privileges on a column given
* oid roleid, table oid, int attnum, and text priv name.
*/
Datum
has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
Oid tableoid = PG_GETARG_OID(1);
AttrNumber colattnum = PG_GETARG_INT16(2);
text *priv_type_text = PG_GETARG_TEXT_P(3);
AclMode mode;
int privresult;
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_column_privilege_name_name
* Check user privileges on a column given
* text tablename, text colname, and text priv name.
* current_user is assumed
*/
Datum
has_column_privilege_name_name(PG_FUNCTION_ARGS)
{
text *tablename = PG_GETARG_TEXT_P(0);
text *column = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
Oid tableoid;
AttrNumber colattnum;
AclMode mode;
int privresult;
roleid = GetUserId();
tableoid = convert_table_name(tablename);
colattnum = convert_column_name(tableoid, column);
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_column_privilege_name_attnum
* Check user privileges on a column given
* text tablename, int attnum, and text priv name.
* current_user is assumed
*/
Datum
has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
{
text *tablename = PG_GETARG_TEXT_P(0);
AttrNumber colattnum = PG_GETARG_INT16(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
Oid tableoid;
AclMode mode;
int privresult;
roleid = GetUserId();
tableoid = convert_table_name(tablename);
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_column_privilege_id_name
* Check user privileges on a column given
* table oid, text colname, and text priv name.
* current_user is assumed
*/
Datum
has_column_privilege_id_name(PG_FUNCTION_ARGS)
{
Oid tableoid = PG_GETARG_OID(0);
text *column = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
AttrNumber colattnum;
AclMode mode;
int privresult;
roleid = GetUserId();
colattnum = convert_column_name(tableoid, column);
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* has_column_privilege_id_attnum
* Check user privileges on a column given
* table oid, int attnum, and text priv name.
* current_user is assumed
*/
Datum
has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
{
Oid tableoid = PG_GETARG_OID(0);
AttrNumber colattnum = PG_GETARG_INT16(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
AclMode mode;
int privresult;
roleid = GetUserId();
mode = convert_column_priv_string(priv_type_text);
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
if (privresult < 0)
PG_RETURN_NULL();
PG_RETURN_BOOL(privresult);
}
/*
* Support routines for has_column_privilege family.
*/
/*
* Given a table OID and a column name expressed as a string, look it up
* and return the column number
*/
static AttrNumber
convert_column_name(Oid tableoid, text *column)
{
AttrNumber attnum;
char *colname;
colname = text_to_cstring(column);
attnum = get_attnum(tableoid, colname);
if (attnum == InvalidAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
colname, get_rel_name(tableoid))));
pfree(colname);
return attnum;
}
/*
* convert_column_priv_string
* Convert text string to AclMode value.
*/
static AclMode
convert_column_priv_string(text *priv_type_text)
{
static const priv_map column_priv_map[] = {
{ "SELECT", ACL_SELECT },
{ "SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT) },
{ "INSERT", ACL_INSERT },
{ "INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT) },
{ "UPDATE", ACL_UPDATE },
{ "UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE) },
{ "REFERENCES", ACL_REFERENCES },
{ "REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES) },
{ NULL, 0 }
};
return convert_any_priv_string(priv_type_text, column_priv_map);
}
/*
* has_database_privilege variants
* These are all named "has_database_privilege" at the SQL level.
* They take various combinations of database name, database 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_database_privilege_name_name
* Check user privileges on a database given
* name username, text databasename, and text priv name.
*/
Datum
has_database_privilege_name_name(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
text *databasename = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
Oid databaseoid;
AclMode mode;
AclResult aclresult;
roleid = get_roleid_checked(NameStr(*username));
databaseoid = convert_database_name(databasename);
mode = convert_database_priv_string(priv_type_text);
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_name
* Check user privileges on a database given
* text databasename and text priv name.
* current_user is assumed
*/
Datum
has_database_privilege_name(PG_FUNCTION_ARGS)
{
text *databasename = PG_GETARG_TEXT_P(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
Oid databaseoid;
AclMode mode;
AclResult aclresult;
roleid = GetUserId();
databaseoid = convert_database_name(databasename);
mode = convert_database_priv_string(priv_type_text);
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_name_id
* Check user privileges on a database given
* name usename, database oid, and text priv name.
*/
Datum
has_database_privilege_name_id(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
Oid databaseoid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
AclMode mode;
AclResult aclresult;
roleid = get_roleid_checked(NameStr(*username));
mode = convert_database_priv_string(priv_type_text);
if (!SearchSysCacheExists(DATABASEOID,
ObjectIdGetDatum(databaseoid),
0, 0, 0))
PG_RETURN_NULL();
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_id
* Check user privileges on a database given
* database oid, and text priv name.
* current_user is assumed
*/
Datum
has_database_privilege_id(PG_FUNCTION_ARGS)
{
Oid databaseoid = PG_GETARG_OID(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
AclMode mode;
AclResult aclresult;
roleid = GetUserId();
mode = convert_database_priv_string(priv_type_text);
if (!SearchSysCacheExists(DATABASEOID,
ObjectIdGetDatum(databaseoid),
0, 0, 0))
PG_RETURN_NULL();
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_id_name
* Check user privileges on a database given
* roleid, text databasename, and text priv name.
*/
Datum
has_database_privilege_id_name(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
text *databasename = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid databaseoid;
AclMode mode;
AclResult aclresult;
databaseoid = convert_database_name(databasename);
mode = convert_database_priv_string(priv_type_text);
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_database_privilege_id_id
* Check user privileges on a database given
* roleid, database oid, and text priv name.
*/
Datum
has_database_privilege_id_id(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
Oid databaseoid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
AclMode mode;
AclResult aclresult;
mode = convert_database_priv_string(priv_type_text);
if (!SearchSysCacheExists(DATABASEOID,
ObjectIdGetDatum(databaseoid),
0, 0, 0))
PG_RETURN_NULL();
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* Support routines for has_database_privilege family.
*/
/*
* Given a database name expressed as a string, look it up and return Oid
*/
static Oid
convert_database_name(text *databasename)
{
char *dbname = text_to_cstring(databasename);
Oid oid;
oid = get_database_oid(dbname);
if (!OidIsValid(oid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", dbname)));
return oid;
}
/*
* convert_database_priv_string
* Convert text string to AclMode value.
*/
static AclMode
convert_database_priv_string(text *priv_type_text)
{
static const priv_map database_priv_map[] = {
{ "CREATE", ACL_CREATE },
{ "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
{ "TEMPORARY", ACL_CREATE_TEMP },
{ "TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP) },
{ "TEMP", ACL_CREATE_TEMP },
{ "TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP) },
{ "CONNECT", ACL_CONNECT },
{ "CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT) },
{ NULL, 0 }
};
return convert_any_priv_string(priv_type_text, database_priv_map);
}
/*
* has_foreign_data_wrapper_privilege variants
* These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
* They take various combinations of foreign-data wrapper name,
* fdw 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.
*/
/*
* has_foreign_data_wrapper_privilege_name_name
* Check user privileges on a foreign-data wrapper given
* name username, text fdwname, and text priv name.
*/
Datum
has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
text *fdwname = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
Oid fdwid;
AclMode mode;
AclResult aclresult;
roleid = get_roleid_checked(NameStr(*username));
fdwid = convert_foreign_data_wrapper_name(fdwname);
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_foreign_data_wrapper_privilege_name
* Check user privileges on a foreign-data wrapper given
* text fdwname and text priv name.
* current_user is assumed
*/
Datum
has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
{
char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(0));
text *fdwname = PG_GETARG_TEXT_P(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
Oid fdwid;
AclMode mode;
AclResult aclresult;
return has_foreign_data_wrapper_privilege(GetUserId(),
GetForeignDataWrapperOidByName(fdwname, false),
priv_type_text);
roleid = GetUserId();
fdwid = convert_foreign_data_wrapper_name(fdwname);
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
......@@ -1969,14 +2611,16 @@ has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
Name username = PG_GETARG_NAME(0);
Oid fdwid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
AclMode mode;
AclResult aclresult;
if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
ObjectIdGetDatum(fdwid),
0, 0, 0))
PG_RETURN_NULL();
roleid = get_roleid_checked(NameStr(*username));
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
return has_foreign_data_wrapper_privilege(get_roleid_checked(NameStr(*username)),
fdwid, priv_type_text);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
......@@ -1990,14 +2634,16 @@ has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
{
Oid fdwid = PG_GETARG_OID(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
AclMode mode;
AclResult aclresult;
if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
ObjectIdGetDatum(fdwid),
0, 0, 0))
PG_RETURN_NULL();
roleid = GetUserId();
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
return has_foreign_data_wrapper_privilege(GetUserId(), fdwid,
priv_type_text);
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
......@@ -2009,12 +2655,18 @@ Datum
has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(1));
text *fdwname = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid fdwid;
AclMode mode;
AclResult aclresult;
fdwid = convert_foreign_data_wrapper_name(fdwname);
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
return has_foreign_data_wrapper_privilege(roleid,
GetForeignDataWrapperOidByName(fdwname, false),
priv_type_text);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
......@@ -2028,13 +2680,45 @@ has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
Oid roleid = PG_GETARG_OID(0);
Oid fdwid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
AclMode mode;
AclResult aclresult;
if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
ObjectIdGetDatum(fdwid),
0, 0, 0))
PG_RETURN_NULL();
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* Support routines for has_foreign_data_wrapper_privilege family.
*/
/*
* Given a FDW name expressed as a string, look it up and return Oid
*/
static Oid
convert_foreign_data_wrapper_name(text *fdwname)
{
char *fdwstr = text_to_cstring(fdwname);
return GetForeignDataWrapperOidByName(fdwstr, false);
}
return has_foreign_data_wrapper_privilege(roleid, fdwid, priv_type_text);
/*
* convert_foreign_data_wrapper_priv_string
* Convert text string to AclMode value.
*/
static AclMode
convert_foreign_data_wrapper_priv_string(text *priv_type_text)
{
static const priv_map foreign_data_wrapper_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, foreign_data_wrapper_priv_map);
}
......@@ -2234,20 +2918,13 @@ convert_function_name(text *functionname)
static AclMode
convert_function_priv_string(text *priv_type_text)
{
char *priv_type = text_to_cstring(priv_type_text);
/*
* Return mode from priv_type string
*/
if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
return ACL_EXECUTE;
if (pg_strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
static const priv_map function_priv_map[] = {
{ "EXECUTE", ACL_EXECUTE },
{ "EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE) },
{ NULL, 0 }
};
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
return ACL_NO_RIGHTS; /* keep compiler quiet */
return convert_any_priv_string(priv_type_text, function_priv_map);
}
......@@ -2447,20 +3124,13 @@ convert_language_name(text *languagename)
static AclMode
convert_language_priv_string(text *priv_type_text)
{
char *priv_type = text_to_cstring(priv_type_text);
/*
* Return mode from priv_type string
*/
if (pg_strcasecmp(priv_type, "USAGE") == 0)
return ACL_USAGE;
if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_USAGE);
static const priv_map language_priv_map[] = {
{ "USAGE", ACL_USAGE },
{ "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
{ NULL, 0 }
};
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
return ACL_NO_RIGHTS; /* keep compiler quiet */
return convert_any_priv_string(priv_type_text, language_priv_map);
}
......@@ -2660,27 +3330,18 @@ convert_schema_name(text *schemaname)
static AclMode
convert_schema_priv_string(text *priv_type_text)
{
char *priv_type = text_to_cstring(priv_type_text);
/*
* Return mode from priv_type string
*/
if (pg_strcasecmp(priv_type, "CREATE") == 0)
return ACL_CREATE;
if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_CREATE);
if (pg_strcasecmp(priv_type, "USAGE") == 0)
return ACL_USAGE;
if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_USAGE);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
return ACL_NO_RIGHTS; /* keep compiler quiet */
static const priv_map schema_priv_map[] = {
{ "CREATE", ACL_CREATE },
{ "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
{ "USAGE", ACL_USAGE },
{ "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
{ NULL, 0 }
};
return convert_any_priv_string(priv_type_text, schema_priv_map);
}
/*
* has_server_privilege variants
* These are all named "has_server_privilege" at the SQL level.
......@@ -2691,31 +3352,6 @@ convert_schema_priv_string(text *priv_type_text)
* privilege, false if not.
*/
/*
* has_server_privilege
* Check user privileges on a foreign server.
*/
static Datum
has_server_privilege(Oid roleid, Oid serverid, text *priv_type_text)
{
AclResult aclresult;
AclMode mode = ACL_NO_RIGHTS;
char *priv_type = text_to_cstring(priv_type_text);
if (pg_strcasecmp(priv_type, "USAGE") == 0)
mode = ACL_USAGE;
else if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
mode = ACL_GRANT_OPTION_FOR(ACL_USAGE);
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* has_server_privilege_name_name
* Check user privileges on a foreign server given
......@@ -2725,12 +3361,20 @@ Datum
has_server_privilege_name_name(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
char *servername = text_to_cstring(PG_GETARG_TEXT_P(1));
text *servername = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
Oid serverid;
AclMode mode;
AclResult aclresult;
roleid = get_roleid_checked(NameStr(*username));
serverid = convert_server_name(servername);
mode = convert_server_priv_string(priv_type_text);
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
return has_server_privilege(get_roleid_checked(NameStr(*username)),
GetForeignServerOidByName(servername, false),
priv_type_text);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
......@@ -2742,12 +3386,20 @@ has_server_privilege_name_name(PG_FUNCTION_ARGS)
Datum
has_server_privilege_name(PG_FUNCTION_ARGS)
{
char *servername = text_to_cstring(PG_GETARG_TEXT_P(0));
text *servername = PG_GETARG_TEXT_P(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
Oid serverid;
AclMode mode;
AclResult aclresult;
roleid = GetUserId();
serverid = convert_server_name(servername);
mode = convert_server_priv_string(priv_type_text);
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
return has_server_privilege(GetUserId(),
GetForeignServerOidByName(servername, false),
priv_type_text);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
......@@ -2761,14 +3413,16 @@ has_server_privilege_name_id(PG_FUNCTION_ARGS)
Name username = PG_GETARG_NAME(0);
Oid serverid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid roleid;
AclMode mode;
AclResult aclresult;
if (!SearchSysCacheExists(FOREIGNSERVEROID,
ObjectIdGetDatum(serverid),
0, 0, 0))
PG_RETURN_NULL();
roleid = get_roleid_checked(NameStr(*username));
mode = convert_server_priv_string(priv_type_text);
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
return has_server_privilege(get_roleid_checked(NameStr(*username)), serverid,
priv_type_text);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
......@@ -2782,13 +3436,16 @@ has_server_privilege_id(PG_FUNCTION_ARGS)
{
Oid serverid = PG_GETARG_OID(0);
text *priv_type_text = PG_GETARG_TEXT_P(1);
Oid roleid;
AclMode mode;
AclResult aclresult;
if (!SearchSysCacheExists(FOREIGNSERVEROID,
ObjectIdGetDatum(serverid),
0, 0, 0))
PG_RETURN_NULL();
roleid = GetUserId();
mode = convert_server_priv_string(priv_type_text);
return has_server_privilege(GetUserId(), serverid, priv_type_text);
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
......@@ -2800,12 +3457,18 @@ Datum
has_server_privilege_id_name(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
char *servername = text_to_cstring(PG_GETARG_TEXT_P(1));
text *servername = PG_GETARG_TEXT_P(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
Oid serverid;
AclMode mode;
AclResult aclresult;
serverid = convert_server_name(servername);
mode = convert_server_priv_string(priv_type_text);
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
return has_server_privilege(roleid,
GetForeignServerOidByName(servername, false),
priv_type_text);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
......@@ -2819,13 +3482,45 @@ has_server_privilege_id_id(PG_FUNCTION_ARGS)
Oid roleid = PG_GETARG_OID(0);
Oid serverid = PG_GETARG_OID(1);
text *priv_type_text = PG_GETARG_TEXT_P(2);
AclMode mode;
AclResult aclresult;
if (!SearchSysCacheExists(FOREIGNSERVEROID,
ObjectIdGetDatum(serverid),
0, 0, 0))
PG_RETURN_NULL();
mode = convert_server_priv_string(priv_type_text);
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
/*
* Support routines for has_server_privilege family.
*/
/*
* Given a server name expressed as a string, look it up and return Oid
*/
static Oid
convert_server_name(text *servername)
{
char *serverstr = text_to_cstring(servername);
return GetForeignServerOidByName(serverstr, false);
}
/*
* convert_server_priv_string
* Convert text string to AclMode value.
*/
static AclMode
convert_server_priv_string(text *priv_type_text)
{
static const priv_map server_priv_map[] = {
{ "USAGE", ACL_USAGE },
{ "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
{ NULL, 0 }
};
return has_server_privilege(roleid, serverid, priv_type_text);
return convert_any_priv_string(priv_type_text, server_priv_map);
}
......@@ -3009,20 +3704,13 @@ convert_tablespace_name(text *tablespacename)
static AclMode
convert_tablespace_priv_string(text *priv_type_text)
{
char *priv_type = text_to_cstring(priv_type_text);
/*
* Return mode from priv_type string
*/
if (pg_strcasecmp(priv_type, "CREATE") == 0)
return ACL_CREATE;
if (pg_strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_CREATE);
static const priv_map tablespace_priv_map[] = {
{ "CREATE", ACL_CREATE },
{ "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
{ NULL, 0 }
};
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
return ACL_NO_RIGHTS; /* keep compiler quiet */
return convert_any_priv_string(priv_type_text, tablespace_priv_map);
}
/*
......@@ -3192,25 +3880,17 @@ pg_has_role_id_id(PG_FUNCTION_ARGS)
static AclMode
convert_role_priv_string(text *priv_type_text)
{
char *priv_type = text_to_cstring(priv_type_text);
/*
* Return mode from priv_type string
*/
if (pg_strcasecmp(priv_type, "USAGE") == 0)
return ACL_USAGE;
if (pg_strcasecmp(priv_type, "MEMBER") == 0)
return ACL_CREATE;
if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0 ||
pg_strcasecmp(priv_type, "USAGE WITH ADMIN OPTION") == 0 ||
pg_strcasecmp(priv_type, "MEMBER WITH GRANT OPTION") == 0 ||
pg_strcasecmp(priv_type, "MEMBER WITH ADMIN OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_CREATE);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
return ACL_NO_RIGHTS; /* keep compiler quiet */
static const priv_map role_priv_map[] = {
{ "USAGE", ACL_USAGE },
{ "MEMBER", ACL_CREATE },
{ "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
{ "USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
{ "MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
{ "MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
{ NULL, 0 }
};
return convert_any_priv_string(priv_type_text, role_priv_map);
}
/*
......
......@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.520 2009/01/27 12:40:15 petere Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.521 2009/02/06 21:15:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200901271
#define CATALOG_VERSION_NO 200902061
#endif
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.535 2009/01/01 17:23:57 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.536 2009/02/06 21:15:11 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
......@@ -2913,6 +2913,43 @@ DESCR("current user privilege on relation by rel name");
DATA(insert OID = 1927 ( has_table_privilege PGNSP PGUID 12 1 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_table_privilege_id _null_ _null_ _null_ ));
DESCR("current user privilege on relation by rel oid");
DATA(insert OID = 3012 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 4 0 16 "19 25 25 25" _null_ _null_ _null_ _null_ has_column_privilege_name_name_name _null_ _null_ _null_ ));
DESCR("user privilege on column by username, rel name, col name");
DATA(insert OID = 3013 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 4 0 16 "19 25 21 25" _null_ _null_ _null_ _null_ has_column_privilege_name_name_attnum _null_ _null_ _null_ ));
DESCR("user privilege on column by username, rel name, col attnum");
DATA(insert OID = 3014 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 4 0 16 "19 26 25 25" _null_ _null_ _null_ _null_ has_column_privilege_name_id_name _null_ _null_ _null_ ));
DESCR("user privilege on column by username, rel oid, col name");
DATA(insert OID = 3015 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 4 0 16 "19 26 21 25" _null_ _null_ _null_ _null_ has_column_privilege_name_id_attnum _null_ _null_ _null_ ));
DESCR("user privilege on column by username, rel oid, col attnum");
DATA(insert OID = 3016 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 4 0 16 "26 25 25 25" _null_ _null_ _null_ _null_ has_column_privilege_id_name_name _null_ _null_ _null_ ));
DESCR("user privilege on column by user oid, rel name, col name");
DATA(insert OID = 3017 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 4 0 16 "26 25 21 25" _null_ _null_ _null_ _null_ has_column_privilege_id_name_attnum _null_ _null_ _null_ ));
DESCR("user privilege on column by user oid, rel name, col attnum");
DATA(insert OID = 3018 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 4 0 16 "26 26 25 25" _null_ _null_ _null_ _null_ has_column_privilege_id_id_name _null_ _null_ _null_ ));
DESCR("user privilege on column by user oid, rel oid, col name");
DATA(insert OID = 3019 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 4 0 16 "26 26 21 25" _null_ _null_ _null_ _null_ has_column_privilege_id_id_attnum _null_ _null_ _null_ ));
DESCR("user privilege on column by user oid, rel oid, col attnum");
DATA(insert OID = 3020 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 3 0 16 "25 25 25" _null_ _null_ _null_ _null_ has_column_privilege_name_name _null_ _null_ _null_ ));
DESCR("current user privilege on column by rel name, col name");
DATA(insert OID = 3021 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 3 0 16 "25 21 25" _null_ _null_ _null_ _null_ has_column_privilege_name_attnum _null_ _null_ _null_ ));
DESCR("current user privilege on column by rel name, col attnum");
DATA(insert OID = 3022 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ has_column_privilege_id_name _null_ _null_ _null_ ));
DESCR("current user privilege on column by rel oid, col name");
DATA(insert OID = 3023 ( has_column_privilege PGNSP PGUID 12 1 0 0 f f f t f s 3 0 16 "26 21 25" _null_ _null_ _null_ _null_ has_column_privilege_id_attnum _null_ _null_ _null_ ));
DESCR("current user privilege on column by rel oid, col attnum");
DATA(insert OID = 3024 ( has_any_column_privilege PGNSP PGUID 12 10 0 0 f f f t f s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ has_any_column_privilege_name_name _null_ _null_ _null_ ));
DESCR("user privilege on any column by username, rel name");
DATA(insert OID = 3025 ( has_any_column_privilege PGNSP PGUID 12 10 0 0 f f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ has_any_column_privilege_name_id _null_ _null_ _null_ ));
DESCR("user privilege on any column by username, rel oid");
DATA(insert OID = 3026 ( has_any_column_privilege PGNSP PGUID 12 10 0 0 f f f t f s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ has_any_column_privilege_id_name _null_ _null_ _null_ ));
DESCR("user privilege on any column by user oid, rel name");
DATA(insert OID = 3027 ( has_any_column_privilege PGNSP PGUID 12 10 0 0 f f f t f s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ has_any_column_privilege_id_id _null_ _null_ _null_ ));
DESCR("user privilege on any column by user oid, rel oid");
DATA(insert OID = 3028 ( has_any_column_privilege PGNSP PGUID 12 10 0 0 f f f t f s 2 0 16 "25 25" _null_ _null_ _null_ _null_ has_any_column_privilege_name _null_ _null_ _null_ ));
DESCR("current user privilege on any column by rel name");
DATA(insert OID = 3029 ( has_any_column_privilege PGNSP PGUID 12 10 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_any_column_privilege_id _null_ _null_ _null_ ));
DESCR("current user privilege on any column by rel oid");
DATA(insert OID = 1928 ( pg_stat_get_numscans PGNSP PGUID 12 1 0 0 f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_numscans _null_ _null_ _null_ ));
DESCR("statistics: number of scans done for table/index");
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.330 2009/01/01 17:24:02 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.331 2009/02/06 21:15:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -22,6 +22,24 @@
*/
/* acl.c */
extern Datum has_any_column_privilege_name_name(PG_FUNCTION_ARGS);
extern Datum has_any_column_privilege_name_id(PG_FUNCTION_ARGS);
extern Datum has_any_column_privilege_id_name(PG_FUNCTION_ARGS);
extern Datum has_any_column_privilege_id_id(PG_FUNCTION_ARGS);
extern Datum has_any_column_privilege_name(PG_FUNCTION_ARGS);
extern Datum has_any_column_privilege_id(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_name_name_name(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_name_id_name(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_id_name_name(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_id_id_name(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_name_name(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_name_attnum(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_id_name(PG_FUNCTION_ARGS);
extern Datum has_column_privilege_id_attnum(PG_FUNCTION_ARGS);
extern Datum has_table_privilege_name_name(PG_FUNCTION_ARGS);
extern Datum has_table_privilege_name_id(PG_FUNCTION_ARGS);
extern Datum has_table_privilege_id_name(PG_FUNCTION_ARGS);
......
......@@ -695,8 +695,8 @@ SELECT * FROM information_schema.user_mapping_options ORDER BY lower(authorizati
SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
foreign_data_user | foreign_data_user | regression | | s6 | FOREIGN SERVER | USAGE | NO
foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | YES
foreign_data_user | foreign_data_user | regression | | s6 | FOREIGN SERVER | USAGE | YES
foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
(4 rows)
......@@ -704,8 +704,8 @@ SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIG
SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
foreign_data_user | foreign_data_user | regression | | s6 | FOREIGN SERVER | USAGE | NO
foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | YES
foreign_data_user | foreign_data_user | regression | | s6 | FOREIGN SERVER | USAGE | YES
foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
(4 rows)
......
......@@ -258,10 +258,16 @@ SELECT one FROM atest5; -- ok
1
(1 row)
COPY atest5 (one) TO stdout; -- ok
1
SELECT two FROM atest5; -- fail
ERROR: permission denied for relation atest5
COPY atest5 (two) TO stdout; -- fail
ERROR: permission denied for relation atest5
SELECT atest5 FROM atest5; -- fail
ERROR: permission denied for relation atest5
COPY atest5 (one,two) TO stdout; -- fail
ERROR: permission denied for relation atest5
SELECT 1 FROM atest5; -- ok
?column?
----------
......@@ -324,6 +330,9 @@ SELECT one, two FROM atest5 NATURAL JOIN atest6; -- ok now
-- test column-level privileges for INSERT and UPDATE
INSERT INTO atest5 (two) VALUES (3); -- ok
COPY atest5 FROM stdin; -- fail
ERROR: permission denied for relation atest5
COPY atest5 (two) FROM stdin; -- ok
INSERT INTO atest5 (three) VALUES (4); -- fail
ERROR: permission denied for relation atest5
INSERT INTO atest5 VALUES (5,5,5); -- fail
......@@ -346,6 +355,7 @@ SELECT atest6 FROM atest6; -- ok
--------
(0 rows)
COPY atest6 TO stdout; -- ok
-- test column-level privileges when involved with DELETE
SET SESSION AUTHORIZATION regressuser1;
ALTER TABLE atest6 ADD COLUMN three integer;
......
......@@ -1276,8 +1276,8 @@ drop table cchild;
-- Check that ruleutils are working
--
SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
viewname | definition
--------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
viewname | definition
--------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
pg_cursors | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
pg_group | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
......@@ -1308,7 +1308,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
pg_statio_user_indexes | SELECT pg_statio_all_indexes.relid, pg_statio_all_indexes.indexrelid, pg_statio_all_indexes.schemaname, pg_statio_all_indexes.relname, pg_statio_all_indexes.indexrelname, pg_statio_all_indexes.idx_blks_read, pg_statio_all_indexes.idx_blks_hit FROM pg_statio_all_indexes WHERE ((pg_statio_all_indexes.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_indexes.schemaname !~ '^pg_toast'::text));
pg_statio_user_sequences | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE ((pg_statio_all_sequences.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_sequences.schemaname !~ '^pg_toast'::text));
pg_statio_user_tables | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE ((pg_statio_all_tables.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_tables.schemaname !~ '^pg_toast'::text));
pg_stats | SELECT n.nspname AS schemaname, c.relname AS tablename, a.attname, s.stanullfrac AS null_frac, s.stawidth AS avg_width, s.stadistinct AS n_distinct, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stavalues1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stavalues2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stavalues3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stanumbers1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stanumbers2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stanumbers3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE WHEN (s.stakind1 = 2) THEN s.stavalues1 WHEN (s.stakind2 = 2) THEN s.stavalues2 WHEN (s.stakind3 = 2) THEN s.stavalues3 WHEN (s.stakind4 = 2) THEN s.stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE WHEN (s.stakind1 = 3) THEN s.stanumbers1[1] WHEN (s.stakind2 = 3) THEN s.stanumbers2[1] WHEN (s.stakind3 = 3) THEN s.stanumbers3[1] WHEN (s.stakind4 = 3) THEN s.stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE has_table_privilege(c.oid, 'select'::text);
pg_stats | SELECT n.nspname AS schemaname, c.relname AS tablename, a.attname, s.stanullfrac AS null_frac, s.stawidth AS avg_width, s.stadistinct AS n_distinct, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stavalues1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stavalues2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stavalues3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stanumbers1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stanumbers2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stanumbers3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE WHEN (s.stakind1 = 2) THEN s.stavalues1 WHEN (s.stakind2 = 2) THEN s.stavalues2 WHEN (s.stakind3 = 2) THEN s.stavalues3 WHEN (s.stakind4 = 2) THEN s.stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE WHEN (s.stakind1 = 3) THEN s.stanumbers1[1] WHEN (s.stakind2 = 3) THEN s.stanumbers2[1] WHEN (s.stakind3 = 3) THEN s.stanumbers3[1] WHEN (s.stakind4 = 3) THEN s.stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text));
pg_tables | SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, t.spcname AS tablespace, c.relhasindex AS hasindexes, c.relhasrules AS hasrules, c.relhastriggers AS hastriggers FROM ((pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) WHERE (c.relkind = 'r'::"char");
pg_timezone_abbrevs | SELECT pg_timezone_abbrevs.abbrev, pg_timezone_abbrevs.utc_offset, pg_timezone_abbrevs.is_dst FROM pg_timezone_abbrevs() pg_timezone_abbrevs(abbrev, utc_offset, is_dst);
pg_timezone_names | SELECT pg_timezone_names.name, pg_timezone_names.abbrev, pg_timezone_names.utc_offset, pg_timezone_names.is_dst FROM pg_timezone_names() pg_timezone_names(name, abbrev, utc_offset, is_dst);
......
......@@ -184,8 +184,11 @@ INSERT INTO atest5 VALUES (1,2,3);
SET SESSION AUTHORIZATION regressuser4;
SELECT * FROM atest5; -- fail
SELECT one FROM atest5; -- ok
COPY atest5 (one) TO stdout; -- ok
SELECT two FROM atest5; -- fail
COPY atest5 (two) TO stdout; -- fail
SELECT atest5 FROM atest5; -- fail
COPY atest5 (one,two) TO stdout; -- fail
SELECT 1 FROM atest5; -- ok
SELECT 1 FROM atest5 a JOIN atest5 b USING (one); -- ok
SELECT 1 FROM atest5 a JOIN atest5 b USING (two); -- fail
......@@ -213,6 +216,10 @@ SELECT one, two FROM atest5 NATURAL JOIN atest6; -- ok now
-- test column-level privileges for INSERT and UPDATE
INSERT INTO atest5 (two) VALUES (3); -- ok
COPY atest5 FROM stdin; -- fail
COPY atest5 (two) FROM stdin; -- ok
1
\.
INSERT INTO atest5 (three) VALUES (4); -- fail
INSERT INTO atest5 VALUES (5,5,5); -- fail
UPDATE atest5 SET three = 10; -- ok
......@@ -227,6 +234,7 @@ SET SESSION AUTHORIZATION regressuser4;
SELECT one FROM atest5; -- fail
UPDATE atest5 SET one = 1; -- fail
SELECT atest6 FROM atest6; -- ok
COPY atest6 TO stdout; -- ok
-- test column-level privileges when involved with DELETE
SET SESSION AUTHORIZATION regressuser1;
......
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