diff -Naur pgsql.virg/src/backend/utils/adt/acl.c pgsql.dev/src/backend/utils/adt/acl.c
--- pgsql.virg/src/backend/utils/adt/acl.c	Sun May 27 09:59:30 2001
+++ pgsql.dev/src/backend/utils/adt/acl.c	Sat Jun  2 17:29:41 2001
@@ -756,3 +756,343 @@
 	pfree(str.data);
 	return n;
 }
+
+
+/*
+ * text_text_has_table_privilege
+ *		Check user privileges on a relation given
+ *		usename, relname, and priv name.
+ *		If usename is omitted, current_user is assumed
+ *
+ * RETURNS
+ *		a boolean value
+ *		't' indicating user has the privilege
+ *		'f' indicating user does not have the privilege
+ */
+Datum
+text_text_has_table_privilege(PG_FUNCTION_ARGS)
+{
+	text		*username_text = NULL;
+	char		*username = NULL;
+	int			usesysid = -1;
+	text		*relname_text = NULL;
+	char		*relname = NULL;
+	text		*priv_type_text = NULL;
+	char		*priv_type = NULL;
+	HeapTuple	tuple;
+	bool		result;
+
+	if (PG_NARGS == 2) {
+
+		relname_text = PG_GETARG_TEXT_P(0);
+		priv_type_text = PG_GETARG_TEXT_P(1);
+
+		usesysid = GetUserId();
+
+	} else if (PG_NARGS == 3) {
+
+		username_text = PG_GETARG_TEXT_P(0);
+		relname_text = PG_GETARG_TEXT_P(1);
+		priv_type_text = PG_GETARG_TEXT_P(2);
+
+		/* 
+		 * Convert username 'text' pattern to null-terminated string
+		 */
+		username = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(username_text)));
+
+		/*
+		 * Lookup userid based on username
+		 */
+
+		tuple = SearchSysCache(SHADOWNAME, NameGetDatum(username), 0, 0, 0);
+		if (!HeapTupleIsValid(tuple)) {
+			elog(ERROR, "has_table_privilege: invalid user name %s", (char *) username);
+		}
+
+		usesysid = ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid;
+
+		ReleaseSysCache(tuple);
+
+	} else {
+		/* 
+		 * should never get here!
+		 */
+
+		elog(ERROR, "has_table_privilege: wrong number of arguments %d", PG_NARGS);
+
+	}
+
+	/* 
+	 * Convert relname and priv_type 'text' pattern to null-terminated string
+	 */
+	relname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(relname_text)));
+	priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text)));
+
+	result = has_table_privilege(usesysid, relname, priv_type);
+
+	PG_RETURN_BOOL(result);
+}
+
+
+/*
+ * text_oid_has_table_privilege
+ *		Check user privileges on a relation given
+ *		usename, rel oid, and priv name.
+ *		If usename is omitted, current_user is assumed
+ *
+ * RETURNS
+ *		a boolean value
+ *		't' indicating user has the privilege
+ *		'f' indicating user does not have the privilege
+ */
+Datum
+text_oid_has_table_privilege(PG_FUNCTION_ARGS)
+{
+	text		*username_text = NULL;
+	char		*username = NULL;
+	int			usesysid = -1;
+	Oid			reloid = 0;
+	char		*relname = NULL;
+	text		*priv_type_text = NULL;
+	char		*priv_type = NULL;
+	HeapTuple	tuple;
+	bool		result;
+
+	if (PG_NARGS == 2) {
+
+		reloid = PG_GETARG_OID(0);
+		priv_type_text = PG_GETARG_TEXT_P(1);
+
+		usesysid = GetUserId();
+
+	} else if (PG_NARGS == 3) {
+
+		username_text = PG_GETARG_TEXT_P(0);
+		reloid = PG_GETARG_OID(1);
+		priv_type_text = PG_GETARG_TEXT_P(2);
+
+		/* 
+		 * Convert username 'text' pattern to null-terminated string
+		 */
+		username = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(username_text)));
+
+		/*
+		 * Lookup userid based on username
+		 */
+
+		tuple = SearchSysCache(SHADOWNAME, NameGetDatum(username), 0, 0, 0);
+		if (!HeapTupleIsValid(tuple)) {
+			elog(ERROR, "has_table_privilege: invalid user name %s", (char *) username);
+		}
+
+		usesysid = ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid;
+
+		ReleaseSysCache(tuple);
+
+	} else {
+		/* 
+		 * should never get here!
+		 */
+
+		elog(ERROR, "has_table_privilege: wrong number of arguments %d", PG_NARGS);
+
+	}
+
+	/* 
+	 * Convert priv_type 'text' pattern to null-terminated string
+	 */
+	priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text)));
+
+
+	/*
+	 * Lookup relname based on rel oid
+	 */
+	tuple = SearchSysCache(RELOID, ObjectIdGetDatum(reloid), 0, 0, 0);
+	if (!HeapTupleIsValid(tuple)) {
+		elog(ERROR, "has_table_privilege: invalid relation oid %d", (int) reloid);
+	}
+
+	relname = NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname);
+
+	ReleaseSysCache(tuple);
+
+	result = has_table_privilege(usesysid, relname, priv_type);
+
+	PG_RETURN_BOOL(result);
+}
+
+
+/*
+ * int_text_has_table_privilege
+ *		Check user privileges on a relation given
+ *		usesysid, relname, and priv name.
+ *
+ * RETURNS
+ *		a boolean value
+ *		't' indicating user has the privilege
+ *		'f' indicating user does not have the privilege
+ */
+Datum
+int_text_has_table_privilege(PG_FUNCTION_ARGS)
+{
+	int			usesysid;
+	text		*relname_text;
+	char		*relname;
+	text		*priv_type_text;
+	char		*priv_type;
+	bool		result;
+
+
+	usesysid = PG_GETARG_INT32(0);
+	relname_text = PG_GETARG_TEXT_P(1);
+	priv_type_text = PG_GETARG_TEXT_P(2);
+
+	/* 
+	 * Convert relname and priv_type 'text' pattern to null-terminated string
+	 */
+	relname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(relname_text)));
+	priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text)));
+
+	result = has_table_privilege(usesysid, relname, priv_type);
+
+	PG_RETURN_BOOL(result);
+}
+
+
+/*
+ * int_oid_has_table_privilege
+ *		Check user privileges on a relation given
+ *		usesysid, rel oid, and priv name.
+ *
+ * RETURNS
+ *		a boolean value
+ *		't' indicating user has the privilege
+ *		'f' indicating user does not have the privilege
+ */
+Datum
+int_oid_has_table_privilege(PG_FUNCTION_ARGS)
+{
+	int			usesysid;
+	Oid			reloid;
+	char		*relname;
+	text		*priv_type_text;
+	char		*priv_type;
+	HeapTuple	tuple;
+	bool		result;
+
+
+	usesysid = PG_GETARG_INT32(0);
+	reloid = PG_GETARG_OID(1);
+	priv_type_text = PG_GETARG_TEXT_P(2);
+
+	/* 
+	 * Convert priv_type 'text' pattern to null-terminated string
+	 */
+	priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text)));
+
+	/*
+	 * Lookup relname based on rel oid
+	 */
+	tuple = SearchSysCache(RELOID, ObjectIdGetDatum(reloid), 0, 0, 0);
+	if (!HeapTupleIsValid(tuple)) {
+		elog(ERROR, "has_table_privilege: invalid relation oid %d", (int) reloid);
+	}
+
+	relname = NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname);
+
+	ReleaseSysCache(tuple);
+
+	result = has_table_privilege(usesysid, relname, priv_type);
+
+	PG_RETURN_BOOL(result);
+}
+
+
+/*
+ * has_table_privilege
+ *		Internal function.
+ *		Check user privileges on a relation given
+ *		usesysid, relname, and priv name
+ *
+ * RETURNS
+ *		a boolean value
+ *		't' indicating user has the privilege
+ *		'f' indicating user does not have the privilege
+ */
+
+Datum
+has_table_privilege(int usesysid, char *relname, char *priv_type)
+{
+	HeapTuple	tuple;
+	AclMode		mode;
+	int32		result;
+
+	/*
+	 * Verify usesysid is valid
+	 */
+	tuple = SearchSysCache(SHADOWSYSID, Int32GetDatum(usesysid), 0, 0, 0);
+	if (!HeapTupleIsValid(tuple)) {
+		elog(ERROR, "has_table_privilege: invalid usesysid %d", usesysid);
+	}
+
+	ReleaseSysCache(tuple);
+
+	/*
+	 * Verify relname is valid
+	 */
+	tuple = SearchSysCache(RELNAME, NameGetDatum(relname), 0, 0, 0);
+	if (!HeapTupleIsValid(tuple)) {
+		elog(ERROR, "has_table_privilege: invalid relation name %s", (char *) relname);
+	}
+
+	ReleaseSysCache(tuple);
+
+
+	/*
+	 * Determine mode from priv_type string
+	 */
+	if (strcasecmp(priv_type, PRIV_SELECT) == 0) {
+
+		mode = (AclMode) ACL_SELECT;
+
+	} else if (strcasecmp(priv_type, PRIV_INSERT) == 0) {
+
+		mode = (AclMode) ACL_INSERT;
+
+	} else if (strcasecmp(priv_type, PRIV_UPDATE) == 0) {
+
+		mode = (AclMode) ACL_UPDATE;
+
+	} else if (strcasecmp(priv_type, PRIV_DELETE) == 0) {
+
+		mode = (AclMode) ACL_DELETE;
+
+	} else if (strcasecmp(priv_type, PRIV_RULE) == 0) {
+
+		mode = (AclMode) ACL_RULE;
+
+	} else if (strcasecmp(priv_type, PRIV_REFERENCES) == 0) {
+
+		mode = (AclMode) ACL_REFERENCES;
+
+	} else if (strcasecmp(priv_type, PRIV_TRIGGER) == 0) {
+
+		mode = (AclMode) ACL_TRIGGER;
+
+	} else {
+
+		mode = (AclMode) ACL_NO;
+		elog(ERROR, "has_table_privilege: invalid privilege type %s", (char *) priv_type);
+
+	}
+
+	result = pg_aclcheck(relname, usesysid, mode);
+
+	if (result == 1) {
+		PG_RETURN_BOOL(FALSE);
+	} else {
+		PG_RETURN_BOOL(TRUE);
+	}
+}
+
+
diff -Naur pgsql.virg/src/include/fmgr.h pgsql.dev/src/include/fmgr.h
--- pgsql.virg/src/include/fmgr.h	Thu May 17 17:44:18 2001
+++ pgsql.dev/src/include/fmgr.h	Sat Jun  2 14:28:57 2001
@@ -144,6 +144,7 @@
 
 /* Macros for fetching arguments of standard types */
 
+#define PG_NARGS             (fcinfo->nargs)
 #define PG_GETARG_DATUM(n)	 (fcinfo->arg[n])
 #define PG_GETARG_INT32(n)	 DatumGetInt32(PG_GETARG_DATUM(n))
 #define PG_GETARG_UINT32(n)  DatumGetUInt32(PG_GETARG_DATUM(n))
diff -Naur pgsql.virg/src/include/utils/acl.h pgsql.dev/src/include/utils/acl.h
--- pgsql.virg/src/include/utils/acl.h	Sun May 27 09:59:30 2001
+++ pgsql.dev/src/include/utils/acl.h	Sat Jun  2 16:16:07 2001
@@ -164,6 +164,16 @@
 #define ACLCHECK_NO_CLASS		  2
 #define ACLCHECK_NOT_OWNER		  3
 
+
+/* Privilege names for oid_oid_has_table_privilege */
+#define PRIV_INSERT			"INSERT\0"
+#define PRIV_SELECT			"SELECT\0"
+#define PRIV_UPDATE			"UPDATE\0"
+#define PRIV_DELETE			"DELETE\0"
+#define PRIV_RULE			"RULE\0"
+#define PRIV_REFERENCES		"REFERENCES\0"
+#define PRIV_TRIGGER		"TRIGGER\0"
+
 /* warning messages.  set these in aclchk.c. */
 extern char *aclcheck_error_strings[];
 
@@ -174,6 +184,8 @@
 
 extern Acl *aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg);
 
+extern Datum has_table_privilege(int usesysid, char *relname, char *priv_type);
+
 /*
  * routines used by the parser
  */
@@ -192,6 +204,11 @@
 extern Datum aclremove(PG_FUNCTION_ARGS);
 extern Datum aclcontains(PG_FUNCTION_ARGS);
 extern void ExecuteChangeACLStmt(ChangeACLStmt *stmt);
+
+extern Datum int_text_has_table_privilege(PG_FUNCTION_ARGS);
+extern Datum text_text_has_table_privilege(PG_FUNCTION_ARGS);
+extern Datum text_oid_has_table_privilege(PG_FUNCTION_ARGS);
+extern Datum int_oid_has_table_privilege(PG_FUNCTION_ARGS);
 
 /*
  * prototypes for functions in aclchk.c
diff -Naur pgsql.virg/src/include/utils/builtins.h pgsql.dev/src/include/utils/builtins.h
--- pgsql.virg/src/include/utils/builtins.h	Thu Mar 22 04:01:11 2001
+++ pgsql.dev/src/include/utils/builtins.h	Sat Jun  2 16:42:29 2001
@@ -22,6 +22,13 @@
 /*
  *		Defined in adt/
  */
+
+/* acl.c */
+extern Datum text_text_has_table_privilege(PG_FUNCTION_ARGS);
+extern Datum text_oid_has_table_privilege(PG_FUNCTION_ARGS);
+extern Datum int_text_has_table_privilege(PG_FUNCTION_ARGS);
+extern Datum int_oid_has_table_privilege(PG_FUNCTION_ARGS);
+
 /* bool.c */
 extern Datum boolin(PG_FUNCTION_ARGS);
 extern Datum boolout(PG_FUNCTION_ARGS);
diff -Naur pgsql.virg/src/include/catalog/pg_proc.h pgsql.dev/src/include/catalog/pg_proc.h
--- pgsql.virg/src/include/catalog/pg_proc.h	Thu May 24 09:29:29 2001
+++ pgsql.dev/src/include/catalog/pg_proc.h	Sat Jun  2 17:06:33 2001
@@ -2614,6 +2614,20 @@
 DATA(insert OID = 1909 (  int8shr		   PGUID 12 f t t t 2 f 20 "20 23" 100 0 0 100	int8shr - ));
 DESCR("binary shift right");
 
+DATA(insert OID = 1920 (  has_table_privilege		   PGUID 12 f t f t 3 f 16 "25 25 25" 100 0 0 100	text_text_has_table_privilege - ));
+DESCR("user privilege on relation by username, relname");
+DATA(insert OID = 1921 (  has_table_privilege		   PGUID 12 f t f t 3 f 16 "25 26 25" 100 0 0 100	text_oid_has_table_privilege - ));
+DESCR("user privilege on relation by username, rel oid");
+DATA(insert OID = 1922 (  has_table_privilege		   PGUID 12 f t f t 3 f 16 "23 25 25" 100 0 0 100	int_text_has_table_privilege - ));
+DESCR("user privilege on relation by usesysid, relname");
+DATA(insert OID = 1923 (  has_table_privilege		   PGUID 12 f t f t 3 f 16 "23 26 25" 100 0 0 100	int_oid_has_table_privilege - ));
+DESCR("user privilege on relation by usesysid, rel oid");
+DATA(insert OID = 1924 (  has_table_privilege		   PGUID 12 f t f t 2 f 16 "25 25" 100 0 0 100	text_text_has_table_privilege - ));
+DESCR("current user privilege on relation by relname");
+DATA(insert OID = 1925 (  has_table_privilege		   PGUID 12 f t f t 2 f 16 "26 25" 100 0 0 100	text_oid_has_table_privilege - ));
+DESCR("current user privilege on relation by rel oid");
+
+
 /*
  * prototypes for functions pg_proc.c
  */
