*
* The result is a boolean value: true if user has the indicated
* privilege, false if not. The variants that take a relation OID
- * and an integer attnum return NULL (rather than throwing an error)
- * if the column doesn't exist or is dropped.
+ * return NULL (rather than throwing an error) if that relation OID
+ * doesn't exist. Likewise, the variants that take an integer attnum
+ * return NULL (rather than throwing an error) if there is no such
+ * pg_attribute entry. All variants return NULL if an attisdropped
+ * column is selected. These rules are meant to avoid unnecessary
+ * failures in queries that scan pg_attribute.
*/
/*
HeapTuple attTuple;
Form_pg_attribute attributeForm;
+ /*
+ * If convert_column_name failed, we can just return -1 immediately.
+ */
+ if (attnum == InvalidAttrNumber)
+ return -1;
+
/*
* First check if we have the privilege at the table level. We check
* existence of the pg_class row before risking calling pg_class_aclcheck.
/*
* Given a table OID and a column name expressed as a string, look it up
- * and return the column number
+ * and return the column number. Returns InvalidAttrNumber in cases
+ * where caller should return NULL instead of failing.
*/
static AttrNumber
convert_column_name(Oid tableoid, text *column)
{
- AttrNumber attnum;
char *colname;
+ HeapTuple attTuple;
+ AttrNumber attnum;
colname = text_to_cstring(column);
- attnum = get_attnum(tableoid, colname);
- if (attnum == InvalidAttrNumber)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("column \"%s\" of relation \"%s\" does not exist",
- colname, get_rel_name(tableoid))));
+
+ /*
+ * We don't use get_attnum() here because it will report that dropped
+ * columns don't exist. We need to treat dropped columns differently from
+ * nonexistent columns.
+ */
+ attTuple = SearchSysCache2(ATTNAME,
+ ObjectIdGetDatum(tableoid),
+ CStringGetDatum(colname));
+ if (HeapTupleIsValid(attTuple))
+ {
+ Form_pg_attribute attributeForm;
+
+ attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
+ /* We want to return NULL for dropped columns */
+ if (attributeForm->attisdropped)
+ attnum = InvalidAttrNumber;
+ else
+ attnum = attributeForm->attnum;
+ ReleaseSysCache(attTuple);
+ }
+ else
+ {
+ char *tablename = get_rel_name(tableoid);
+
+ /*
+ * If the table OID is bogus, or it's just been dropped, we'll get
+ * NULL back. In such cases we want has_column_privilege to return
+ * NULL too, so just return InvalidAttrNumber.
+ */
+ if (tablename != NULL)
+ {
+ /* tableoid exists, colname does not, so throw error */
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ colname, tablename)));
+ }
+ /* tableoid doesn't exist, so act like attisdropped case */
+ attnum = InvalidAttrNumber;
+ }
+
pfree(colname);
return attnum;
}
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
+ if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid)))
+ PG_RETURN_NULL();
+
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
roleid = GetUserId();
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
+ if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid)))
+ PG_RETURN_NULL();
+
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
+ if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid)))
+ PG_RETURN_NULL();
+
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_server_priv_string(priv_type_text);
+ if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid)))
+ PG_RETURN_NULL();
+
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
roleid = GetUserId();
mode = convert_server_priv_string(priv_type_text);
+ if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid)))
+ PG_RETURN_NULL();
+
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
mode = convert_server_priv_string(priv_type_text);
+ if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid)))
+ PG_RETURN_NULL();
+
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_tablespace_priv_string(priv_type_text);
+ if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid)))
+ PG_RETURN_NULL();
+
aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
roleid = GetUserId();
mode = convert_tablespace_priv_string(priv_type_text);
+ if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid)))
+ PG_RETURN_NULL();
+
aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
mode = convert_tablespace_priv_string(priv_type_text);
+ if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid)))
+ PG_RETURN_NULL();
+
aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
f
(1 row)
+-- has_column_privilege function
+-- bad-input checks (as non-super-user)
+select has_column_privilege('pg_authid',NULL,'select');
+ has_column_privilege
+----------------------
+
+(1 row)
+
+select has_column_privilege('pg_authid','nosuchcol','select');
+ERROR: column "nosuchcol" of relation "pg_authid" does not exist
+select has_column_privilege(9999,'nosuchcol','select');
+ has_column_privilege
+----------------------
+
+(1 row)
+
+select has_column_privilege(9999,99::int2,'select');
+ has_column_privilege
+----------------------
+
+(1 row)
+
+select has_column_privilege('pg_authid',99::int2,'select');
+ has_column_privilege
+----------------------
+
+(1 row)
+
+select has_column_privilege(9999,99::int2,'select');
+ has_column_privilege
+----------------------
+
+(1 row)
+
+create temp table mytable(f1 int, f2 int, f3 int);
+alter table mytable drop column f2;
+select has_column_privilege('mytable','f2','select');
+ERROR: column "f2" of relation "mytable" does not exist
+select has_column_privilege('mytable','........pg.dropped.2........','select');
+ has_column_privilege
+----------------------
+
+(1 row)
+
+select has_column_privilege('mytable',2::int2,'select');
+ has_column_privilege
+----------------------
+ t
+(1 row)
+
+revoke select on table mytable from regress_priv_user3;
+select has_column_privilege('mytable',2::int2,'select');
+ has_column_privilege
+----------------------
+
+(1 row)
+
-- Grant options
SET SESSION AUTHORIZATION regress_priv_user1;
CREATE TABLE atest4 (a int);
select has_table_privilege(t1.oid,'trigger')
from (select oid from pg_class where relname = 'atest1') as t1;
+-- has_column_privilege function
+
+-- bad-input checks (as non-super-user)
+select has_column_privilege('pg_authid',NULL,'select');
+select has_column_privilege('pg_authid','nosuchcol','select');
+select has_column_privilege(9999,'nosuchcol','select');
+select has_column_privilege(9999,99::int2,'select');
+select has_column_privilege('pg_authid',99::int2,'select');
+select has_column_privilege(9999,99::int2,'select');
+
+create temp table mytable(f1 int, f2 int, f3 int);
+alter table mytable drop column f2;
+select has_column_privilege('mytable','f2','select');
+select has_column_privilege('mytable','........pg.dropped.2........','select');
+select has_column_privilege('mytable',2::int2,'select');
+revoke select on table mytable from regress_priv_user3;
+select has_column_privilege('mytable',2::int2,'select');
-- Grant options