Implement has_sequence_privilege()
authorJoe Conway
Mon, 3 Aug 2009 21:11:40 +0000 (21:11 +0000)
committerJoe Conway
Mon, 3 Aug 2009 21:11:40 +0000 (21:11 +0000)
Add family of functions that did not exist earlier,
mainly due to historical omission. Original patch by
Abhijit Menon-Sen, with review and modifications by
Joe Conway. catversion.h bumped.

doc/src/sgml/func.sgml
src/backend/utils/adt/acl.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/test/regress/expected/privileges.out
src/test/regress/sql/privileges.sql

index b84f7d18dd73496850646921b297899287e45186..4e5b08d8e431351d7ceeee1e4907857a96eabc06 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
  
   Functions and Operators
@@ -11788,6 +11788,21 @@ SET search_path TO schema schema, ..
        boolean
        does current user have privilege for foreign server
       
+      
+       has_sequence_privilege(user,
+                                  sequence,
+                                  privilege)
+       
+       boolean
+       does user have privilege for sequence
+      
+      
+       has_sequence_privilege(sequence,
+                                  privilege)
+       
+       boolean
+       does current user have privilege for sequence
+      
       
        has_table_privilege(user,
                                   table,
@@ -11861,6 +11876,9 @@ SET search_path TO schema schema, ..
    
     has_server_privilege
    
+   
+    has_sequence_privilege
+   
    
     has_table_privilege
    
@@ -11900,6 +11918,16 @@ SELECT has_table_privilege('joe', 'mytable', 'INSERT, SELECT WITH GRANT OPTION')
 
    
 
+   
+    has_sequence_privilege checks whether a user
+    can access a sequence in a particular way.  The possibilities for its
+    arguments are analogous to has_table_privilege.
+    The desired access privilege type must evaluate to one of
+    USAGE,
+    SELECT, or
+    UPDATE.
+   
+
    
     has_any_column_privilege checks whether a user can
     access any column of a table in a particular way.
index 67c4ea36e361d50bd01a7c70ba6f3a84bf24324f..83d93ad34836241959f5833b70047523a62dba30 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.148 2009/06/11 14:49:03 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.149 2009/08/03 21:11:39 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,7 @@
 #include "catalog/pg_authid.h"
 #include "catalog/pg_auth_members.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_class.h"
 #include "commands/dbcommands.h"
 #include "commands/tablespace.h"
 #include "foreign/foreign.h"
@@ -88,6 +89,7 @@ static AclMode convert_any_priv_string(text *priv_type_text,
 
 static Oid convert_table_name(text *tablename);
 static AclMode convert_table_priv_string(text *priv_type_text);
+static AclMode convert_sequence_priv_string(text *priv_type_text);
 static AttrNumber convert_column_name(Oid tableoid, text *column);
 static AclMode convert_column_priv_string(text *priv_type_text);
 static Oid convert_database_name(text *databasename);
@@ -1704,6 +1706,216 @@ convert_table_priv_string(text *priv_type_text)
    return convert_any_priv_string(priv_type_text, table_priv_map);
 }
 
+/*
+ * has_sequence_privilege variants
+ *     These are all named "has_sequence_privilege" at the SQL level.
+ *     They take various combinations of relation name, relation OID,
+ *     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.
+ */
+
+/*
+ * has_sequence_privilege_name_name
+ *     Check user privileges on a sequence given
+ *     name username, text sequencename, and text priv name.
+ */
+Datum
+has_sequence_privilege_name_name(PG_FUNCTION_ARGS)
+{
+   Name        rolename = PG_GETARG_NAME(0);
+   text       *sequencename = PG_GETARG_TEXT_P(1);
+   text       *priv_type_text = PG_GETARG_TEXT_P(2);
+   Oid         roleid;
+   Oid         sequenceoid;
+   AclMode     mode;
+   AclResult   aclresult;
+
+   roleid = get_roleid_checked(NameStr(*rolename));
+   mode = convert_sequence_priv_string(priv_type_text);
+   sequenceoid = convert_table_name(sequencename);
+   if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
+       ereport(ERROR,
+               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+               errmsg("\"%s\" is not a sequence",
+               text_to_cstring(sequencename))));
+
+   aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
+
+   PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_sequence_privilege_name
+ *     Check user privileges on a sequence given
+ *     text sequencename and text priv name.
+ *     current_user is assumed
+ */
+Datum
+has_sequence_privilege_name(PG_FUNCTION_ARGS)
+{
+   text       *sequencename = PG_GETARG_TEXT_P(0);
+   text       *priv_type_text = PG_GETARG_TEXT_P(1);
+   Oid         roleid;
+   Oid         sequenceoid;
+   AclMode     mode;
+   AclResult   aclresult;
+
+   roleid = GetUserId();
+   mode = convert_sequence_priv_string(priv_type_text);
+   sequenceoid = convert_table_name(sequencename);
+   if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
+       ereport(ERROR,
+               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+               errmsg("\"%s\" is not a sequence",
+               text_to_cstring(sequencename))));
+
+   aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
+
+   PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_sequence_privilege_name_id
+ *     Check user privileges on a sequence given
+ *     name usename, sequence oid, and text priv name.
+ */
+Datum
+has_sequence_privilege_name_id(PG_FUNCTION_ARGS)
+{
+   Name        username = PG_GETARG_NAME(0);
+   Oid         sequenceoid = PG_GETARG_OID(1);
+   text       *priv_type_text = PG_GETARG_TEXT_P(2);
+   Oid         roleid;
+   AclMode     mode;
+   AclResult   aclresult;
+   char        relkind;
+
+   roleid = get_roleid_checked(NameStr(*username));
+   mode = convert_sequence_priv_string(priv_type_text);
+   relkind = get_rel_relkind(sequenceoid);
+   if (relkind == '\0')
+       PG_RETURN_NULL();
+   else if (relkind != RELKIND_SEQUENCE)
+       ereport(ERROR,
+               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+               errmsg("\"%s\" is not a sequence",
+               get_rel_name(sequenceoid))));
+
+   aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
+
+   PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_sequence_privilege_id
+ *     Check user privileges on a sequence given
+ *     sequence oid, and text priv name.
+ *     current_user is assumed
+ */
+Datum
+has_sequence_privilege_id(PG_FUNCTION_ARGS)
+{
+   Oid         sequenceoid = PG_GETARG_OID(0);
+   text       *priv_type_text = PG_GETARG_TEXT_P(1);
+   Oid         roleid;
+   AclMode     mode;
+   AclResult   aclresult;
+   char        relkind;
+
+   roleid = GetUserId();
+   mode = convert_sequence_priv_string(priv_type_text);
+   relkind = get_rel_relkind(sequenceoid);
+   if (relkind == '\0')
+       PG_RETURN_NULL();
+   else if (relkind != RELKIND_SEQUENCE)
+       ereport(ERROR,
+               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+               errmsg("\"%s\" is not a sequence",
+               get_rel_name(sequenceoid))));
+
+   aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
+
+   PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_sequence_privilege_id_name
+ *     Check user privileges on a sequence given
+ *     roleid, text sequencename, and text priv name.
+ */
+Datum
+has_sequence_privilege_id_name(PG_FUNCTION_ARGS)
+{
+   Oid         roleid = PG_GETARG_OID(0);
+   text       *sequencename = PG_GETARG_TEXT_P(1);
+   text       *priv_type_text = PG_GETARG_TEXT_P(2);
+   Oid         sequenceoid;
+   AclMode     mode;
+   AclResult   aclresult;
+
+   mode = convert_sequence_priv_string(priv_type_text);
+   sequenceoid = convert_table_name(sequencename);
+   if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
+       ereport(ERROR,
+               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+               errmsg("\"%s\" is not a sequence",
+               text_to_cstring(sequencename))));
+
+   aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
+
+   PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_sequence_privilege_id_id
+ *     Check user privileges on a sequence given
+ *     roleid, sequence oid, and text priv name.
+ */
+Datum
+has_sequence_privilege_id_id(PG_FUNCTION_ARGS)
+{
+   Oid         roleid = PG_GETARG_OID(0);
+   Oid         sequenceoid = PG_GETARG_OID(1);
+   text       *priv_type_text = PG_GETARG_TEXT_P(2);
+   AclMode     mode;
+   AclResult   aclresult;
+   char        relkind;
+
+   mode = convert_sequence_priv_string(priv_type_text);
+   relkind = get_rel_relkind(sequenceoid);
+   if (relkind == '\0')
+       PG_RETURN_NULL();
+   else if (relkind != RELKIND_SEQUENCE)
+       ereport(ERROR,
+               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+               errmsg("\"%s\" is not a sequence",
+               get_rel_name(sequenceoid))));
+
+   aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
+
+   PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * convert_sequence_priv_string
+ *     Convert text string to AclMode value.
+ */
+static AclMode
+convert_sequence_priv_string(text *priv_type_text)
+{
+   static const priv_map sequence_priv_map[] = {
+       { "USAGE", ACL_USAGE },
+       { "SELECT", ACL_SELECT },
+       { "UPDATE", ACL_UPDATE },
+       { NULL, 0 }
+   };
+
+   return convert_any_priv_string(priv_type_text, sequence_priv_map);
+}
+
 
 /*
  * has_any_column_privilege variants
index dc1b41d06bbcfcfd4b1231a3984998a6f00f02f8..c1b8f6b6a89226c8d1cf19fe480c90c3fa255869 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.535 2009/08/02 22:14:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.536 2009/08/03 21:11:39 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 200908021
+#define CATALOG_VERSION_NO 200908031
 
 #endif
index d5884faa4a6d42468e92452b4d6c827ac23afea8..89effab149159a973b239d5a82726fa8f6485221 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.547 2009/07/29 20:56:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.548 2009/08/03 21:11:39 joe Exp $
  *
  * NOTES
  *   The script catalog/genbki.sh reads this file and generates .bki
@@ -2918,6 +2918,19 @@ DESCR("current user privilege on relation by rel name");
 DATA(insert OID = 1927 (  has_table_privilege         PGNSP PGUID 12 1 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_table_privilege_id _null_ _null_ _null_ ));
 DESCR("current user privilege on relation by rel oid");
 
+DATA(insert OID = 2181 (  has_sequence_privilege          PGNSP PGUID 12 1 0 0 f f f t f s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_   has_sequence_privilege_name_name _null_ _null_ _null_ ));
+DESCR("user privilege on sequence by username, seq name");
+DATA(insert OID = 2182 (  has_sequence_privilege          PGNSP PGUID 12 1 0 0 f f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_   has_sequence_privilege_name_id _null_ _null_ _null_ ));
+DESCR("user privilege on sequence by username, seq oid");
+DATA(insert OID = 2183 (  has_sequence_privilege          PGNSP PGUID 12 1 0 0 f f f t f s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_   has_sequence_privilege_id_name _null_ _null_ _null_ ));
+DESCR("user privilege on sequence by user oid, seq name");
+DATA(insert OID = 2184 (  has_sequence_privilege          PGNSP PGUID 12 1 0 0 f f f t f s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_   has_sequence_privilege_id_id _null_ _null_ _null_ ));
+DESCR("user privilege on sequence by user oid, seq oid");
+DATA(insert OID = 2185 (  has_sequence_privilege          PGNSP PGUID 12 1 0 0 f f f t f s 2 0 16 "25 25" _null_ _null_ _null_ _null_ has_sequence_privilege_name _null_ _null_ _null_ ));
+DESCR("current user privilege on sequence by seq name");
+DATA(insert OID = 2186 (  has_sequence_privilege          PGNSP PGUID 12 1 0 0 f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_sequence_privilege_id _null_ _null_ _null_ ));
+DESCR("current user privilege on sequence by seq 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_ ));
index 481eacf9b9f3fda2f63634b0956e8a07a71902d2..4b92cbcb6084e3e7603b66f98a56beb9c4e14c38 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.336 2009/08/01 19:59:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.337 2009/08/03 21:11:39 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,12 @@ extern Datum has_table_privilege_id_name(PG_FUNCTION_ARGS);
 extern Datum has_table_privilege_id_id(PG_FUNCTION_ARGS);
 extern Datum has_table_privilege_name(PG_FUNCTION_ARGS);
 extern Datum has_table_privilege_id(PG_FUNCTION_ARGS);
+extern Datum has_sequence_privilege_name_name(PG_FUNCTION_ARGS);
+extern Datum has_sequence_privilege_name_id(PG_FUNCTION_ARGS);
+extern Datum has_sequence_privilege_id_name(PG_FUNCTION_ARGS);
+extern Datum has_sequence_privilege_id_id(PG_FUNCTION_ARGS);
+extern Datum has_sequence_privilege_name(PG_FUNCTION_ARGS);
+extern Datum has_sequence_privilege_id(PG_FUNCTION_ARGS);
 extern Datum has_database_privilege_name_name(PG_FUNCTION_ARGS);
 extern Datum has_database_privilege_name_id(PG_FUNCTION_ARGS);
 extern Datum has_database_privilege_id_name(PG_FUNCTION_ARGS);
index a17ff59d0c81182b11f094c21ec7c1ef00cc55e0..809b65621713431156c8038033a23bacc130315c 100644 (file)
@@ -815,8 +815,30 @@ SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION')
  t
 (1 row)
 
+-- has_sequence_privilege tests
+\c -
+CREATE SEQUENCE x_seq;
+GRANT USAGE on x_seq to regressuser2;
+SELECT has_sequence_privilege('regressuser1', 'atest1', 'SELECT');
+ERROR:  "atest1" is not a sequence
+SELECT has_sequence_privilege('regressuser1', 'x_seq', 'INSERT');
+ERROR:  unrecognized privilege type: "INSERT"
+SELECT has_sequence_privilege('regressuser1', 'x_seq', 'SELECT');
+ has_sequence_privilege 
+------------------------
+ f
+(1 row)
+
+SET SESSION AUTHORIZATION regressuser2;
+SELECT has_sequence_privilege('x_seq', 'USAGE');
+ has_sequence_privilege 
+------------------------
+ t
+(1 row)
+
 -- clean up
 \c
+drop sequence x_seq;
 DROP FUNCTION testfunc2(int);
 DROP FUNCTION testfunc4(boolean);
 DROP VIEW atestv1;
index 5aa1012f3f619de7befd2d2222874d6a6c938a7e..917e8e5da4e14513d18cb14f909b436f90a17ec6 100644 (file)
@@ -469,10 +469,27 @@ SELECT has_table_privilege('regressuser3', 'atest4', 'SELECT'); -- false
 SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true
 
 
+-- has_sequence_privilege tests
+\c -
+
+CREATE SEQUENCE x_seq;
+
+GRANT USAGE on x_seq to regressuser2;
+
+SELECT has_sequence_privilege('regressuser1', 'atest1', 'SELECT');
+SELECT has_sequence_privilege('regressuser1', 'x_seq', 'INSERT');
+SELECT has_sequence_privilege('regressuser1', 'x_seq', 'SELECT');
+
+SET SESSION AUTHORIZATION regressuser2;
+
+SELECT has_sequence_privilege('x_seq', 'USAGE');
+
 -- clean up
 
 \c
 
+drop sequence x_seq;
+
 DROP FUNCTION testfunc2(int);
 DROP FUNCTION testfunc4(boolean);