From 4ab8e69094452286a5894f1b2b237304808f4391 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 9 Aug 2002 16:45:16 +0000
Subject: [PATCH] has_table_privilege spawns scions has_database_privilege,
 has_function_privilege, has_language_privilege, has_schema_privilege to let
 SQL queries test all the new privilege types in 7.3.  Also, add functions
 pg_table_is_visible, pg_type_is_visible, pg_function_is_visible,
 pg_operator_is_visible, pg_opclass_is_visible to test whether objects
 contained in schemas are visible in the current search path.  Do some minor
 cleanup to centralize accesses to pg_database, as well.

---
 contrib/dbsize/dbsize.c            |   24 +-
 doc/src/sgml/func.sgml             |  256 +++++--
 src/backend/catalog/namespace.c    |   53 +-
 src/backend/commands/comment.c     |   38 +-
 src/backend/commands/dbcommands.c  |   77 ++-
 src/backend/utils/adt/acl.c        | 1014 ++++++++++++++++++++++++----
 src/backend/utils/adt/sets.c       |    5 +-
 src/backend/utils/misc/superuser.c |   28 +-
 src/include/catalog/catversion.h   |    4 +-
 src/include/catalog/pg_proc.h      |   77 ++-
 src/include/commands/dbcommands.h  |    5 +-
 src/include/utils/builtins.h       |   26 +-
 12 files changed, 1325 insertions(+), 282 deletions(-)

diff --git a/contrib/dbsize/dbsize.c b/contrib/dbsize/dbsize.c
index 44699aa6936..0e5e63d1eee 100644
--- a/contrib/dbsize/dbsize.c
+++ b/contrib/dbsize/dbsize.c
@@ -8,12 +8,10 @@
 
 #include "access/heapam.h"
 #include "catalog/catalog.h"
-#include "catalog/catname.h"
 #include "catalog/namespace.h"
-#include "catalog/pg_database.h"
+#include "commands/dbcommands.h"
 #include "fmgr.h"
 #include "utils/builtins.h"
-#include "utils/fmgroids.h"
 
 
 static char *
@@ -46,32 +44,16 @@ database_size(PG_FUNCTION_ARGS)
 {
 	Name		dbname = PG_GETARG_NAME(0);
 
-	HeapTuple	tuple;
-	Relation	relation;
-	ScanKeyData	scanKey;
-	HeapScanDesc scan;
 	Oid			dbid;
 	char	   *dbpath;
 	DIR		   *dirdesc;
 	struct dirent *direntry;
 	int64		totalsize;
 
-	relation = heap_openr(DatabaseRelationName, AccessShareLock);
-	ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
-						   F_NAMEEQ, NameGetDatum(dbname));
-	scan = heap_beginscan(relation, SnapshotNow, 1, &scanKey);
-	tuple = heap_getnext(scan, ForwardScanDirection);
-
-	if (!HeapTupleIsValid(tuple))
+	dbid = get_database_oid(NameStr(*dbname));
+	if (!OidIsValid(dbid))
 		elog(ERROR, "database %s does not exist", NameStr(*dbname));
 
-	dbid = HeapTupleGetOid(tuple);
-	if (dbid == InvalidOid)
-		elog(ERROR, "invalid database id");
-
-	heap_endscan(scan);
-	heap_close(relation, NoLock);
-
 	dbpath = GetDatabasePath(dbid);
 
 	dirdesc = opendir(dbpath);
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 8d722a91853..475af474649 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.109 2002/08/08 14:29:07 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.110 2002/08/09 16:45:13 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -4925,57 +4925,11 @@ select current_setting('DateStyle');
     <literal>false</literal> instead. It is the equivalent to the SQL
     <command>SET</command> command. For example:
 <programlisting>
-SHOW show_query_stats;
- show_query_stats
-------------------
- on
-(1 row)
-
 select set_config('show_query_stats','off','f');
  set_config
 ------------
  off
 (1 row)
-
-SHOW show_query_stats;
- show_query_stats
-------------------
- off
-(1 row)
-
-select set_config('show_query_stats','on','t');
- set_config
-------------
- on
-(1 row)
-
-SHOW show_query_stats;
- show_query_stats
-------------------
- off
-(1 row)
-
-BEGIN;
-BEGIN
-select set_config('show_query_stats','on','t');
- set_config
-------------
- on
-(1 row)
-
-SHOW show_query_stats;
- show_query_stats
-------------------
- on
-(1 row)
-
-COMMIT;
-COMMIT
-SHOW show_query_stats;
- show_query_stats
-------------------
- off
-(1 row)
 </programlisting>
    </para>
 
@@ -5002,6 +4956,66 @@ SHOW show_query_stats;
        <entry><type>boolean</type></entry>
        <entry>does current user have access to table</entry>
       </row>
+      <row>
+       <entry><function>has_database_privilege</function>(<parameter>user</parameter>,
+                                  <parameter>database</parameter>,
+                                  <parameter>access</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>does user have access to database</entry>
+      </row>
+      <row>
+       <entry><function>has_database_privilege</function>(<parameter>database</parameter>,
+                                  <parameter>access</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>does current user have access to database</entry>
+      </row>
+      <row>
+       <entry><function>has_function_privilege</function>(<parameter>user</parameter>,
+                                  <parameter>function</parameter>,
+                                  <parameter>access</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>does user have access to function</entry>
+      </row>
+      <row>
+       <entry><function>has_function_privilege</function>(<parameter>function</parameter>,
+                                  <parameter>access</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>does current user have access to function</entry>
+      </row>
+      <row>
+       <entry><function>has_language_privilege</function>(<parameter>user</parameter>,
+                                  <parameter>language</parameter>,
+                                  <parameter>access</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>does user have access to language</entry>
+      </row>
+      <row>
+       <entry><function>has_language_privilege</function>(<parameter>language</parameter>,
+                                  <parameter>access</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>does current user have access to language</entry>
+      </row>
+      <row>
+       <entry><function>has_schema_privilege</function>(<parameter>user</parameter>,
+                                  <parameter>schema</parameter>,
+                                  <parameter>access</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>does user have access to schema</entry>
+      </row>
+      <row>
+       <entry><function>has_schema_privilege</function>(<parameter>schema</parameter>,
+                                  <parameter>access</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>does current user have access to schema</entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
@@ -5009,9 +5023,21 @@ SHOW show_query_stats;
    <indexterm zone="functions-misc">
     <primary>has_table_privilege</primary>
    </indexterm>
+   <indexterm zone="functions-misc">
+    <primary>has_database_privilege</primary>
+   </indexterm>
+   <indexterm zone="functions-misc">
+    <primary>has_function_privilege</primary>
+   </indexterm>
+   <indexterm zone="functions-misc">
+    <primary>has_language_privilege</primary>
+   </indexterm>
+   <indexterm zone="functions-misc">
+    <primary>has_schema_privilege</primary>
+   </indexterm>
 
    <para>
-    <function>has_table_privilege</function> determines whether a user
+    <function>has_table_privilege</function> checks whether a user
     can access a table in a particular way.  The user can be
     specified by name or by ID
     (<classname>pg_user</classname>.<structfield>usesysid</structfield>), or if the argument is
@@ -5032,6 +5058,140 @@ SELECT has_table_privilege('myschema.mytable', 'select');
 </programlisting>
    </para>
 
+   <para>
+    <function>has_database_privilege</function> checks whether a user
+    can access a database in a particular way.  The possibilities for its
+    arguments are analogous to <function>has_table_privilege</function>.
+    The desired access type must evaluate to
+    <literal>CREATE</literal>,
+    <literal>TEMPORARY</literal>, or
+    <literal>TEMP</literal> (which is equivalent to
+    <literal>TEMPORARY</literal>).
+   </para>
+
+   <para>
+    <function>has_function_privilege</function> checks whether a user
+    can access a function in a particular way.  The possibilities for its
+    arguments are analogous to <function>has_table_privilege</function>.
+    When specifying a function by a text string rather than by OID,
+    the allowed input is the same as for the <type>regprocedure</> datatype.
+    The desired access type must currently evaluate to
+    <literal>EXECUTE</literal>.
+   </para>
+
+   <para>
+    <function>has_language_privilege</function> checks whether a user
+    can access a procedural language in a particular way.  The possibilities
+    for its arguments are analogous to <function>has_table_privilege</function>.
+    The desired access type must currently evaluate to
+    <literal>USAGE</literal>.
+   </para>
+
+   <para>
+    <function>has_schema_privilege</function> checks whether a user
+    can access a schema in a particular way.  The possibilities for its
+    arguments are analogous to <function>has_table_privilege</function>.
+    The desired access type must evaluate to
+    <literal>CREATE</literal> or
+    <literal>USAGE</literal>.
+   </para>
+
+   <table>
+    <title>Schema Visibility Inquiry Functions</title>
+    <tgroup cols="3">
+     <thead>
+      <row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry></row>
+     </thead>
+
+     <tbody>
+      <row>
+       <entry><function>pg_table_is_visible</function>(<parameter>tableOID</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>is table visible in search path</entry>
+      </row>
+      <row>
+       <entry><function>pg_type_is_visible</function>(<parameter>typeOID</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>is type visible in search path</entry>
+      </row>
+      <row>
+       <entry><function>pg_function_is_visible</function>(<parameter>functionOID</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>is function visible in search path</entry>
+      </row>
+      <row>
+       <entry><function>pg_operator_is_visible</function>(<parameter>operatorOID</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>is operator visible in search path</entry>
+      </row>
+      <row>
+       <entry><function>pg_opclass_is_visible</function>(<parameter>opclassOID</parameter>)
+       </entry>
+       <entry><type>boolean</type></entry>
+       <entry>is operator class visible in search path</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+   <indexterm zone="functions-misc">
+    <primary>pg_table_is_visible</primary>
+   </indexterm>
+   <indexterm zone="functions-misc">
+    <primary>pg_type_is_visible</primary>
+   </indexterm>
+   <indexterm zone="functions-misc">
+    <primary>pg_function_is_visible</primary>
+   </indexterm>
+   <indexterm zone="functions-misc">
+    <primary>pg_operator_is_visible</primary>
+   </indexterm>
+   <indexterm zone="functions-misc">
+    <primary>pg_opclass_is_visible</primary>
+   </indexterm>
+
+   <para>
+    <function>pg_table_is_visible</function> checks whether a table
+    (or view, or any other kind of <structname>pg_class</> entry) is
+    <firstterm>visible</> in the current schema search path.  A table
+    is said to be visible if its containing schema is in the search path
+    and no table of the same name appears earlier in the search path.
+    This is equivalent to the statement that the table can be referenced
+    by name without explicit schema qualification.
+    For example, to list the names of all visible tables:
+<programlisting>
+SELECT relname FROM pg_class WHERE pg_table_is_visible(oid);
+</programlisting>
+   </para>
+
+   <para>
+    <function>pg_type_is_visible</function>,
+    <function>pg_function_is_visible</function>,
+    <function>pg_operator_is_visible</function>, and
+    <function>pg_opclass_is_visible</function> perform the same sort of
+    visibility check for types, functions, operators, and operator classes,
+    respectively.  For functions and operators, an object in the search path
+    is visible if there is no object of the same name <emphasis>and argument
+    datatype(s)</> earlier in the path.  For operator classes,
+    both name and associated index access method are considered.
+   </para>
+
+   <para>
+    All these functions require object OIDs to identify the object to be
+    checked.  If you want to test an object by name, it is convenient to use
+    the OID alias types (<type>regclass</>, <type>regtype</>,
+    <type>regprocedure</>, or <type>regoperator</>), for example
+<programlisting>
+SELECT pg_type_is_visible('myschema.widget'::regtype);
+</programlisting>
+    Note that it would not make much sense to test an unqualified name in
+    this way --- if the name can be recognized at all, it must be visible.
+   </para>
+
    <table>
     <title>Catalog Information Functions</title>
     <tgroup cols="3">
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 4999ea4b640..1aab73279fa 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.29 2002/08/08 01:44:30 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.30 2002/08/09 16:45:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -137,6 +137,13 @@ static void RemoveTempRelations(Oid tempNamespaceId);
 static void RemoveTempRelationsCallback(void);
 static void NamespaceCallback(Datum arg, Oid relid);
 
+/* These don't really need to appear in any header file */
+Datum pg_table_is_visible(PG_FUNCTION_ARGS);
+Datum pg_type_is_visible(PG_FUNCTION_ARGS);
+Datum pg_function_is_visible(PG_FUNCTION_ARGS);
+Datum pg_operator_is_visible(PG_FUNCTION_ARGS);
+Datum pg_opclass_is_visible(PG_FUNCTION_ARGS);
+
 
 /*
  * RangeVarGetRelid
@@ -1747,3 +1754,47 @@ fetch_search_path(bool includeImplicit)
 
 	return result;
 }
+
+/*
+ * Export the FooIsVisible functions as SQL-callable functions.
+ */
+
+Datum
+pg_table_is_visible(PG_FUNCTION_ARGS)
+{
+	Oid			oid = PG_GETARG_OID(0);
+
+	PG_RETURN_BOOL(RelationIsVisible(oid));
+}
+
+Datum
+pg_type_is_visible(PG_FUNCTION_ARGS)
+{
+	Oid			oid = PG_GETARG_OID(0);
+
+	PG_RETURN_BOOL(TypeIsVisible(oid));
+}
+
+Datum
+pg_function_is_visible(PG_FUNCTION_ARGS)
+{
+	Oid			oid = PG_GETARG_OID(0);
+
+	PG_RETURN_BOOL(FunctionIsVisible(oid));
+}
+
+Datum
+pg_operator_is_visible(PG_FUNCTION_ARGS)
+{
+	Oid			oid = PG_GETARG_OID(0);
+
+	PG_RETURN_BOOL(OperatorIsVisible(oid));
+}
+
+Datum
+pg_opclass_is_visible(PG_FUNCTION_ARGS)
+{
+	Oid			oid = PG_GETARG_OID(0);
+
+	PG_RETURN_BOOL(OpclassIsVisible(oid));
+}
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index e244a82d1ad..41ef71960de 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -7,7 +7,7 @@
  * Copyright (c) 1996-2001, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.55 2002/08/05 03:29:16 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.56 2002/08/09 16:45:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,12 +20,12 @@
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_constraint.h"
-#include "catalog/pg_database.h"
 #include "catalog/pg_description.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_trigger.h"
 #include "commands/comment.h"
+#include "commands/dbcommands.h"
 #include "miscadmin.h"
 #include "parser/parse_func.h"
 #include "parser/parse_oper.h"
@@ -398,34 +398,16 @@ static void
 CommentDatabase(List *qualname, char *comment)
 {
 	char	   *database;
-	Relation	pg_database;
-	ScanKeyData entry;
-	HeapScanDesc scan;
-	HeapTuple	dbtuple;
 	Oid			oid;
 
 	if (length(qualname) != 1)
 		elog(ERROR, "CommentDatabase: database name may not be qualified");
 	database = strVal(lfirst(qualname));
 
-	/* Only allow comments on the current database */
-	if (strcmp(database, DatabaseName) != 0)
-		elog(ERROR, "Database comments may only be applied to the current database");
-
-	/* First find the tuple in pg_database for the database */
-
-	pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
-	ScanKeyEntryInitialize(&entry, 0, Anum_pg_database_datname,
-						   F_NAMEEQ, CStringGetDatum(database));
-	scan = heap_beginscan(pg_database, SnapshotNow, 1, &entry);
-	dbtuple = heap_getnext(scan, ForwardScanDirection);
-
-	/* Validate database exists, and fetch the db oid */
-
-	if (!HeapTupleIsValid(dbtuple))
+	/* First get the database OID */
+	oid = get_database_oid(database);
+	if (!OidIsValid(oid))
 		elog(ERROR, "database \"%s\" does not exist", database);
-	AssertTupleDescHasOid(pg_database->rd_att);
-	oid = HeapTupleGetOid(dbtuple);
 
 	/* Allow if the user matches the database dba or is a superuser */
 
@@ -433,14 +415,12 @@ CommentDatabase(List *qualname, char *comment)
 		elog(ERROR, "you are not permitted to comment on database \"%s\"",
 			 database);
 
-	/* Create the comment with the pg_database oid */
+	/* Only allow comments on the current database */
+	if (oid != MyDatabaseId)
+		elog(ERROR, "Database comments may only be applied to the current database");
 
+	/* Create the comment with the pg_database oid */
 	CreateComments(oid, RelOid_pg_database, 0, comment);
-
-	/* Complete the scan and close any opened relations */
-
-	heap_endscan(scan);
-	heap_close(pg_database, AccessShareLock);
 }
 
 /*
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index d043d95b784..53c8391c0c5 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.98 2002/08/05 03:29:16 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.99 2002/08/09 16:45:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -746,3 +746,78 @@ remove_dbdirs(const char *nominal_loc, const char *alt_loc)
 
 	return success;
 }
+
+
+/*
+ * get_database_oid - given a database name, look up the OID
+ *
+ * Returns InvalidOid if database name not found.
+ *
+ * This is not actually used in this file, but is exported for use elsewhere.
+ */
+Oid
+get_database_oid(const char *dbname)
+{
+	Relation	pg_database;
+	ScanKeyData entry[1];
+	HeapScanDesc scan;
+	HeapTuple	dbtuple;
+	Oid			oid;
+
+	/* There's no syscache for pg_database, so must look the hard way */
+	pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
+	ScanKeyEntryInitialize(&entry[0], 0x0,
+						   Anum_pg_database_datname, F_NAMEEQ,
+						   CStringGetDatum(dbname));
+	scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
+
+	dbtuple = heap_getnext(scan, ForwardScanDirection);
+
+	/* We assume that there can be at most one matching tuple */
+	if (HeapTupleIsValid(dbtuple))
+		oid = HeapTupleGetOid(dbtuple);
+	else
+		oid = InvalidOid;
+
+	heap_endscan(scan);
+	heap_close(pg_database, AccessShareLock);
+
+	return oid;
+}
+
+/*
+ * get_database_owner - given a database OID, fetch the owner's usesysid.
+ *
+ * Errors out if database not found.
+ *
+ * This is not actually used in this file, but is exported for use elsewhere.
+ */
+Oid
+get_database_owner(Oid dbid)
+{
+	Relation	pg_database;
+	ScanKeyData entry[1];
+	HeapScanDesc scan;
+	HeapTuple	dbtuple;
+	int32		dba;
+
+	/* There's no syscache for pg_database, so must look the hard way */
+	pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
+	ScanKeyEntryInitialize(&entry[0], 0x0,
+						   ObjectIdAttributeNumber, F_OIDEQ,
+						   ObjectIdGetDatum(dbid));
+	scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
+
+	dbtuple = heap_getnext(scan, ForwardScanDirection);
+
+	if (!HeapTupleIsValid(dbtuple))
+		elog(ERROR, "database %u does not exist", dbid);
+
+	dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
+
+	heap_endscan(scan);
+	heap_close(pg_database, AccessShareLock);
+
+	/* XXX some confusion about whether userids are OID or int4 ... */
+	return (Oid) dba;
+}
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 1b0296965e5..494a262f0bd 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.74 2002/06/20 20:29:36 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.75 2002/08/09 16:45:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 
 #include "catalog/namespace.h"
 #include "catalog/pg_shadow.h"
+#include "commands/dbcommands.h"
 #include "miscadmin.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -34,8 +35,16 @@ static const char *aclparse(const char *s, AclItem *aip, unsigned *modechg);
 static bool aclitemeq(const AclItem *a1, const AclItem *a2);
 static bool aclitemgt(const AclItem *a1, const AclItem *a2);
 
-static AclMode convert_priv_string(text *priv_type_text);
-static Oid convert_rel_name(text *relname);
+static Oid convert_table_name(text *tablename);
+static AclMode convert_table_priv_string(text *priv_type_text);
+static Oid convert_database_name(text *databasename);
+static AclMode convert_database_priv_string(text *priv_type_text);
+static Oid convert_function_name(text *functionname);
+static AclMode convert_function_priv_string(text *priv_type_text);
+static Oid convert_language_name(text *languagename);
+static AclMode convert_language_priv_string(text *priv_type_text);
+static Oid convert_schema_name(text *schemaname);
+static AclMode convert_schema_priv_string(text *priv_type_text);
 
 
 /*
@@ -646,266 +655,179 @@ aclcontains(PG_FUNCTION_ARGS)
 
 
 /*
- * has_table_privilege_name_name
- *		Check user privileges on a relation given
- *		name username, text relname, and text priv name.
+ * has_table_privilege variants
+ *		These are all named "has_table_privilege" at the SQL level.
+ *		They take various combinations of relation name, relation OID,
+ *		user name, user sysid, or implicit user = current_user.
  *
- * RETURNS
- *		a boolean value
- *		't' indicating user has the privilege
- *		'f' indicating user does not have the privilege
+ *		The result is a boolean value: true if user has the indicated
+ *		privilege, false if not.
+ */
+
+/*
+ * has_table_privilege_name_name
+ *		Check user privileges on a table given
+ *		name username, text tablename, and text priv name.
  */
 Datum
 has_table_privilege_name_name(PG_FUNCTION_ARGS)
 {
 	Name		username = PG_GETARG_NAME(0);
-	text	   *relname = PG_GETARG_TEXT_P(1);
+	text	   *tablename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	int32		usesysid;
-	Oid			reloid;
+	Oid			tableoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	/*
-	 * Lookup userid based on username
-	 */
 	usesysid = get_usesysid(NameStr(*username));
+	tableoid = convert_table_name(tablename);
+	mode = convert_table_priv_string(priv_type_text);
 
-	/*
-	 * Lookup rel OID based on relname
-	 */
-	reloid = convert_rel_name(relname);
-
-	/*
-	 * Convert priv_type_text to an AclMode
-	 */
-	mode = convert_priv_string(priv_type_text);
-
-	/*
-	 * Check for the privilege
-	 */
-	aclresult = pg_class_aclcheck(reloid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
 
-
 /*
  * has_table_privilege_name
- *		Check user privileges on a relation given
- *		text relname and text priv name.
+ *		Check user privileges on a table given
+ *		text tablename and text priv name.
  *		current_user is assumed
- *
- * RETURNS
- *		a boolean value
- *		't' indicating user has the privilege
- *		'f' indicating user does not have the privilege
  */
 Datum
 has_table_privilege_name(PG_FUNCTION_ARGS)
 {
-	text	   *relname = PG_GETARG_TEXT_P(0);
+	text	   *tablename = PG_GETARG_TEXT_P(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
 	int32		usesysid;
-	Oid			reloid;
+	Oid			tableoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
 	usesysid = GetUserId();
+	tableoid = convert_table_name(tablename);
+	mode = convert_table_priv_string(priv_type_text);
 
-	/*
-	 * Lookup rel OID based on relname
-	 */
-	reloid = convert_rel_name(relname);
-
-	/*
-	 * Convert priv_type_text to an AclMode
-	 */
-	mode = convert_priv_string(priv_type_text);
-
-	/*
-	 * Check for the privilege
-	 */
-	aclresult = pg_class_aclcheck(reloid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
 
-
 /*
  * has_table_privilege_name_id
- *		Check user privileges on a relation given
- *		name usename, rel oid, and text priv name.
- *
- * RETURNS
- *		a boolean value
- *		't' indicating user has the privilege
- *		'f' indicating user does not have the privilege
+ *		Check user privileges on a table given
+ *		name usename, table oid, and text priv name.
  */
 Datum
 has_table_privilege_name_id(PG_FUNCTION_ARGS)
 {
 	Name		username = PG_GETARG_NAME(0);
-	Oid			reloid = PG_GETARG_OID(1);
+	Oid			tableoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	int32		usesysid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	/*
-	 * Lookup userid based on username
-	 */
 	usesysid = get_usesysid(NameStr(*username));
+	mode = convert_table_priv_string(priv_type_text);
 
-	/*
-	 * Convert priv_type_text to an AclMode
-	 */
-	mode = convert_priv_string(priv_type_text);
-
-	/*
-	 * Check for the privilege
-	 */
-	aclresult = pg_class_aclcheck(reloid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
 
-
 /*
  * has_table_privilege_id
- *		Check user privileges on a relation given
- *		rel oid, and text priv name.
+ *		Check user privileges on a table given
+ *		table oid, and text priv name.
  *		current_user is assumed
- *
- * RETURNS
- *		a boolean value
- *		't' indicating user has the privilege
- *		'f' indicating user does not have the privilege
  */
 Datum
 has_table_privilege_id(PG_FUNCTION_ARGS)
 {
-	Oid			reloid = PG_GETARG_OID(0);
+	Oid			tableoid = PG_GETARG_OID(0);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
 	int32		usesysid;
 	AclMode		mode;
 	AclResult	aclresult;
 
 	usesysid = GetUserId();
+	mode = convert_table_priv_string(priv_type_text);
 
-	/*
-	 * Convert priv_type_text to an AclMode
-	 */
-	mode = convert_priv_string(priv_type_text);
-
-	/*
-	 * Check for the privilege
-	 */
-	aclresult = pg_class_aclcheck(reloid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
 
-
 /*
  * has_table_privilege_id_name
- *		Check user privileges on a relation given
- *		usesysid, text relname, and priv name.
- *
- * RETURNS
- *		a boolean value
- *		't' indicating user has the privilege
- *		'f' indicating user does not have the privilege
+ *		Check user privileges on a table given
+ *		usesysid, text tablename, and text priv name.
  */
 Datum
 has_table_privilege_id_name(PG_FUNCTION_ARGS)
 {
 	int32		usesysid = PG_GETARG_INT32(0);
-	text	   *relname = PG_GETARG_TEXT_P(1);
+	text	   *tablename = PG_GETARG_TEXT_P(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
-	Oid			reloid;
+	Oid			tableoid;
 	AclMode		mode;
 	AclResult	aclresult;
 
-	/*
-	 * Lookup rel OID based on relname
-	 */
-	reloid = convert_rel_name(relname);
-
-	/*
-	 * Convert priv_type_text to an AclMode
-	 */
-	mode = convert_priv_string(priv_type_text);
+	tableoid = convert_table_name(tablename);
+	mode = convert_table_priv_string(priv_type_text);
 
-	/*
-	 * Check for the privilege
-	 */
-	aclresult = pg_class_aclcheck(reloid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
 
-
 /*
  * has_table_privilege_id_id
- *		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
+ *		Check user privileges on a table given
+ *		usesysid, table oid, and text priv name.
  */
 Datum
 has_table_privilege_id_id(PG_FUNCTION_ARGS)
 {
 	int32		usesysid = PG_GETARG_INT32(0);
-	Oid			reloid = PG_GETARG_OID(1);
+	Oid			tableoid = PG_GETARG_OID(1);
 	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
 	AclMode		mode;
 	AclResult	aclresult;
 
-	/*
-	 * Convert priv_type_text to an AclMode
-	 */
-	mode = convert_priv_string(priv_type_text);
+	mode = convert_table_priv_string(priv_type_text);
 
-	/*
-	 * Check for the privilege
-	 */
-	aclresult = pg_class_aclcheck(reloid, usesysid, mode);
+	aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
 
 	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 }
 
 /*
- *		Internal functions.
+ *		Support routines for has_table_privilege family.
  */
 
 /*
- * Given a relation name expressed as a string, look it up and return Oid
+ * Given a table name expressed as a string, look it up and return Oid
  */
 static Oid
-convert_rel_name(text *relname)
+convert_table_name(text *tablename)
 {
 	RangeVar   *relrv;
 
-	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
+	relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename,
 													"has_table_privilege"));
 
 	return RangeVarGetRelid(relrv, false);
 }
 
 /*
- * convert_priv_string
- *		Internal function.
- *		Return mode from priv_type string
- *
- * RETURNS
- *		AclMode
+ * convert_table_priv_string
+ *		Convert text string to AclMode value.
  */
 static AclMode
-convert_priv_string(text *priv_type_text)
+convert_table_priv_string(text *priv_type_text)
 {
 	char	   *priv_type;
 
@@ -936,10 +858,810 @@ convert_priv_string(text *priv_type_text)
 	if (strcasecmp(priv_type, "TRIGGER") == 0)
 		return ACL_TRIGGER;
 
-	elog(ERROR, "has_table_privilege: invalid privilege type %s", priv_type);
+	elog(ERROR, "has_table_privilege: invalid privilege type %s",
+		 priv_type);
+	return ACL_NO_RIGHTS;		/* keep compiler quiet */
+}
+
+
+/*
+ * has_database_privilege variants
+ *		These are all named "has_database_privilege" at the SQL level.
+ *		They take various combinations of database name, database OID,
+ *		user name, user sysid, or implicit user = current_user.
+ *
+ *		The result is a boolean value: true if user has the indicated
+ *		privilege, false if not.
+ */
+
+/*
+ * has_database_privilege_name_name
+ *		Check user privileges on a database given
+ *		name username, text databasename, and text priv name.
+ */
+Datum
+has_database_privilege_name_name(PG_FUNCTION_ARGS)
+{
+	Name		username = PG_GETARG_NAME(0);
+	text	   *databasename = PG_GETARG_TEXT_P(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	int32		usesysid;
+	Oid			databaseoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = get_usesysid(NameStr(*username));
+	databaseoid = convert_database_name(databasename);
+	mode = convert_database_priv_string(priv_type_text);
+
+	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_database_privilege_name
+ *		Check user privileges on a database given
+ *		text databasename and text priv name.
+ *		current_user is assumed
+ */
+Datum
+has_database_privilege_name(PG_FUNCTION_ARGS)
+{
+	text	   *databasename = PG_GETARG_TEXT_P(0);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
+	int32		usesysid;
+	Oid			databaseoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = GetUserId();
+	databaseoid = convert_database_name(databasename);
+	mode = convert_database_priv_string(priv_type_text);
+
+	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_database_privilege_name_id
+ *		Check user privileges on a database given
+ *		name usename, database oid, and text priv name.
+ */
+Datum
+has_database_privilege_name_id(PG_FUNCTION_ARGS)
+{
+	Name		username = PG_GETARG_NAME(0);
+	Oid			databaseoid = PG_GETARG_OID(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	int32		usesysid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = get_usesysid(NameStr(*username));
+	mode = convert_database_priv_string(priv_type_text);
+
+	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_database_privilege_id
+ *		Check user privileges on a database given
+ *		database oid, and text priv name.
+ *		current_user is assumed
+ */
+Datum
+has_database_privilege_id(PG_FUNCTION_ARGS)
+{
+	Oid			databaseoid = PG_GETARG_OID(0);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
+	int32		usesysid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = GetUserId();
+	mode = convert_database_priv_string(priv_type_text);
+
+	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_database_privilege_id_name
+ *		Check user privileges on a database given
+ *		usesysid, text databasename, and text priv name.
+ */
+Datum
+has_database_privilege_id_name(PG_FUNCTION_ARGS)
+{
+	int32		usesysid = PG_GETARG_INT32(0);
+	text	   *databasename = PG_GETARG_TEXT_P(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	Oid			databaseoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	databaseoid = convert_database_name(databasename);
+	mode = convert_database_priv_string(priv_type_text);
+
+	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_database_privilege_id_id
+ *		Check user privileges on a database given
+ *		usesysid, database oid, and text priv name.
+ */
+Datum
+has_database_privilege_id_id(PG_FUNCTION_ARGS)
+{
+	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			databaseoid = PG_GETARG_OID(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	AclMode		mode;
+	AclResult	aclresult;
+
+	mode = convert_database_priv_string(priv_type_text);
+
+	aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ *		Support routines for has_database_privilege family.
+ */
+
+/*
+ * Given a database name expressed as a string, look it up and return Oid
+ */
+static Oid
+convert_database_name(text *databasename)
+{
+	char	   *dbname;
+	Oid			oid;
+
+	dbname = DatumGetCString(DirectFunctionCall1(textout,
+											PointerGetDatum(databasename)));
+
+	oid = get_database_oid(dbname);
+	if (!OidIsValid(oid))
+		elog(ERROR, "database \"%s\" does not exist", dbname);
+
+	return oid;
+}
+
+/*
+ * convert_database_priv_string
+ *		Convert text string to AclMode value.
+ */
+static AclMode
+convert_database_priv_string(text *priv_type_text)
+{
+	char	   *priv_type;
+
+	priv_type = DatumGetCString(DirectFunctionCall1(textout,
+											PointerGetDatum(priv_type_text)));
 
 	/*
-	 * We should never get here, but stop the compiler from complaining
+	 * Return mode from priv_type string
 	 */
-	return ACL_NO_RIGHTS;
+	if (strcasecmp(priv_type, "CREATE") == 0)
+		return ACL_CREATE;
+
+	if (strcasecmp(priv_type, "TEMPORARY") == 0)
+		return ACL_CREATE_TEMP;
+
+	if (strcasecmp(priv_type, "TEMP") == 0)
+		return ACL_CREATE_TEMP;
+
+	elog(ERROR, "has_database_privilege: invalid privilege type %s",
+		 priv_type);
+	return ACL_NO_RIGHTS;		/* keep compiler quiet */
+}
+
+
+/*
+ * has_function_privilege variants
+ *		These are all named "has_function_privilege" at the SQL level.
+ *		They take various combinations of function name, function OID,
+ *		user name, user sysid, or implicit user = current_user.
+ *
+ *		The result is a boolean value: true if user has the indicated
+ *		privilege, false if not.
+ */
+
+/*
+ * has_function_privilege_name_name
+ *		Check user privileges on a function given
+ *		name username, text functionname, and text priv name.
+ */
+Datum
+has_function_privilege_name_name(PG_FUNCTION_ARGS)
+{
+	Name		username = PG_GETARG_NAME(0);
+	text	   *functionname = PG_GETARG_TEXT_P(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	int32		usesysid;
+	Oid			functionoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = get_usesysid(NameStr(*username));
+	functionoid = convert_function_name(functionname);
+	mode = convert_function_priv_string(priv_type_text);
+
+	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_function_privilege_name
+ *		Check user privileges on a function given
+ *		text functionname and text priv name.
+ *		current_user is assumed
+ */
+Datum
+has_function_privilege_name(PG_FUNCTION_ARGS)
+{
+	text	   *functionname = PG_GETARG_TEXT_P(0);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
+	int32		usesysid;
+	Oid			functionoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = GetUserId();
+	functionoid = convert_function_name(functionname);
+	mode = convert_function_priv_string(priv_type_text);
+
+	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_function_privilege_name_id
+ *		Check user privileges on a function given
+ *		name usename, function oid, and text priv name.
+ */
+Datum
+has_function_privilege_name_id(PG_FUNCTION_ARGS)
+{
+	Name		username = PG_GETARG_NAME(0);
+	Oid			functionoid = PG_GETARG_OID(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	int32		usesysid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = get_usesysid(NameStr(*username));
+	mode = convert_function_priv_string(priv_type_text);
+
+	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_function_privilege_id
+ *		Check user privileges on a function given
+ *		function oid, and text priv name.
+ *		current_user is assumed
+ */
+Datum
+has_function_privilege_id(PG_FUNCTION_ARGS)
+{
+	Oid			functionoid = PG_GETARG_OID(0);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
+	int32		usesysid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = GetUserId();
+	mode = convert_function_priv_string(priv_type_text);
+
+	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_function_privilege_id_name
+ *		Check user privileges on a function given
+ *		usesysid, text functionname, and text priv name.
+ */
+Datum
+has_function_privilege_id_name(PG_FUNCTION_ARGS)
+{
+	int32		usesysid = PG_GETARG_INT32(0);
+	text	   *functionname = PG_GETARG_TEXT_P(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	Oid			functionoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	functionoid = convert_function_name(functionname);
+	mode = convert_function_priv_string(priv_type_text);
+
+	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_function_privilege_id_id
+ *		Check user privileges on a function given
+ *		usesysid, function oid, and text priv name.
+ */
+Datum
+has_function_privilege_id_id(PG_FUNCTION_ARGS)
+{
+	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			functionoid = PG_GETARG_OID(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	AclMode		mode;
+	AclResult	aclresult;
+
+	mode = convert_function_priv_string(priv_type_text);
+
+	aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ *		Support routines for has_function_privilege family.
+ */
+
+/*
+ * Given a function name expressed as a string, look it up and return Oid
+ */
+static Oid
+convert_function_name(text *functionname)
+{
+	char	   *funcname;
+	Oid			oid;
+
+	funcname = DatumGetCString(DirectFunctionCall1(textout,
+											PointerGetDatum(functionname)));
+
+	oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
+											   CStringGetDatum(funcname)));
+
+	if (!OidIsValid(oid))
+		elog(ERROR, "function \"%s\" does not exist", funcname);
+
+	return oid;
+}
+
+/*
+ * convert_function_priv_string
+ *		Convert text string to AclMode value.
+ */
+static AclMode
+convert_function_priv_string(text *priv_type_text)
+{
+	char	   *priv_type;
+
+	priv_type = DatumGetCString(DirectFunctionCall1(textout,
+											PointerGetDatum(priv_type_text)));
+
+	/*
+	 * Return mode from priv_type string
+	 */
+	if (strcasecmp(priv_type, "EXECUTE") == 0)
+		return ACL_EXECUTE;
+
+	elog(ERROR, "has_function_privilege: invalid privilege type %s",
+		 priv_type);
+	return ACL_NO_RIGHTS;		/* keep compiler quiet */
+}
+
+
+/*
+ * has_language_privilege variants
+ *		These are all named "has_language_privilege" at the SQL level.
+ *		They take various combinations of language name, language OID,
+ *		user name, user sysid, or implicit user = current_user.
+ *
+ *		The result is a boolean value: true if user has the indicated
+ *		privilege, false if not.
+ */
+
+/*
+ * has_language_privilege_name_name
+ *		Check user privileges on a language given
+ *		name username, text languagename, and text priv name.
+ */
+Datum
+has_language_privilege_name_name(PG_FUNCTION_ARGS)
+{
+	Name		username = PG_GETARG_NAME(0);
+	text	   *languagename = PG_GETARG_TEXT_P(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	int32		usesysid;
+	Oid			languageoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = get_usesysid(NameStr(*username));
+	languageoid = convert_language_name(languagename);
+	mode = convert_language_priv_string(priv_type_text);
+
+	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_language_privilege_name
+ *		Check user privileges on a language given
+ *		text languagename and text priv name.
+ *		current_user is assumed
+ */
+Datum
+has_language_privilege_name(PG_FUNCTION_ARGS)
+{
+	text	   *languagename = PG_GETARG_TEXT_P(0);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
+	int32		usesysid;
+	Oid			languageoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = GetUserId();
+	languageoid = convert_language_name(languagename);
+	mode = convert_language_priv_string(priv_type_text);
+
+	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_language_privilege_name_id
+ *		Check user privileges on a language given
+ *		name usename, language oid, and text priv name.
+ */
+Datum
+has_language_privilege_name_id(PG_FUNCTION_ARGS)
+{
+	Name		username = PG_GETARG_NAME(0);
+	Oid			languageoid = PG_GETARG_OID(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	int32		usesysid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = get_usesysid(NameStr(*username));
+	mode = convert_language_priv_string(priv_type_text);
+
+	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_language_privilege_id
+ *		Check user privileges on a language given
+ *		language oid, and text priv name.
+ *		current_user is assumed
+ */
+Datum
+has_language_privilege_id(PG_FUNCTION_ARGS)
+{
+	Oid			languageoid = PG_GETARG_OID(0);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
+	int32		usesysid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = GetUserId();
+	mode = convert_language_priv_string(priv_type_text);
+
+	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_language_privilege_id_name
+ *		Check user privileges on a language given
+ *		usesysid, text languagename, and text priv name.
+ */
+Datum
+has_language_privilege_id_name(PG_FUNCTION_ARGS)
+{
+	int32		usesysid = PG_GETARG_INT32(0);
+	text	   *languagename = PG_GETARG_TEXT_P(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	Oid			languageoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	languageoid = convert_language_name(languagename);
+	mode = convert_language_priv_string(priv_type_text);
+
+	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_language_privilege_id_id
+ *		Check user privileges on a language given
+ *		usesysid, language oid, and text priv name.
+ */
+Datum
+has_language_privilege_id_id(PG_FUNCTION_ARGS)
+{
+	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			languageoid = PG_GETARG_OID(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	AclMode		mode;
+	AclResult	aclresult;
+
+	mode = convert_language_priv_string(priv_type_text);
+
+	aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ *		Support routines for has_language_privilege family.
+ */
+
+/*
+ * Given a language name expressed as a string, look it up and return Oid
+ */
+static Oid
+convert_language_name(text *languagename)
+{
+	char	   *langname;
+	Oid			oid;
+
+	langname = DatumGetCString(DirectFunctionCall1(textout,
+											PointerGetDatum(languagename)));
+
+	oid = GetSysCacheOid(LANGNAME,
+						 CStringGetDatum(langname),
+						 0, 0, 0);
+	if (!OidIsValid(oid))
+		elog(ERROR, "language \"%s\" does not exist", langname);
+
+	return oid;
+}
+
+/*
+ * convert_language_priv_string
+ *		Convert text string to AclMode value.
+ */
+static AclMode
+convert_language_priv_string(text *priv_type_text)
+{
+	char	   *priv_type;
+
+	priv_type = DatumGetCString(DirectFunctionCall1(textout,
+											PointerGetDatum(priv_type_text)));
+
+	/*
+	 * Return mode from priv_type string
+	 */
+	if (strcasecmp(priv_type, "USAGE") == 0)
+		return ACL_USAGE;
+
+	elog(ERROR, "has_language_privilege: invalid privilege type %s",
+		 priv_type);
+	return ACL_NO_RIGHTS;		/* keep compiler quiet */
+}
+
+
+/*
+ * has_schema_privilege variants
+ *		These are all named "has_schema_privilege" at the SQL level.
+ *		They take various combinations of schema name, schema OID,
+ *		user name, user sysid, or implicit user = current_user.
+ *
+ *		The result is a boolean value: true if user has the indicated
+ *		privilege, false if not.
+ */
+
+/*
+ * has_schema_privilege_name_name
+ *		Check user privileges on a schema given
+ *		name username, text schemaname, and text priv name.
+ */
+Datum
+has_schema_privilege_name_name(PG_FUNCTION_ARGS)
+{
+	Name		username = PG_GETARG_NAME(0);
+	text	   *schemaname = PG_GETARG_TEXT_P(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	int32		usesysid;
+	Oid			schemaoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = get_usesysid(NameStr(*username));
+	schemaoid = convert_schema_name(schemaname);
+	mode = convert_schema_priv_string(priv_type_text);
+
+	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_schema_privilege_name
+ *		Check user privileges on a schema given
+ *		text schemaname and text priv name.
+ *		current_user is assumed
+ */
+Datum
+has_schema_privilege_name(PG_FUNCTION_ARGS)
+{
+	text	   *schemaname = PG_GETARG_TEXT_P(0);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
+	int32		usesysid;
+	Oid			schemaoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = GetUserId();
+	schemaoid = convert_schema_name(schemaname);
+	mode = convert_schema_priv_string(priv_type_text);
+
+	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_schema_privilege_name_id
+ *		Check user privileges on a schema given
+ *		name usename, schema oid, and text priv name.
+ */
+Datum
+has_schema_privilege_name_id(PG_FUNCTION_ARGS)
+{
+	Name		username = PG_GETARG_NAME(0);
+	Oid			schemaoid = PG_GETARG_OID(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	int32		usesysid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = get_usesysid(NameStr(*username));
+	mode = convert_schema_priv_string(priv_type_text);
+
+	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_schema_privilege_id
+ *		Check user privileges on a schema given
+ *		schema oid, and text priv name.
+ *		current_user is assumed
+ */
+Datum
+has_schema_privilege_id(PG_FUNCTION_ARGS)
+{
+	Oid			schemaoid = PG_GETARG_OID(0);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(1);
+	int32		usesysid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	usesysid = GetUserId();
+	mode = convert_schema_priv_string(priv_type_text);
+
+	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_schema_privilege_id_name
+ *		Check user privileges on a schema given
+ *		usesysid, text schemaname, and text priv name.
+ */
+Datum
+has_schema_privilege_id_name(PG_FUNCTION_ARGS)
+{
+	int32		usesysid = PG_GETARG_INT32(0);
+	text	   *schemaname = PG_GETARG_TEXT_P(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	Oid			schemaoid;
+	AclMode		mode;
+	AclResult	aclresult;
+
+	schemaoid = convert_schema_name(schemaname);
+	mode = convert_schema_priv_string(priv_type_text);
+
+	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_schema_privilege_id_id
+ *		Check user privileges on a schema given
+ *		usesysid, schema oid, and text priv name.
+ */
+Datum
+has_schema_privilege_id_id(PG_FUNCTION_ARGS)
+{
+	int32		usesysid = PG_GETARG_INT32(0);
+	Oid			schemaoid = PG_GETARG_OID(1);
+	text	   *priv_type_text = PG_GETARG_TEXT_P(2);
+	AclMode		mode;
+	AclResult	aclresult;
+
+	mode = convert_schema_priv_string(priv_type_text);
+
+	aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
+
+	PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ *		Support routines for has_schema_privilege family.
+ */
+
+/*
+ * Given a schema name expressed as a string, look it up and return Oid
+ */
+static Oid
+convert_schema_name(text *schemaname)
+{
+	char	   *nspname;
+	Oid			oid;
+
+	nspname = DatumGetCString(DirectFunctionCall1(textout,
+											PointerGetDatum(schemaname)));
+
+	oid = GetSysCacheOid(NAMESPACENAME,
+						 CStringGetDatum(nspname),
+						 0, 0, 0);
+	if (!OidIsValid(oid))
+		elog(ERROR, "schema \"%s\" does not exist", nspname);
+
+	return oid;
+}
+
+/*
+ * convert_schema_priv_string
+ *		Convert text string to AclMode value.
+ */
+static AclMode
+convert_schema_priv_string(text *priv_type_text)
+{
+	char	   *priv_type;
+
+	priv_type = DatumGetCString(DirectFunctionCall1(textout,
+											PointerGetDatum(priv_type_text)));
+
+	/*
+	 * Return mode from priv_type string
+	 */
+	if (strcasecmp(priv_type, "CREATE") == 0)
+		return ACL_CREATE;
+
+	if (strcasecmp(priv_type, "USAGE") == 0)
+		return ACL_USAGE;
+
+	elog(ERROR, "has_schema_privilege: invalid privilege type %s",
+		 priv_type);
+	return ACL_NO_RIGHTS;		/* keep compiler quiet */
 }
diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c
index 609e20219c2..d4ba7a18050 100644
--- a/src/backend/utils/adt/sets.c
+++ b/src/backend/utils/adt/sets.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.50 2002/08/05 03:29:17 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.51 2002/08/09 16:45:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,6 +25,7 @@
 #include "catalog/pg_proc.h"
 #include "executor/executor.h"
 #include "utils/fcache.h"
+#include "utils/fmgroids.h"
 #include "utils/sets.h"
 #include "utils/syscache.h"
 
@@ -58,7 +59,7 @@ SetDefine(char *querystr, Oid elemType)
 							 true,		/* returnsSet */
 							 elemType,	/* returnType */
 							 SQLlanguageId,	/* language */
-							 SQLvalidatorId,
+							 F_FMGR_SQL_VALIDATOR,
 							 querystr,	/* prosrc */
 							 fileName,	/* probin */
 							 false,		/* not aggregate */
diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c
index 9652b5c01aa..735ad7adf32 100644
--- a/src/backend/utils/misc/superuser.c
+++ b/src/backend/utils/misc/superuser.c
@@ -10,19 +10,17 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.23 2002/06/20 20:29:40 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.24 2002/08/09 16:45:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/heapam.h"
-#include "catalog/catname.h"
-#include "catalog/pg_database.h"
 #include "catalog/pg_shadow.h"
+#include "commands/dbcommands.h"
 #include "utils/syscache.h"
 #include "miscadmin.h"
-#include "utils/fmgroids.h"
 
 
 /*
@@ -69,25 +67,9 @@ superuser_arg(Oid userid)
 bool
 is_dbadmin(Oid dbid)
 {
-	Relation	pg_database;
-	ScanKeyData entry[1];
-	HeapScanDesc scan;
-	HeapTuple	dbtuple;
-	int32		dba;
+	Oid			dba;
 
-	/* There's no syscache for pg_database, so must look the hard way */
-	pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
-	ScanKeyEntryInitialize(&entry[0], 0x0,
-						   ObjectIdAttributeNumber, F_OIDEQ,
-						   ObjectIdGetDatum(dbid));
-	scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
-	dbtuple = heap_getnext(scan, ForwardScanDirection);
-	if (!HeapTupleIsValid(dbtuple))
-		elog(ERROR, "database %u does not exist", dbid);
-	dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
-	heap_endscan(scan);
-	heap_close(pg_database, AccessShareLock);
+	dba = get_database_owner(dbid);
 
-	/* XXX some confusion about whether userids are OID or int4 ... */
-	return (GetUserId() == (Oid) dba);
+	return (GetUserId() == dba);
 }
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index f3dfa81879d..792b2858f1d 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.146 2002/08/06 05:40:45 ishii Exp $
+ * $Id: catversion.h,v 1.147 2002/08/09 16:45:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200208061
+#define CATALOG_VERSION_NO	200208091
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index afd8a782cc2..c4717e7b511 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.252 2002/08/06 05:40:45 ishii Exp $
+ * $Id: pg_proc.h,v 1.253 2002/08/09 16:45:15 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -2675,15 +2675,15 @@ DATA(insert OID = 1915 (  numeric_uplus    PGNSP PGUID 12 f f t f i 1 1700 "1700
 DESCR("unary plus");
 
 DATA(insert OID = 1922 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 25 25"  has_table_privilege_name_name - _null_ ));
-DESCR("user privilege on relation by username, relname");
+DESCR("user privilege on relation by username, rel name");
 DATA(insert OID = 1923 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25"  has_table_privilege_name_id - _null_ ));
 DESCR("user privilege on relation by username, rel oid");
 DATA(insert OID = 1924 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25"  has_table_privilege_id_name - _null_ ));
-DESCR("user privilege on relation by usesysid, relname");
+DESCR("user privilege on relation by usesysid, rel name");
 DATA(insert OID = 1925 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25"  has_table_privilege_id_id - _null_ ));
 DESCR("user privilege on relation by usesysid, rel oid");
 DATA(insert OID = 1926 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25"	has_table_privilege_name - _null_ ));
-DESCR("current user privilege on relation by relname");
+DESCR("current user privilege on relation by rel name");
 DATA(insert OID = 1927 (  has_table_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25"	has_table_privilege_id - _null_ ));
 DESCR("current user privilege on relation by rel oid");
 
@@ -2881,11 +2881,23 @@ DESCR("int8 to bitstring");
 DATA(insert OID = 2076 (  int8				PGNSP PGUID 12 f f t f i 1 20 "1560"	bittoint8 - _null_ ));
 DESCR("bitstring to int8");
 
-DATA(insert OID = 2090 (  current_setting	PGNSP PGUID 12 f f t f s 1 25 "25" show_config_by_name - _null_ ));
+DATA(insert OID = 2077 (  current_setting	PGNSP PGUID 12 f f t f s 1 25 "25" show_config_by_name - _null_ ));
 DESCR("SHOW X as a function");
-DATA(insert OID = 2091 (  set_config		PGNSP PGUID 12 f f f f v 3 25 "25 25 16" set_config_by_name - _null_ ));
+DATA(insert OID = 2078 (  set_config		PGNSP PGUID 12 f f f f v 3 25 "25 25 16" set_config_by_name - _null_ ));
 DESCR("SET X as a function");
 
+DATA(insert OID = 2079 (  pg_table_is_visible		PGNSP PGUID 12 f f t f s 1 16 "26"  pg_table_is_visible - _null_ ));
+DESCR("is table visible in search path?");
+DATA(insert OID = 2080 (  pg_type_is_visible		PGNSP PGUID 12 f f t f s 1 16 "26"  pg_type_is_visible - _null_ ));
+DESCR("is type visible in search path?");
+DATA(insert OID = 2081 (  pg_function_is_visible	PGNSP PGUID 12 f f t f s 1 16 "26"  pg_function_is_visible - _null_ ));
+DESCR("is function visible in search path?");
+DATA(insert OID = 2082 (  pg_operator_is_visible	PGNSP PGUID 12 f f t f s 1 16 "26"  pg_operator_is_visible - _null_ ));
+DESCR("is operator visible in search path?");
+DATA(insert OID = 2083 (  pg_opclass_is_visible		PGNSP PGUID 12 f f t f s 1 16 "26"  pg_opclass_is_visible - _null_ ));
+DESCR("is opclass visible in search path?");
+
+
 /* Aggregates (moved here from pg_aggregate for 7.3) */
 
 DATA(insert OID = 2100 (  avg				PGNSP PGUID 12 t f f f i 1 1700 "20"  aggregate_dummy - _null_ ));
@@ -2983,7 +2995,58 @@ DATA(insert OID = 2247 ( fmgr_c_validator	PGNSP PGUID 12 f f t f s 1   26 "23"	f
 DESCR("(internal)");
 DATA(insert OID = 2248 ( fmgr_sql_validator	PGNSP PGUID 12 f f t f s 1   26 "23"	fmgr_sql_validator - _null_ ));
 DESCR("(internal)");
-#define SQLvalidatorId 2248
+
+DATA(insert OID = 2250 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 25 25"  has_database_privilege_name_name - _null_ ));
+DESCR("user privilege on database by username, database name");
+DATA(insert OID = 2251 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25"  has_database_privilege_name_id - _null_ ));
+DESCR("user privilege on database by username, database oid");
+DATA(insert OID = 2252 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25"  has_database_privilege_id_name - _null_ ));
+DESCR("user privilege on database by usesysid, database name");
+DATA(insert OID = 2253 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25"  has_database_privilege_id_id - _null_ ));
+DESCR("user privilege on database by usesysid, database oid");
+DATA(insert OID = 2254 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25"	has_database_privilege_name - _null_ ));
+DESCR("current user privilege on database by database name");
+DATA(insert OID = 2255 (  has_database_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25"	has_database_privilege_id - _null_ ));
+DESCR("current user privilege on database by database oid");
+
+DATA(insert OID = 2256 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 25 25"  has_function_privilege_name_name - _null_ ));
+DESCR("user privilege on function by username, function name");
+DATA(insert OID = 2257 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25"  has_function_privilege_name_id - _null_ ));
+DESCR("user privilege on function by username, function oid");
+DATA(insert OID = 2258 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25"  has_function_privilege_id_name - _null_ ));
+DESCR("user privilege on function by usesysid, function name");
+DATA(insert OID = 2259 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25"  has_function_privilege_id_id - _null_ ));
+DESCR("user privilege on function by usesysid, function oid");
+DATA(insert OID = 2260 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25"	has_function_privilege_name - _null_ ));
+DESCR("current user privilege on function by function name");
+DATA(insert OID = 2261 (  has_function_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25"	has_function_privilege_id - _null_ ));
+DESCR("current user privilege on function by function oid");
+
+DATA(insert OID = 2262 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 25 25"  has_language_privilege_name_name - _null_ ));
+DESCR("user privilege on language by username, language name");
+DATA(insert OID = 2263 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25"  has_language_privilege_name_id - _null_ ));
+DESCR("user privilege on language by username, language oid");
+DATA(insert OID = 2264 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25"  has_language_privilege_id_name - _null_ ));
+DESCR("user privilege on language by usesysid, language name");
+DATA(insert OID = 2265 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25"  has_language_privilege_id_id - _null_ ));
+DESCR("user privilege on language by usesysid, language oid");
+DATA(insert OID = 2266 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25"	has_language_privilege_name - _null_ ));
+DESCR("current user privilege on language by language name");
+DATA(insert OID = 2267 (  has_language_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25"	has_language_privilege_id - _null_ ));
+DESCR("current user privilege on language by language oid");
+
+DATA(insert OID = 2268 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 25 25"  has_schema_privilege_name_name - _null_ ));
+DESCR("user privilege on schema by username, schema name");
+DATA(insert OID = 2269 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16 "19 26 25"  has_schema_privilege_name_id - _null_ ));
+DESCR("user privilege on schema by username, schema oid");
+DATA(insert OID = 2270 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 25 25"  has_schema_privilege_id_name - _null_ ));
+DESCR("user privilege on schema by usesysid, schema name");
+DATA(insert OID = 2271 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 3 16 "23 26 25"  has_schema_privilege_id_id - _null_ ));
+DESCR("user privilege on schema by usesysid, schema oid");
+DATA(insert OID = 2272 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 2 16 "25 25"	has_schema_privilege_name - _null_ ));
+DESCR("current user privilege on schema by schema name");
+DATA(insert OID = 2273 (  has_schema_privilege		   PGNSP PGUID 12 f f t f s 2 16 "26 25"	has_schema_privilege_id - _null_ ));
+DESCR("current user privilege on schema by schema oid");
 
 /*
  * Symbolic values for provolatile column: these indicate whether the result
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index d0cccbda469..89e3f471f7a 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: dbcommands.h,v 1.24 2002/06/20 20:29:49 momjian Exp $
+ * $Id: dbcommands.h,v 1.25 2002/08/09 16:45:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,4 +20,7 @@ extern void createdb(const CreatedbStmt *stmt);
 extern void dropdb(const char *dbname);
 extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt);
 
+extern Oid	get_database_oid(const char *dbname);
+extern Oid	get_database_owner(Oid dbid);
+
 #endif   /* DBCOMMANDS_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index a138e2d2ffa..01d5a4e7306 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.189 2002/08/06 14:11:05 tgl Exp $
+ * $Id: builtins.h,v 1.190 2002/08/09 16:45:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,6 +29,30 @@ 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_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);
+extern Datum has_database_privilege_id_id(PG_FUNCTION_ARGS);
+extern Datum has_database_privilege_name(PG_FUNCTION_ARGS);
+extern Datum has_database_privilege_id(PG_FUNCTION_ARGS);
+extern Datum has_function_privilege_name_name(PG_FUNCTION_ARGS);
+extern Datum has_function_privilege_name_id(PG_FUNCTION_ARGS);
+extern Datum has_function_privilege_id_name(PG_FUNCTION_ARGS);
+extern Datum has_function_privilege_id_id(PG_FUNCTION_ARGS);
+extern Datum has_function_privilege_name(PG_FUNCTION_ARGS);
+extern Datum has_function_privilege_id(PG_FUNCTION_ARGS);
+extern Datum has_language_privilege_name_name(PG_FUNCTION_ARGS);
+extern Datum has_language_privilege_name_id(PG_FUNCTION_ARGS);
+extern Datum has_language_privilege_id_name(PG_FUNCTION_ARGS);
+extern Datum has_language_privilege_id_id(PG_FUNCTION_ARGS);
+extern Datum has_language_privilege_name(PG_FUNCTION_ARGS);
+extern Datum has_language_privilege_id(PG_FUNCTION_ARGS);
+extern Datum has_schema_privilege_name_name(PG_FUNCTION_ARGS);
+extern Datum has_schema_privilege_name_id(PG_FUNCTION_ARGS);
+extern Datum has_schema_privilege_id_name(PG_FUNCTION_ARGS);
+extern Datum has_schema_privilege_id_id(PG_FUNCTION_ARGS);
+extern Datum has_schema_privilege_name(PG_FUNCTION_ARGS);
+extern Datum has_schema_privilege_id(PG_FUNCTION_ARGS);
 
 /* bool.c */
 extern Datum boolin(PG_FUNCTION_ARGS);
-- 
GitLab