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:
+ * If message contains only 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).
+ * If grantee's name len or grantor's name len is {@code -1} then use respecitve
+ * OIDs.
+ * 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.
+ * 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.
+ *
+ * Magic lenght for grantee's or grantor's name -1 means that following
+ * is unnamed, which will be for {@link ACL_ID_PUBLIC}.
+ *
+ * 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);