diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c
index 482bb924dcb4320e06c66002cf7087f1e3da876d..bab118573037a667be0b1c751f78727b7752b95b 100644
--- a/src/backend/access/heap/tuptoaster.c
+++ b/src/backend/access/heap/tuptoaster.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.9 2000/07/22 11:18:46 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.10 2000/07/31 22:39:17 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -273,7 +273,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
 
 			/* ----------
 			 * If the old value is an external stored one, check if it
-			 * has changed so we have to detele it later.
+			 * has changed so we have to delete it later.
 			 * ----------
 			 */
 			if (!old_isnull && att[i]->attlen == -1 && 
@@ -336,17 +336,16 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
 		if (att[i]->attlen == -1)
 		{
 			/* ----------
-			 * If the tables attribute say's PLAIN allways, we
-			 * do so below.
+			 * If the table's attribute says PLAIN always, force it so.
 			 * ----------
 			 */
 			if (att[i]->attstorage == 'p')
 				toast_action[i] = 'p';
 
 			/* ----------
-			 * We're running for UPDATE, so any TOASTed value we find
-			 * still in the tuple must be someone elses we cannot reuse.
-			 * Expand it to plain and eventually toast it again below.
+			 * We took care of UPDATE above, so any TOASTed value we find
+			 * still in the tuple must be someone else's we cannot reuse.
+			 * Expand it to plain (and, probably, toast it again below).
 			 * ----------
 			 */
 			if (VARATT_IS_EXTENDED(DatumGetPointer(toast_values[i])))
@@ -367,7 +366,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
 		else
 		{
 			/* ----------
-			 * Not a variable size attribute, plain storage allways
+			 * Not a variable size attribute, plain storage always
 			 * ----------
 			 */
 			toast_action[i] = 'p';
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index c342b067ff4078b610db7eae0eb8197d6d8894b7..6be489a0c74eb7a5650f15f988aa33c22c56a0eb 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.38 2000/04/12 17:14:55 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.39 2000/07/31 22:39:13 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -33,7 +33,8 @@
 #include "utils/acl.h"
 #include "utils/syscache.h"
 
-static int32 aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode);
+static int32 aclcheck(char *relname, Acl *acl, AclId id,
+					  AclIdType idtype, AclMode mode);
 
 /*
  * Enable use of user relations in place of real system catalogs.
@@ -68,14 +69,16 @@ char	   *aclcheck_error_strings[] = {
 static
 dumpacl(Acl *acl)
 {
-	unsigned	i;
+	int			i;
 	AclItem    *aip;
 
 	elog(DEBUG, "acl size = %d, # acls = %d",
 		 ACL_SIZE(acl), ACL_NUM(acl));
-	aip = (AclItem *) ACL_DAT(acl);
+	aip = ACL_DAT(acl);
 	for (i = 0; i < ACL_NUM(acl); ++i)
-		elog(DEBUG, "	acl[%d]: %s", i, aclitemout(aip + i));
+		elog(DEBUG, "	acl[%d]: %s", i,
+			 DatumGetCString(DirectFunctionCall1(aclitemout,
+												 PointerGetDatum(aip + i))));
 }
 
 #endif
@@ -89,7 +92,7 @@ ChangeAcl(char *relname,
 		  unsigned modechg)
 {
 	unsigned	i;
-	Acl		   *old_acl = (Acl *) NULL,
+	Acl		   *old_acl,
 			   *new_acl;
 	Relation	relation;
 	HeapTuple	tuple;
@@ -97,14 +100,12 @@ ChangeAcl(char *relname,
 	char		nulls[Natts_pg_class];
 	char		replaces[Natts_pg_class];
 	Relation	idescs[Num_pg_class_indices];
-	int			free_old_acl = 0;
+	bool		isNull;
+	bool		free_old_acl = false;
 
 	/*
 	 * Find the pg_class tuple matching 'relname' and extract the ACL. If
 	 * there's no ACL, create a default using the pg_class.relowner field.
-	 *
-	 * We can't use the syscache here, since we need to do a heap_update on
-	 * the tuple we find.
 	 */
 	relation = heap_openr(RelationRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheTuple(RELNAME,
@@ -117,25 +118,37 @@ ChangeAcl(char *relname,
 			 relname);
 	}
 
-	if (!heap_attisnull(tuple, Anum_pg_class_relacl))
-		old_acl = (Acl *) heap_getattr(tuple,
-									   Anum_pg_class_relacl,
-									   RelationGetDescr(relation),
-									   (bool *) NULL);
-	if (!old_acl || ACL_NUM(old_acl) < 1)
+	old_acl = (Acl *) heap_getattr(tuple,
+								   Anum_pg_class_relacl,
+								   RelationGetDescr(relation),
+								   &isNull);
+	if (isNull)
 	{
 #ifdef ACLDEBUG_TRACE
 		elog(DEBUG, "ChangeAcl: using default ACL");
 #endif
-/*		old_acl = acldefault(((Form_pg_class) GETSTRUCT(tuple))->relowner); */
 		old_acl = acldefault(relname);
-		free_old_acl = 1;
+		free_old_acl = true;
+	}
+
+	/* Need to detoast the old ACL for modification */
+	old_acl = DatumGetAclP(PointerGetDatum(old_acl));
+
+	if (ACL_NUM(old_acl) < 1)
+	{
+#ifdef ACLDEBUG_TRACE
+		elog(DEBUG, "ChangeAcl: old ACL has zero length");
+#endif
+		old_acl = acldefault(relname);
+		free_old_acl = true;
 	}
 
 #ifdef ACLDEBUG_TRACE
 	dumpacl(old_acl);
 #endif
+
 	new_acl = aclinsert3(old_acl, mod_aip, modechg);
+
 #ifdef ACLDEBUG_TRACE
 	dumpacl(new_acl);
 #endif
@@ -148,7 +161,7 @@ ChangeAcl(char *relname,
 										 * anyway */
 	}
 	replaces[Anum_pg_class_relacl - 1] = 'r';
-	values[Anum_pg_class_relacl - 1] = (Datum) new_acl;
+	values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
 	tuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
 
 	heap_update(relation, &tuple->t_self, tuple, NULL);
@@ -193,20 +206,20 @@ get_groname(AclId grosysid)
 	if (HeapTupleIsValid(tuple))
 		name = NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname);
 	else
-		elog(NOTICE, "get_groname: group %d not found", grosysid);
+		elog(NOTICE, "get_groname: group %u not found", grosysid);
 	return name;
 }
 
-static int32
+static bool
 in_group(AclId uid, AclId gid)
 {
 	Relation	relation;
 	HeapTuple	tuple;
 	Acl		   *tmp;
-	unsigned	i,
+	int			i,
 				num;
 	AclId	   *aidp;
-	int32		found = 0;
+	bool		found = false;
 
 	relation = heap_openr(GroupRelationName, RowExclusiveLock);
 	tuple = SearchSysCacheTuple(GROSYSID,
@@ -219,13 +232,15 @@ in_group(AclId uid, AclId gid)
 									  Anum_pg_group_grolist,
 									  RelationGetDescr(relation),
 									  (bool *) NULL);
+		/* be sure the IdList is not toasted */
+		tmp = DatumGetIdListP(PointerGetDatum(tmp));
 		/* XXX make me a function */
 		num = IDLIST_NUM(tmp);
 		aidp = IDLIST_DAT(tmp);
 		for (i = 0; i < num; ++i)
 			if (aidp[i] == uid)
 			{
-				found = 1;
+				found = true;
 				break;
 			}
 	}
@@ -344,8 +359,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
 {
 	HeapTuple	tuple;
 	AclId		id;
-	Acl		   *acl = (Acl *) NULL,
-			   *tmp;
+	Acl		   *acl = (Acl *) NULL;
 	int32		result;
 	Relation	relation;
 
@@ -396,12 +410,11 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
 	}
 	if (!heap_attisnull(tuple, Anum_pg_class_relacl))
 	{
-		tmp = (Acl *) heap_getattr(tuple,
-								   Anum_pg_class_relacl,
-								   RelationGetDescr(relation),
-								   (bool *) NULL);
-		acl = makeacl(ACL_NUM(tmp));
-		memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
+		/* get a detoasted copy of the ACL */
+		acl = DatumGetAclPCopy(heap_getattr(tuple,
+											Anum_pg_class_relacl,
+											RelationGetDescr(relation),
+											(bool *) NULL));
 	}
 	else
 	{
@@ -410,13 +423,10 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
 		 * if the acl is null, by default the owner can do whatever he
 		 * wants to with it
 		 */
-		int4		ownerId;
+		AclId		ownerId;
 
-		ownerId = (int4) heap_getattr(tuple,
-									  Anum_pg_class_relowner,
-									  RelationGetDescr(relation),
-									  (bool *) NULL);
-		acl = aclownerdefault(relname, (AclId) ownerId);
+		ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
+		acl = aclownerdefault(relname, ownerId);
 	}
 	heap_close(relation, RowExclusiveLock);
 #else
@@ -427,12 +437,11 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
 	if (HeapTupleIsValid(tuple) &&
 		!heap_attisnull(tuple, Anum_pg_class_relacl))
 	{
-		tmp = (Acl *) heap_getattr(tuple,
-								   Anum_pg_class_relacl,
-								   RelationGetDescr(relation),
-								   (bool *) NULL);
-		acl = makeacl(ACL_NUM(tmp));
-		memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
+		/* get a detoasted copy of the ACL */
+		acl = DatumGetAclPCopy(heap_getattr(tuple,
+											Anum_pg_class_relacl,
+											RelationGetDescr(relation),
+											(bool *) NULL));
 	}
 	heap_close(relation, RowExclusiveLock);
 #endif
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 4cbaba9b12f8531bcc702927da56bd5dc3be90cc..c4f1228dbcf05d1a6c55c188c6c99fba0c5c470f 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.47 2000/06/14 18:17:42 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.48 2000/07/31 22:39:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,8 +26,8 @@
 #include "utils/syscache.h"
 
 static char *getid(char *s, char *n);
-static int32 aclitemeq(AclItem *a1, AclItem *a2);
-static int32 aclitemgt(AclItem *a1, AclItem *a2);
+static bool aclitemeq(AclItem *a1, AclItem *a2);
+static bool aclitemgt(AclItem *a1, AclItem *a2);
 static char *aclparse(char *s, AclItem *aip, unsigned *modechg);
 
 #define ACL_IDTYPE_GID_KEYWORD	"group"
@@ -229,18 +229,14 @@ makeacl(int n)
  * RETURNS:
  *		the new AclItem
  */
-AclItem    *
-aclitemin(char *s)
+Datum
+aclitemin(PG_FUNCTION_ARGS)
 {
-	unsigned	modechg;
+	char	   *s = PG_GETARG_CSTRING(0);
 	AclItem    *aip;
-
-	if (!s)
-		elog(ERROR, "aclitemin: null string");
+	unsigned	modechg;
 
 	aip = (AclItem *) palloc(sizeof(AclItem));
-	if (!aip)
-		elog(ERROR, "aclitemin: palloc failed");
 	s = aclparse(s, aip, &modechg);
 	if (modechg != ACL_MODECHG_EQL)
 		elog(ERROR, "aclitemin: cannot accept anything but = ACLs");
@@ -248,7 +244,7 @@ aclitemin(char *s)
 		++s;
 	if (*s)
 		elog(ERROR, "aclitemin: extra garbage at end of specification");
-	return aip;
+	PG_RETURN_ACLITEM_P(aip);
 }
 
 /*
@@ -259,24 +255,17 @@ aclitemin(char *s)
  * RETURNS:
  *		the new string
  */
-char *
-aclitemout(AclItem *aip)
+Datum
+aclitemout(PG_FUNCTION_ARGS)
 {
+	AclItem	   *aip = PG_GETARG_ACLITEM_P(0);
 	char	   *p;
 	char	   *out;
 	HeapTuple	htup;
 	unsigned	i;
-	static AclItem default_aclitem = {ACL_ID_WORLD,
-		ACL_IDTYPE_WORLD,
-	ACL_WORLD_DEFAULT};
 	char	   *tmpname;
 
-	if (!aip)
-		aip = &default_aclitem;
-
 	p = out = palloc(strlen("group =arwR ") + 1 + NAMEDATALEN);
-	if (!out)
-		elog(ERROR, "aclitemout: palloc failed");
 	*p = '\0';
 
 	switch (aip->ai_idtype)
@@ -319,36 +308,28 @@ aclitemout(AclItem *aip)
 			*p++ = ACL_MODE_STR[i];
 	*p = '\0';
 
-	return out;
+	PG_RETURN_CSTRING(out);
 }
 
 /*
  * aclitemeq
  * aclitemgt
  *		AclItem equality and greater-than comparison routines.
- *		Two AclItems are equal iff they are both NULL or they have the
+ *		Two AclItems are equal iff they have the
  *		same identifier (and identifier type).
  *
  * RETURNS:
  *		a boolean value indicating = or >
  */
-static int32
+static bool
 aclitemeq(AclItem *a1, AclItem *a2)
 {
-	if (!a1 && !a2)
-		return 1;
-	if (!a1 || !a2)
-		return 0;
 	return a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id;
 }
 
-static int32
+static bool
 aclitemgt(AclItem *a1, AclItem *a2)
 {
-	if (a1 && !a2)
-		return 1;
-	if (!a1 || !a2)
-		return 0;
 	return ((a1->ai_idtype > a2->ai_idtype) ||
 			(a1->ai_idtype == a2->ai_idtype && a1->ai_id > a2->ai_id));
 }
@@ -384,25 +365,28 @@ acldefault(char *relname)
 	return acl;
 }
 
+/*
+ * Add or replace an item in an ACL array.
+ *
+ * NB: caller is responsible for having detoasted the input ACL, if needed.
+ */
 Acl *
 aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
 {
 	Acl		   *new_acl;
 	AclItem    *old_aip,
 			   *new_aip;
-	unsigned	src,
+	int			src,
 				dst,
 				num;
 
+	/* These checks for null input are probably dead code, but... */
 	if (!old_acl || ACL_NUM(old_acl) < 1)
-	{
-		new_acl = makeacl(0);
-		return new_acl;
-	}
+		old_acl = makeacl(0);
 	if (!mod_aip)
 	{
 		new_acl = makeacl(ACL_NUM(old_acl));
-		memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
+		memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
 		return new_acl;
 	}
 
@@ -422,7 +406,7 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
 	{
 		/* modify in-place */
 		new_acl = makeacl(ACL_NUM(old_acl));
-		memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
+		memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
 		new_aip = ACL_DAT(new_acl);
 		src = dst;
 	}
@@ -470,60 +454,58 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
 	/*
 	 * if the newly added entry has no permissions, delete it from the
 	 * list.  For example, this helps in removing entries for users who no
-	 * longer exists...
+	 * longer exist...
 	 */
-	for (dst = 1; dst < num; dst++)
+	if (new_aip[dst].ai_mode == 0)
 	{
-		if (new_aip[dst].ai_mode == 0)
-		{
-			int			i;
+		int			i;
 
-			for (i = dst + 1; i < num; i++)
-			{
-				new_aip[i - 1].ai_id = new_aip[i].ai_id;
-				new_aip[i - 1].ai_idtype = new_aip[i].ai_idtype;
-				new_aip[i - 1].ai_mode = new_aip[i].ai_mode;
-			}
-			ARR_DIMS(new_acl)[0] = num - 1;
-			/* Adjust also the array size because it is used for memmove */
-			ARR_SIZE(new_acl) -= sizeof(AclItem);
-			break;
+		for (i = dst + 1; i < num; i++)
+		{
+			new_aip[i - 1].ai_id = new_aip[i].ai_id;
+			new_aip[i - 1].ai_idtype = new_aip[i].ai_idtype;
+			new_aip[i - 1].ai_mode = new_aip[i].ai_mode;
 		}
+		ARR_DIMS(new_acl)[0] = num - 1;
+		/* Adjust also the array size because it is used for memmove */
+		ARR_SIZE(new_acl) -= sizeof(AclItem);
 	}
 
 	return new_acl;
 }
 
 /*
- * aclinsert
- *
+ * aclinsert (exported function)
  */
-Acl *
-aclinsert(Acl *old_acl, AclItem *mod_aip)
+Datum
+aclinsert(PG_FUNCTION_ARGS)
 {
-	return aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL);
+	Acl		   *old_acl = PG_GETARG_ACL_P(0);
+	AclItem	   *mod_aip = PG_GETARG_ACLITEM_P(1);
+
+	PG_RETURN_ACL_P(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL));
 }
 
-Acl *
-aclremove(Acl *old_acl, AclItem *mod_aip)
+Datum
+aclremove(PG_FUNCTION_ARGS)
 {
+	Acl		   *old_acl = PG_GETARG_ACL_P(0);
+	AclItem	   *mod_aip = PG_GETARG_ACLITEM_P(1);
 	Acl		   *new_acl;
 	AclItem    *old_aip,
 			   *new_aip;
-	unsigned	dst,
+	int			dst,
 				old_num,
 				new_num;
 
+	/* These checks for null input should be dead code, but... */
 	if (!old_acl || ACL_NUM(old_acl) < 1)
-	{
-		new_acl = makeacl(0);
-		return new_acl;
-	}
+		old_acl = makeacl(0);
 	if (!mod_aip)
 	{
 		new_acl = makeacl(ACL_NUM(old_acl));
-		memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
-		return new_acl;
+		memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
+		PG_RETURN_ACL_P(new_acl);
 	}
 
 	old_num = ACL_NUM(old_acl);
@@ -534,12 +516,12 @@ aclremove(Acl *old_acl, AclItem *mod_aip)
 	if (dst >= old_num)
 	{							/* not found or empty */
 		new_acl = makeacl(ACL_NUM(old_acl));
-		memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
+		memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
 	}
 	else
 	{
 		new_num = old_num - 1;
-		new_acl = makeacl(ACL_NUM(old_acl) - 1);
+		new_acl = makeacl(new_num);
 		new_aip = ACL_DAT(new_acl);
 		if (dst == 0)
 		{						/* start */
@@ -561,23 +543,24 @@ aclremove(Acl *old_acl, AclItem *mod_aip)
 					(new_num - dst) * sizeof(AclItem));
 		}
 	}
-	return new_acl;
+	PG_RETURN_ACL_P(new_acl);
 }
 
-int32
-aclcontains(Acl *acl, AclItem *aip)
+Datum
+aclcontains(PG_FUNCTION_ARGS)
 {
-	unsigned	i,
-				num;
+	Acl		   *acl = PG_GETARG_ACL_P(0);
+	AclItem	   *aip = PG_GETARG_ACLITEM_P(1);
 	AclItem    *aidat;
+	int			i,
+				num;
 
-	if (!acl || !aip || ((num = ACL_NUM(acl)) < 1))
-		return 0;
+	num = ACL_NUM(acl);
 	aidat = ACL_DAT(acl);
 	for (i = 0; i < num; ++i)
 		if (aclitemeq(aip, aidat + i))
-			return 1;
-	return 0;
+			PG_RETURN_BOOL(true);
+	PG_RETURN_BOOL(false);
 }
 
 /* parser support routines */
@@ -638,7 +621,7 @@ aclmakepriv(char *old_privlist, char new_priv)
  *						"G"  - group
  *						"U"  - user
  *
- * concatentates the two strings together with a space in between
+ * concatenates the two strings together with a space in between
  *
  * this routine is used in the parser
  *
@@ -649,7 +632,7 @@ aclmakeuser(char *user_type, char *user)
 {
 	char	   *user_list;
 
-	user_list = palloc(strlen(user) + 3);
+	user_list = palloc(strlen(user_type) + strlen(user) + 2);
 	sprintf(user_list, "%s %s", user_type, user);
 	return user_list;
 }
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index 925328e2bd9b564d11c626dd633759fd8d83597c..0ced47b064a6911cc59e5e840748efc7eb7ccf7c 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_attribute.h,v 1.61 2000/07/03 23:10:05 wieck Exp $
+ * $Id: pg_attribute.h,v 1.62 2000/07/31 22:39:06 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -124,15 +124,16 @@ CATALOG(pg_attribute) BOOTSTRAP
 
 	char		attstorage;
 
-	/*
+	/*----------
 	 * attstorage tells for VARLENA attributes, what the heap access
 	 * methods can do to it if a given tuple doesn't fit into a page.
-	 * Possible values are 'p': Value must be stored plain allways 'e':
-	 * Value can be stored in "secondary" relation (if relation has
-	 * rellongrelid attached) 'c': Value can be stored compressed inline
-	 * 'x': Value can be stored compressed inline or in "secondary".
-	 *
-	 * Note: compressed storage
+	 * Possible values are
+	 *		'p': Value must be stored plain always
+	 *		'e': Value can be stored in "secondary" relation (if relation
+	 *			 has rellongrelid attached)
+	 *		'm': Value can be stored compressed inline
+	 *		'x': Value can be stored compressed inline or in "secondary"
+	 *----------
 	 */
 
 	bool		attisset;
@@ -439,7 +440,7 @@ DATA(insert OID = 0 ( 1249 tableoid			26 0  4  -7 0 -1 -1 t p f i f f));
 { 1259, {"relhaspkey"},    16, 0,	1, 18, 0, -1, -1, '\001', 'p', '\0', 'c', '\0', '\0' }, \
 { 1259, {"relhasrules"},   16, 0,	1, 19, 0, -1, -1, '\001', 'p', '\0', 'c', '\0', '\0' }, \
 { 1259, {"relhassubclass"},16, 0,	1, 20, 0, -1, -1, '\001', 'p', '\0', 'c', '\0', '\0' }, \
-{ 1259, {"relacl"},		 1034, 0,  -1, 21, 0, -1, -1,	'\0', 'p', '\0', 'i', '\0', '\0' }
+{ 1259, {"relacl"},		 1034, 0,  -1, 21, 0, -1, -1,	'\0', 'm', '\0', 'i', '\0', '\0' }
 
 DATA(insert OID = 0 ( 1259 relname			19 0 NAMEDATALEN   1 0 -1 -1 f p f i f f));
 DATA(insert OID = 0 ( 1259 reltype			26 0  4   2 0 -1 -1 t p f i f f));
@@ -461,7 +462,7 @@ DATA(insert OID = 0 ( 1259 relrefs			21 0  2  17 0 -1 -1 t p f s f f));
 DATA(insert OID = 0 ( 1259 relhaspkey		16 0  1  18 0 -1 -1 t p f c f f));
 DATA(insert OID = 0 ( 1259 relhasrules		16 0  1  19 0 -1 -1 t p f c f f));
 DATA(insert OID = 0 ( 1259 relhassubclass	16 0  1  20 0 -1 -1 t p f c f f));
-DATA(insert OID = 0 ( 1259 relacl		  1034 0 -1  21 0 -1 -1 f p f i f f));
+DATA(insert OID = 0 ( 1259 relacl		  1034 0 -1  21 0 -1 -1 f m f i f f));
 DATA(insert OID = 0 ( 1259 ctid				27 0  6  -1 0 -1 -1 f p f i f f));
 DATA(insert OID = 0 ( 1259 oid				26 0  4  -2 0 -1 -1 t p f i f f));
 DATA(insert OID = 0 ( 1259 xmin				28 0  4  -3 0 -1 -1 t p f i f f));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 6b833400c08dd60b8416ce709409084c1d3eb422..7d06975b70286987360a81629a2dc058fc8689e0 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.153 2000/07/30 22:14:01 tgl Exp $
+ * $Id: pg_proc.h,v 1.154 2000/07/31 22:39:05 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -1256,16 +1256,16 @@ DATA(insert OID = 1029 (  nullvalue		   PGUID 12 f t t f 1 f 16 "0" 100 0 0 100
 DESCR("(internal)");
 DATA(insert OID = 1030 (  nonnullvalue	   PGUID 12 f t t f 1 f 16 "0" 100 0 0 100  nonnullvalue - ));
 DESCR("(internal)");
-DATA(insert OID = 1031 (  aclitemin		   PGUID 11 f t f t 1 f 1033 "0" 100 0 0 100	aclitemin - ));
+DATA(insert OID = 1031 (  aclitemin		   PGUID 12 f t f t 1 f 1033 "0" 100 0 0 100	aclitemin - ));
 DESCR("(internal)");
-DATA(insert OID = 1032 (  aclitemout	   PGUID 11 f t f t 1 f 23 "0" 100 0 0 100  aclitemout - ));
+DATA(insert OID = 1032 (  aclitemout	   PGUID 12 f t f t 1 f 23 "1033" 100 0 0 100  aclitemout - ));
 DESCR("(internal)");
-DATA(insert OID = 1035 (  aclinsert		   PGUID 11 f t f t 2 f 1034 "1034 1033" 100 0 0 100	aclinsert - ));
-DESCR("addition");
-DATA(insert OID = 1036 (  aclremove		   PGUID 11 f t f t 2 f 1034 "1034 1033" 100 0 0 100	aclremove - ));
-DESCR("subtract");
-DATA(insert OID = 1037 (  aclcontains	   PGUID 11 f t f t 2 f 16 "1034 1033" 100 0 0 100  aclcontains - ));
-DESCR("matches regex., case-sensitive");
+DATA(insert OID = 1035 (  aclinsert		   PGUID 12 f t f t 2 f 1034 "1034 1033" 100 0 0 100	aclinsert - ));
+DESCR("add/update ACL item");
+DATA(insert OID = 1036 (  aclremove		   PGUID 12 f t f t 2 f 1034 "1034 1033" 100 0 0 100	aclremove - ));
+DESCR("remove ACL item");
+DATA(insert OID = 1037 (  aclcontains	   PGUID 12 f t f t 2 f 16 "1034 1033" 100 0 0 100  aclcontains - ));
+DESCR("does ACL contain item?");
 DATA(insert OID = 1038 (  seteval		   PGUID 12 f t f t 1 f 23 "26" 100 0 0 100  seteval - ));
 DESCR("");
 DATA(insert OID = 1044 (  bpcharin		   PGUID 12 f t t t 3 f 1042 "0 26 23" 100 0 0 100 bpcharin - ));
diff --git a/src/include/postgres.h b/src/include/postgres.h
index f11e28ed9f927f1a5a46d6541ad5a7ab19bb5027..1011d04cbbdd37d3406398276a922426e96cba37 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1995, Regents of the University of California
  *
- * $Id: postgres.h,v 1.43 2000/07/03 23:09:56 wieck Exp $
+ * $Id: postgres.h,v 1.44 2000/07/31 22:39:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,8 +46,6 @@
  * ----------------------------------------------------------------
  */
 
-typedef int4 aclitem;
-
 #define InvalidOid		((Oid) 0)
 #define OidIsValid(objectId)  ((bool) ((objectId) != InvalidOid))
 
@@ -57,6 +55,8 @@ typedef Oid RegProcedure;
 
 #define RegProcedureIsValid(p)	OidIsValid(p)
 
+typedef int4 aclitem;			/* PHONY definition for catalog use only */
+
 /* ----------------------------------------------------------------
  *				Section 2:	variable length and array types
  * ----------------------------------------------------------------
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index f1f60fca4cd154add5e6f899a0a4e5206e9a5a5d..e8a8f3a111b4549b7d1037c1ea09490351371516 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,17 +7,16 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: acl.h,v 1.25 2000/04/12 17:16:54 momjian Exp $
+ * $Id: acl.h,v 1.26 2000/07/31 22:39:02 tgl Exp $
  *
  * NOTES
- *	  For backward-compatability purposes we have to allow there
+ *	  For backward-compatibility purposes we have to allow there
  *	  to be a null ACL in a pg_class tuple.  This will be defined as
  *	  meaning "no protection" (i.e., old catalogs get old semantics).
  *
  *	  The AclItems in an ACL array are currently kept in sorted order.
  *	  Things will break hard if you change that without changing the
  *	  code wherever this is included.
- *
  *-------------------------------------------------------------------------
  */
 #ifndef ACL_H
@@ -78,7 +77,7 @@ typedef struct AclItem
 	AclMode		ai_mode;
 
 	/*
-	 * This is actually type 'aclitem', and we want a fixed size for for
+	 * This is actually type 'aclitem', and we want a fixed size for
 	 * all platforms, so we pad this with dummies.
 	 */
 	char		dummy1,
@@ -88,22 +87,30 @@ typedef struct AclItem
 /* Note: if the size of AclItem changes,
    change the aclitem typlen in pg_type.h */
 
+
 /*
- * The value of the first dimension-array element.	Since these arrays
- * always have a lower-bound of 0, this is the same as the number of
- * elements in the array.
+ * Definitions for convenient access to Acl (array of AclItem) and IdList
+ * (array of AclId).  These are standard Postgres arrays, but are restricted
+ * to have one dimension.  We also ignore the lower bound when reading,
+ * and set it to zero when writing.
+ *
+ * CAUTION: as of Postgres 7.1, these arrays are toastable (just like all
+ * other array types).  Therefore, be careful to detoast them with the
+ * macros provided, unless you know for certain that a particular array
+ * can't have been toasted.  Presently, we do not provide toast tables for
+ * pg_class or pg_group, so the entries in those tables won't have been
+ * stored externally --- but they could have been compressed!
  */
-#define ARR_DIM0(a) (((unsigned *) (((char *) a) + sizeof(ArrayType)))[0])
+
 
 /*
  * Acl			a one-dimensional POSTGRES array of AclItem
  */
 typedef ArrayType Acl;
 
-#define ACL_NUM(ACL)			ARR_DIM0(ACL)
+#define ACL_NUM(ACL)			(ARR_DIMS(ACL)[0])
 #define ACL_DAT(ACL)			((AclItem *) ARR_DATA_PTR(ACL))
-#define ACL_N_SIZE(N) \
-		((unsigned) (ARR_OVERHEAD(1) + ((N) * sizeof(AclItem))))
+#define ACL_N_SIZE(N)			(ARR_OVERHEAD(1) + ((N) * sizeof(AclItem)))
 #define ACL_SIZE(ACL)			ARR_SIZE(ACL)
 
 /*
@@ -111,12 +118,32 @@ typedef ArrayType Acl;
  */
 typedef ArrayType IdList;
 
-#define IDLIST_NUM(IDL)			ARR_DIM0(IDL)
+#define IDLIST_NUM(IDL)			(ARR_DIMS(IDL)[0])
 #define IDLIST_DAT(IDL)			((AclId *) ARR_DATA_PTR(IDL))
-#define IDLIST_N_SIZE(N) \
-		((unsigned) (ARR_OVERHEAD(1) + ((N) * sizeof(AclId))))
+#define IDLIST_N_SIZE(N)		(ARR_OVERHEAD(1) + ((N) * sizeof(AclId)))
 #define IDLIST_SIZE(IDL)		ARR_SIZE(IDL)
 
+/*
+ * fmgr macros for these types
+ */
+#define DatumGetAclItemP(X)        ((AclItem *) DatumGetPointer(X))
+#define PG_GETARG_ACLITEM_P(n)     DatumGetAclItemP(PG_GETARG_DATUM(n))
+#define PG_RETURN_ACLITEM_P(x)     PG_RETURN_POINTER(x)
+
+#define DatumGetAclP(X)            ((Acl *) PG_DETOAST_DATUM(X))
+#define DatumGetAclPCopy(X)        ((Acl *) PG_DETOAST_DATUM_COPY(X))
+#define PG_GETARG_ACL_P(n)         DatumGetAclP(PG_GETARG_DATUM(n))
+#define PG_GETARG_ACL_P_COPY(n)    DatumGetAclPCopy(PG_GETARG_DATUM(n))
+#define PG_RETURN_ACL_P(x)         PG_RETURN_POINTER(x)
+
+#define DatumGetIdListP(X)         ((IdList *) PG_DETOAST_DATUM(X))
+#define DatumGetIdListPCopy(X)     ((IdList *) PG_DETOAST_DATUM_COPY(X))
+#define PG_GETARG_IDLIST_P(n)      DatumGetIdListP(PG_GETARG_DATUM(n))
+#define PG_GETARG_IDLIST_P_COPY(n) DatumGetIdListPCopy(PG_GETARG_DATUM(n))
+#define PG_RETURN_IDLIST_P(x)      PG_RETURN_POINTER(x)
+
+
+/* mode indicators for I/O */
 #define ACL_MODECHG_STR			"+-="	/* list of valid characters */
 #define ACL_MODECHG_ADD_CHR		'+'
 #define ACL_MODECHG_DEL_CHR		'-'
@@ -157,11 +184,11 @@ extern ChangeACLStmt *makeAclStmt(char *privs, List *rel_list, char *grantee,
  * exported routines (from acl.c)
  */
 extern Acl *makeacl(int n);
-extern AclItem *aclitemin(char *s);
-extern char *aclitemout(AclItem *aip);
-extern Acl *aclinsert(Acl *old_acl, AclItem *mod_aip);
-extern Acl *aclremove(Acl *old_acl, AclItem *mod_aip);
-extern int32 aclcontains(Acl *acl, AclItem *aip);
+extern Datum aclitemin(PG_FUNCTION_ARGS);
+extern Datum aclitemout(PG_FUNCTION_ARGS);
+extern Datum aclinsert(PG_FUNCTION_ARGS);
+extern Datum aclremove(PG_FUNCTION_ARGS);
+extern Datum aclcontains(PG_FUNCTION_ARGS);
 
 /*
  * prototypes for functions in aclchk.c