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

Reply via email to