Hi,

Actaully one more POD left it's aclitem :). In Java for e.g. it is used to 
obtain column priviliges, I assume some folks may want to use it too.

I tested only recv :-(

Acually I don't know if idea of such format is OK, but my intention was to 
send roles names, so driver don't need to ask for name (like for regproc) and 
to keep together human-based approch (text) and binary approch.

Kind regards,
Radek
diff --git a/.gitignore b/.gitignore
index 1be11e8..0d594f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,5 @@ objfiles.txt
 /GNUmakefile
 /config.log
 /config.status
+/nbproject/private/
+/nbproject
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 691ba3b..33877cb 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -33,6 +33,7 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/syscache.h"
+#include "libpq/pqformat.h"
 
 
 typedef struct
@@ -78,6 +79,10 @@ static void putid(char *p, const char *s);
 static Acl *allocacl(int n);
 static void check_acl(const Acl *acl);
 static const char *aclparse(const char *s, AclItem *aip);
+
+/** Assigns default grantor and send warning. */
+static void aclitem_assign_default_grantor(AclItem *aip);
+
 static bool aclitem_match(const AclItem *a1, const AclItem *a2);
 static int	aclitemComparator(const void *arg1, const void *arg2);
 static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
@@ -209,6 +214,14 @@ putid(char *p, const char *s)
 	*p = '\0';
 }
 
+/** Assigns default grantor and send warning. */
+void aclitem_assign_default_grantor(AclItem *aip) {
+    aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
+    ereport(WARNING,
+                    (errcode(ERRCODE_INVALID_GRANTOR),
+                     errmsg("defaulting grantor to user ID %u",
+                                    BOOTSTRAP_SUPERUSERID)));
+}
 /*
  * aclparse
  *		Consumes and parses an ACL specification of the form:
@@ -343,11 +356,7 @@ aclparse(const char *s, AclItem *aip)
 	}
 	else
 	{
-		aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
-		ereport(WARNING,
-				(errcode(ERRCODE_INVALID_GRANTOR),
-				 errmsg("defaulting grantor to user ID %u",
-						BOOTSTRAP_SUPERUSERID)));
+            aclitem_assign_default_grantor(aip);
 	}
 
 	ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
@@ -643,6 +652,143 @@ aclitemout(PG_FUNCTION_ARGS)
 
 	PG_RETURN_CSTRING(out);
 }
+/** Do binary read of aclitem. Input format is same as {@link aclitem_recv}, but
+ * special algorithm is used to determine grantee's and grantor's OID. The reason
+ * is to keep backward "information" compatiblity with text mode - typical
+ * client (which gets instructions from user)
+ * may be much more interested in sending grantee and grantors name then
+ * OID. Detailed rule is as follow:<br/>
+ * If message contains <b>only</b> oids and privs (no name and names' length) then
+ * use passed OIDs (message may be truncated, we accept this, 
+ * but both, two last fields must be not present).<br/>
+ * If grantee's name len or grantor's name len is {@code -1} then use respecitve
+ * OIDs.<br/>
+ * If name length is not {@code -1} then find OID for given part, and
+ * ensure that respective OID is {@code 0} or is equal to found OID.</br>
+ * If grantor's OID is {@code 0} and grantor's name lenght is {@code -1} or 
+ * truncated then assign superuser as grantor.
+ */
+Datum
+aclitemrecv(PG_FUNCTION_ARGS) {
+    StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+    AclItem    *aip;
+    int        gRawLen;
+    char       *gVal = NULL;
+    int        gValLen;
+    Oid        gOid;
+
+    aip = (AclItem *) palloc(sizeof(AclItem));
+    aip->ai_grantee = pq_getmsgint(buf, 4);
+    aip->ai_grantor = pq_getmsgint(buf, 4);
+    aip->ai_privs = pq_getmsgint(buf, 4);
+    
+    /* Client has passed names. */
+    if (buf->cursor < buf->len) {
+        /* Read grantee. */
+        gRawLen = pq_getmsgint(buf, 4);
+        if (gRawLen != -1) {
+            gVal = pq_getmsgtext(buf, gRawLen, &gValLen);
+            gOid = get_role_oid(gVal, false);
+            if (aip->ai_grantee != 0 && aip->ai_grantee != gOid) {
+                ereport(ERROR,
+                            (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+                            errmsg("grantee's OID is not 0 and passed grantee's name and grantee's OID doesn't match")));
+                
+            }
+        }
+        
+        /* Read grantor. */
+        gRawLen = pq_getmsgint(buf, 4);
+        if (gRawLen != -1) {
+            gVal = pq_getmsgtext(buf, gRawLen, &gValLen);
+            gOid = get_role_oid(gVal, false);
+            if (aip->ai_grantor != 0 && aip->ai_grantor != gOid) {
+                ereport(ERROR,
+                            (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+                            errmsg("grantor's OID is not 0 and passed grantor's name and grantor's OID doesn't match")));
+            }
+        }else {
+            gVal = NULL;
+        }
+    }
+    
+    if (aip->ai_grantor == 0 && gVal == NULL)
+        aclitem_assign_default_grantor(aip);
+    
+    PG_RETURN_ACLITEM_P(aip);
+}
+/**
+ * aclitem_send
+ *		Allocates storage for, and fills in, a new null-delimited string
+ *		containing a formatted ACL specification.  See aclparse for details.
+ * 
+ *              The output format is as follows:
+ *              grantee's oid, grantor's oid
+ *              rights - 32 bit number, 1st 16 bit describes grantor rights
+ *              grentee's name length
+ *              grantee's name
+ *              grantor's name length
+ *              grantor's name
+ * "Number of rights" - describes how many rights PSQL has defined. Each right
+ * has internal number and is represented by bit 1 set on n-th internal positon.
+ * First 16 (currently we have 11) rights are packed in int, for more additional
+ * byte will be added, so you may think about rights like "Number of rights" bit
+ * long number (rounded up to multiplicity of 8 bits), but no shorter then 16 bits.
+ * <br/>
+ * Magic lenght for grantee's or grantor's name -1 means that following
+ * is unnamed, which will be for {@link ACL_ID_PUBLIC}.
+ * <br/>
+ * Last elements are used to pass "usefull" information to client, so it
+ * don't need to query for those names, actually client may be more
+ * interested in getting those names, then OIDs. It will keep backward
+ * compatibility with text mode, as well.
+ */
+Datum
+aclitemsend(PG_FUNCTION_ARGS)
+{
+	AclItem    *aip = PG_GETARG_ACLITEM_P(0);
+	char	   *oidName;
+	HeapTuple	htup;
+        StringInfoData  buf;
+        
+        pq_begintypsend(&buf);
+        
+        pq_sendint(&buf, aip->ai_grantee, 4);
+        pq_sendint(&buf, aip->ai_grantor, 4);
+        pq_sendint(&buf, aip->ai_privs, 4);
+        
+        if (N_ACL_RIGHTS > 16) {
+            /* We sends rights as long (16 bit), but if in future number
+             * of rights will increase we got problem.
+             */
+        }
+        
+        /** Append names at the end. */
+	if (aip->ai_grantee != ACL_ID_PUBLIC) {
+		htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantee));
+		if (HeapTupleIsValid(htup)) {
+			oidName = NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname);
+                        pq_sendcountedtext(&buf, oidName, strlen(oidName), false);
+			ReleaseSysCache(htup);
+		}else {
+                    pq_sendint(&buf,-1, 4);
+		}
+	}else {
+            pq_sendint(&buf, -1, 4);
+        }
+
+	htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantor));
+	if (HeapTupleIsValid(htup)) {
+            oidName = NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname);
+            pq_sendcountedtext(&buf, oidName, strlen(oidName), false);
+            ReleaseSysCache(htup);
+	}
+	else {
+            pq_sendint(&buf, -1, 4);
+	}
+
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
 
 /*
  * aclitem_match
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 8c940bb..c56d8f8 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4230,6 +4230,10 @@ DATA(insert OID = 3120 (  void_recv			   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 22
 DESCR("I/O");
 DATA(insert OID = 3121 (  void_send			   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 17 "2278" _null_ _null_ _null_ _null_	void_send _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 3122 (  aclitemrecv			   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 1033 "2281" _null_ _null_ _null_ _null_ aclitemrecv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 3123 (  aclitemsend			   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 17 "1033" _null_ _null_ _null_ _null_	aclitemsend _null_ _null_ _null_ ));
+DESCR("I/O");
 
 /* System-view support functions with pretty-print option */
 DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 1 0 0 f f f t f s 2 0 25 "26 16" _null_ _null_ _null_ _null_	pg_get_ruledef_ext _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 9baed6c..f89ed44 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -462,7 +462,7 @@ DATA(insert OID = 1023 (  _abstime	 PGNSP PGUID -1 f b A f t \054 0 702 0 array_
 DATA(insert OID = 1024 (  _reltime	 PGNSP PGUID -1 f b A f t \054 0 703 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
 DATA(insert OID = 1025 (  _tinterval PGNSP PGUID -1 f b A f t \054 0 704 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
 DATA(insert OID = 1027 (  _polygon	 PGNSP PGUID -1 f b A f t \054 0 604 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 0 _null_ _null_ ));
-DATA(insert OID = 1033 (  aclitem	 PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout - - - - - i p f 0 -1 0 0 _null_ _null_ ));
+DATA(insert OID = 1033 (  aclitem	 PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout aclitemrecv aclitemsend - - - i p f 0 -1 0 0 _null_ _null_ ));
 DESCR("access control list");
 #define ACLITEMOID		1033
 DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ ));
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 1e9cf7f..1ca959d 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -239,6 +239,8 @@ extern void initialize_acl(void);
  */
 extern Datum aclitemin(PG_FUNCTION_ARGS);
 extern Datum aclitemout(PG_FUNCTION_ARGS);
+extern Datum aclitemrecv(PG_FUNCTION_ARGS);
+extern Datum aclitemsend(PG_FUNCTION_ARGS);
 extern Datum aclinsert(PG_FUNCTION_ARGS);
 extern Datum aclremove(PG_FUNCTION_ARGS);
 extern Datum aclcontains(PG_FUNCTION_ARGS);
-- 
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