Tom, all, In the attached patch-
* Tom Lane (t...@sss.pgh.pa.us) wrote: > * Some of the information_schema views are specified to respond to > per-column privileges; the column_privileges and columns views > certainly need work now to meet spec, and there might be others. Done. > * It might be appropriate to let the pg_stats view expose stats for > columns you have select privilege for, even if you haven't got it > across the whole table. Done. > * We probably ought to invent has_column_privilege SQL functions > analogous to has_table_privilege; this is not just for completeness, > but is probably necessary to finish the above items. Done. > * ISTM that COPY with a column list should succeed if you have > SELECT or INSERT privilege on just the mentioned columns. Done. > * Perhaps it would be appropriate to let LOCK TABLE succeed if you have > proper permissions on at least one column of the table. However, it's > bad enough that LOCK TABLE examines permissions before locking the table > now; I don't think it ought to be grovelling through the columns without > lock. So this might be a place to leave well enough alone. Left alone. Thanks, Stephen
Index: src/backend/catalog/information_schema.sql =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/catalog/information_schema.sql,v retrieving revision 1.50 diff -c -r1.50 information_schema.sql *** src/backend/catalog/information_schema.sql 20 Jan 2009 09:10:20 -0000 1.50 --- src/backend/catalog/information_schema.sql 3 Feb 2009 03:17:26 -0000 *************** *** 507,523 **** 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) 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 (pg_has_role(u_grantor.oid, 'USAGE') OR pg_has_role(grantee.oid, 'USAGE') --- 507,523 ---- UNION ALL SELECT 0::oid, 'PUBLIC' ) AS grantee (oid, rolname), ! (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(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') *************** *** 677,683 **** 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') ); GRANT SELECT ON columns TO PUBLIC; --- 677,687 ---- 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') ! OR has_column_privilege(c.oid, a.attnum, 'INSERT') ! OR has_column_privilege(c.oid, a.attnum, 'UPDATE') ! OR has_column_privilege(c.oid, a.attnum, 'REFERENCES')); GRANT SELECT ON columns TO PUBLIC; Index: src/backend/catalog/system_views.sql =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/catalog/system_views.sql,v retrieving revision 1.58 diff -c -r1.58 system_views.sql *** src/backend/catalog/system_views.sql 1 Jan 2009 17:23:37 -0000 1.58 --- src/backend/catalog/system_views.sql 3 Feb 2009 03:17:26 -0000 *************** *** 137,143 **** 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'); REVOKE ALL on pg_statistic FROM public; --- 137,144 ---- 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') OR ! has_column_privilege(c.oid, a.attnum, 'select'); REVOKE ALL on pg_statistic FROM public; Index: src/backend/commands/copy.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/copy.c,v retrieving revision 1.304 diff -c -r1.304 copy.c *** src/backend/commands/copy.c 2 Jan 2009 20:42:00 -0000 1.304 --- src/backend/commands/copy.c 3 Feb 2009 03:17:26 -0000 *************** *** 711,717 **** * or write to a file. * * Do not allow the copy if user doesn't have proper permission to access ! * the table. */ uint64 DoCopy(const CopyStmt *stmt, const char *queryString) --- 711,717 ---- * or write to a file. * * Do not allow the copy if user doesn't have proper permission to access ! * the table or the specifically requested columns. */ uint64 DoCopy(const CopyStmt *stmt, const char *queryString) *************** *** 723,729 **** List *force_quote = NIL; List *force_notnull = NIL; AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT); ! AclResult aclresult; ListCell *option; TupleDesc tupDesc; int num_phys_attrs; --- 723,730 ---- List *force_quote = NIL; List *force_notnull = NIL; AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT); ! AclMode relPerms; ! AclMode remainingPerms; ListCell *option; TupleDesc tupDesc; int num_phys_attrs; *************** *** 973,986 **** cstate->rel = heap_openrv(stmt->relation, (is_from ? RowExclusiveLock : AccessShareLock)); - /* 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)); - /* check read-only transaction */ if (XactReadOnly && is_from && !isTempNamespace(RelationGetNamespace(cstate->rel))) --- 974,979 ---- *************** *** 996,1001 **** --- 989,1021 ---- RelationGetRelationName(cstate->rel)))); tupDesc = RelationGetDescr(cstate->rel); + + /* Check permissions (relation and column). */ + relPerms = pg_class_aclmask(RelationGetRelid(cstate->rel), + GetUserId(), + required_access, ACLMASK_ALL); + remainingPerms = required_access & ~relPerms; + + /* Check if we have column-level permissions sufficient for this + * operation. */ + if (remainingPerms != 0) + { + 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)); + } + } } else { Index: src/backend/utils/adt/acl.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/acl.c,v retrieving revision 1.146 diff -c -r1.146 acl.c *** src/backend/utils/adt/acl.c 22 Jan 2009 20:16:06 -0000 1.146 --- src/backend/utils/adt/acl.c 3 Feb 2009 03:17:26 -0000 *************** *** 1420,1425 **** --- 1420,1904 ---- /* + * 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 + * return NULL if the OID doesn't exist (rather than failing, as + * they did before Postgres 8.4). + */ + + /* + * 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); + char *colname; + Oid roleid; + Oid tableoid; + AttrNumber colattnum; + AclMode mode; + AclResult aclresult; + + roleid = get_roleid_checked(NameStr(*rolename)); + tableoid = convert_table_name(tablename); + + /* Get the number of the column */ + colname = text_to_cstring(column); + + colattnum = get_attnum(tableoid, colname); + if (colattnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + colname, text_to_cstring(tablename)))); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_name_name_attnum + * Check user privileges on a column given + * name username, text tablename, int attnum, and text priv name. + */ + Datum + has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS) + { + 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; + AclResult aclresult; + + roleid = get_roleid_checked(NameStr(*rolename)); + tableoid = convert_table_name(tablename); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * 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); + char *colname; + AttrNumber colattnum; + Oid roleid; + Oid tableoid; + AclMode mode; + AclResult aclresult; + + roleid = GetUserId(); + tableoid = convert_table_name(tablename); + + /* Get the number of the column */ + colname = text_to_cstring(column); + + colattnum = get_attnum(tableoid, colname); + if (colattnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + colname, text_to_cstring(tablename)))); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_name_attnum + * Check user privileges on a column given + * text tablename, column 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; + AclResult aclresult; + + roleid = GetUserId(); + tableoid = convert_table_name(tablename); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_name_id_name + * Check user privileges on a column given + * name usename, table oid, text colname, and text priv name. + */ + Datum + has_column_privilege_name_id_name(PG_FUNCTION_ARGS) + { + Name username = PG_GETARG_NAME(0); + Oid tableoid = PG_GETARG_OID(1); + text *column = PG_GETARG_TEXT_P(2); + text *priv_type_text = PG_GETARG_TEXT_P(3); + char *colname; + Oid roleid; + AttrNumber colattnum; + AclMode mode; + AclResult aclresult; + + roleid = get_roleid_checked(NameStr(*username)); + + if (!SearchSysCacheExists(RELOID, + ObjectIdGetDatum(tableoid), + 0, 0, 0)) + PG_RETURN_NULL(); + + /* Get the number of the column */ + colname = text_to_cstring(column); + + colattnum = get_attnum(tableoid, colname); + if (colattnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation with OID %u does not exist", + colname, tableoid))); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_name_id_attnum + * Check user privileges on a column given + * name usename, 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; + AclResult aclresult; + + roleid = get_roleid_checked(NameStr(*username)); + + if (!SearchSysCacheExists(RELOID, + ObjectIdGetDatum(tableoid), + 0, 0, 0)) + PG_RETURN_NULL(); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_id_name + * Check user privileges on a table given + * table oid, text column, 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); + char *colname; + Oid roleid; + AttrNumber colattnum; + AclMode mode; + AclResult aclresult; + + roleid = GetUserId(); + + if (!SearchSysCacheExists(RELOID, + ObjectIdGetDatum(tableoid), + 0, 0, 0)) + PG_RETURN_NULL(); + + /* Get the number of the column */ + colname = text_to_cstring(column); + + colattnum = get_attnum(tableoid, colname); + if (colattnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation with OID %u does not exist", + colname, tableoid))); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_id_attnum + * Check user privileges on a table 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; + AclResult aclresult; + + roleid = GetUserId(); + + if (!SearchSysCacheExists(RELOID, + ObjectIdGetDatum(tableoid), + 0, 0, 0)) + PG_RETURN_NULL(); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_id_name_name + * Check user privileges on a column given + * 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); + char *colname; + Oid tableoid; + AttrNumber colattnum; + AclMode mode; + AclResult aclresult; + + tableoid = convert_table_name(tablename); + + /* Get the number of the column */ + colname = text_to_cstring(column); + + colattnum = get_attnum(tableoid, colname); + if (colattnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + colname, text_to_cstring(tablename)))); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_id_name_attnum + * Check user privileges on a column given + * 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; + AclResult aclresult; + + tableoid = convert_table_name(tablename); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_id_id_name + * Check user privileges on a column given + * 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); + char *colname; + AttrNumber colattnum; + AclMode mode; + AclResult aclresult; + + if (!SearchSysCacheExists(RELOID, + ObjectIdGetDatum(tableoid), + 0, 0, 0)) + PG_RETURN_NULL(); + + /* Get the number of the column */ + colname = text_to_cstring(column); + + colattnum = get_attnum(tableoid, colname); + if (colattnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation with OID %u does not exist", + colname, tableoid))); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* + * has_column_privilege_id_id_attnum + * Check user privileges on a column given + * roleid, table oid, int colnum, 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; + AclResult aclresult; + + if (!SearchSysCacheExists(RELOID, + ObjectIdGetDatum(tableoid), + 0, 0, 0)) + PG_RETURN_NULL(); + + mode = convert_table_priv_string(priv_type_text); + if (mode & ~((AclMode) ACL_ALL_RIGHTS_COLUMN)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid privilege type %s for column", + text_to_cstring(priv_type_text)))); + + aclresult = pg_attribute_aclcheck(tableoid, colattnum, roleid, mode); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); + } + + /* * has_table_privilege variants * These are all named "has_table_privilege" at the SQL level. * They take various combinations of relation name, relation OID, Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v retrieving revision 1.535 diff -c -r1.535 pg_proc.h *** src/include/catalog/pg_proc.h 1 Jan 2009 17:23:57 -0000 1.535 --- src/include/catalog/pg_proc.h 3 Feb 2009 03:17:26 -0000 *************** *** 2913,2918 **** --- 2913,2942 ---- 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 = 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"); Index: src/include/utils/builtins.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/utils/builtins.h,v retrieving revision 1.330 diff -c -r1.330 builtins.h *** src/include/utils/builtins.h 1 Jan 2009 17:24:02 -0000 1.330 --- src/include/utils/builtins.h 3 Feb 2009 03:17:26 -0000 *************** *** 22,27 **** --- 22,39 ---- */ /* acl.c */ + 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); Index: src/test/regress/expected/privileges.out =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/privileges.out,v retrieving revision 1.44 diff -c -r1.44 privileges.out *** src/test/regress/expected/privileges.out 27 Jan 2009 12:40:15 -0000 1.44 --- src/test/regress/expected/privileges.out 3 Feb 2009 03:17:26 -0000 *************** *** 258,267 **** --- 258,273 ---- 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,329 **** --- 330,338 ---- -- 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,351 **** --- 355,361 ---- -------- (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; Index: src/test/regress/expected/rules.out =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/rules.out,v retrieving revision 1.148 diff -c -r1.148 rules.out *** src/test/regress/expected/rules.out 27 Jan 2009 12:40:15 -0000 1.148 --- src/test/regress/expected/rules.out 3 Feb 2009 03:17:26 -0000 *************** *** 1276,1283 **** -- Check that ruleutils are working -- SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname; ! 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); --- 1276,1283 ---- -- Check that ruleutils are working -- SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname; ! 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,1314 **** 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_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); --- 1308,1314 ---- 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) OR 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); Index: src/test/regress/sql/privileges.sql =================================================================== RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/privileges.sql,v retrieving revision 1.23 diff -c -r1.23 privileges.sql *** src/test/regress/sql/privileges.sql 22 Jan 2009 20:16:10 -0000 1.23 --- src/test/regress/sql/privileges.sql 3 Feb 2009 03:17:26 -0000 *************** *** 184,191 **** --- 184,194 ---- 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,218 **** --- 216,225 ---- -- 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,232 **** --- 234,240 ---- 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;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers