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)
......
This diff is collapsed.
......@@ -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
{
......
This diff is collapsed.
......@@ -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;
......
This diff is collapsed.
......@@ -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