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
This commit is contained in:
Tom Lane 2009-02-06 21:15:12 +00:00
parent 0274e1b949
commit 7449427a1e
14 changed files with 1330 additions and 463 deletions

View File

@ -1,4 +1,4 @@
<!-- $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

View File

@ -1,4 +1,4 @@
<!-- $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>

View File

@ -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);
continue;
isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
/* ignore dropped columns */
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);
/* ignore dropped columns */
if (isdropped)
continue;
if (pg_attribute_aclmask(table_oid, curr_att, roleid,
mode, ACLMASK_ANY) != 0)
if (attmask != 0)
{
result = ACLCHECK_OK;
if (how == ACLMASK_ANY)

View File

@ -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;

View File

@ -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;

View File

@ -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
{

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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");

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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;