From 82a2881c5b230d62bc811a374503625226be02ae Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 30 Apr 2006 21:15:33 +0000
Subject: [PATCH] Code review for GRANT CONNECT patch.  Spell the privilege as
 CONNECT not CONNECTION, fix a number of places that were missed (eg pg_dump
 support), avoid executing an extra search of pg_database during startup.

---
 doc/src/sgml/client-auth.sgml     | 15 +++++--
 doc/src/sgml/ddl.sgml             |  7 +--
 doc/src/sgml/func.sgml            |  3 +-
 doc/src/sgml/ref/grant.sgml       | 18 ++++----
 doc/src/sgml/ref/revoke.sgml      |  4 +-
 doc/src/sgml/user-manag.sgml      |  8 ++--
 src/backend/catalog/aclchk.c      | 42 ++++++++++++------
 src/backend/utils/adt/acl.c       | 12 ++++-
 src/backend/utils/init/postinit.c | 74 +++++++++++++++----------------
 src/bin/pg_dump/dumputils.c       |  3 +-
 src/bin/psql/tab-complete.c       |  5 ++-
 src/include/utils/acl.h           |  8 +++-
 12 files changed, 118 insertions(+), 81 deletions(-)

diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 2185eebeb05..22fe521bfb0 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.88 2006/04/30 02:09:06 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.89 2006/04/30 21:15:32 tgl Exp $ -->
 
 <chapter id="client-authentication">
  <title>Client Authentication</title>
@@ -206,8 +206,6 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
        Multiple user names can be supplied by separating them with commas.
        A separate file containing user names can be specified by preceding the
        file name with <literal>@</>.
-       User and group connectivity can also be restricted by <command>GRANT
-       CONNECTION ON DATABASE</>.
       </para>
      </listitem>
     </varlistentry>
@@ -436,6 +434,17 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
    re-read the file.
   </para>
 
+  <tip>
+   <para>
+    To connect to a particular database, a user must not only pass the
+    <filename>pg_hba.conf</filename> checks, but must have the
+    <literal>CONNECT</> privilege for the database.  If you wish to
+    restrict which users can connect to which databases, it's usually
+    easier to control this by granting/revoking <literal>CONNECT</> privilege
+    than to put the rules into <filename>pg_hba.conf</filename> entries.
+   </para>
+  </tip>
+
   <para>
    Some examples of <filename>pg_hba.conf</filename> entries are shown in
    <xref linkend="example-pg-hba.conf">. See the next section for details on the
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index 77bc1dd4970..a6fb4b3691f 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.56 2006/04/23 03:39:50 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.57 2006/04/30 21:15:32 tgl Exp $ -->
 
 <chapter id="ddl">
  <title>Data Definition</title>
@@ -1343,8 +1343,9 @@ ALTER TABLE products RENAME TO items;
    There are several different privileges: <literal>SELECT</>,
    <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
    <literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
-   <literal>CREATE</>, <literal>TEMPORARY</>, <literal>EXECUTE</>, and
-   <literal>USAGE</>.  The privileges applicable to a particular
+   <literal>CREATE</>, <literal>CONNECT</>, <literal>TEMPORARY</>,
+   <literal>EXECUTE</>, and <literal>USAGE</>.
+   The privileges applicable to a particular
    object vary depending on the object's type (table, function, etc).
    For complete information on the different types of privileges
    supported by <productname>PostgreSQL</productname>, refer to the
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index b53bdca6fc3..1c6738b8cb4 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.315 2006/04/25 00:25:15 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.316 2006/04/30 21:15:32 tgl Exp $ -->
 
  <chapter id="functions">
   <title>Functions and Operators</title>
@@ -9227,6 +9227,7 @@ SELECT has_table_privilege('myschema.mytable', 'select');
     arguments are analogous to <function>has_table_privilege</function>.
     The desired access privilege type must evaluate to
     <literal>CREATE</literal>,
+    <literal>CONNECT</literal>,
     <literal>TEMPORARY</literal>, or
     <literal>TEMP</literal> (which is equivalent to
     <literal>TEMPORARY</literal>).
diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index 03060f97212..c6073dc35e4 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.53 2006/04/30 02:09:06 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.54 2006/04/30 21:15:33 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -30,7 +30,7 @@ GRANT { { USAGE | SELECT | UPDATE }
     ON SEQUENCE <replaceable class="PARAMETER">sequencename</replaceable> [, ...]
     TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
 
-GRANT { { CREATE | TEMPORARY | TEMP | CONNECTION } [,...] | ALL [ PRIVILEGES ] }
+GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
     ON DATABASE <replaceable>dbname</replaceable> [, ...]
     TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
 
@@ -118,7 +118,8 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...]
    Depending on the type of object, the initial default privileges may
    include granting some privileges to <literal>PUBLIC</literal>.
    The default is no public access for tables, schemas, and tablespaces;
-   <literal>TEMP</> table creation privilege for databases;
+   <literal>CONNECT</> privilege and <literal>TEMP</> table creation privilege
+   for databases;
    <literal>EXECUTE</> privilege for functions; and
    <literal>USAGE</> privilege for languages.
    The object owner may of course revoke these privileges.  (For maximum
@@ -230,13 +231,12 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...]
     </varlistentry>
 
     <varlistentry>
-     <term>CONNECTION</term>
+     <term>CONNECT</term>
      <listitem>
       <para>
-       Allows the ability to connect to the specified database.
-       By default, Grant permissions allow users to connect to any database,
-       though <filename>pg_hba.conf</> can add additional connection
-       restrictions.
+       Allows the user to connect to the specified database.  This
+       privilege is checked at connection startup (in addition to checking
+       any restrictions imposed by <filename>pg_hba.conf</>).
       </para>
      </listitem>
     </varlistentry>
@@ -429,7 +429,7 @@ GRANT <replaceable class="PARAMETER">role</replaceable> [, ...]
                   X -- EXECUTE
                   U -- USAGE
                   C -- CREATE
-                  c -- CONNECTION
+                  c -- CONNECT
                   T -- TEMPORARY
             arwdRxt -- ALL PRIVILEGES (for tables)
                   * -- grant option for preceding privilege
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index 034b946111c..bccb8010b5f 100644
--- a/doc/src/sgml/ref/revoke.sgml
+++ b/doc/src/sgml/ref/revoke.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.37 2006/04/30 02:09:06 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.38 2006/04/30 21:15:33 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -35,7 +35,7 @@ REVOKE [ GRANT OPTION FOR ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
-    { { CREATE | TEMPORARY | TEMP | CONNECTION } [,...] | ALL [ PRIVILEGES ] }
+    { { CREATE | CONNECT | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
     ON DATABASE <replaceable>dbname</replaceable> [, ...]
     FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
     [ CASCADE | RESTRICT ]
diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml
index d05a9d3b047..41e60200919 100644
--- a/doc/src/sgml/user-manag.sgml
+++ b/doc/src/sgml/user-manag.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/user-manag.sgml,v 1.34 2006/03/10 19:10:49 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/user-manag.sgml,v 1.35 2006/04/30 21:15:32 tgl Exp $ -->
 
 <chapter id="user-manag">
  <title>Database Roles and Privileges</title>
@@ -294,9 +294,9 @@ ALTER ROLE myname SET enable_indexscan TO off;
    There are several different kinds of privilege: <literal>SELECT</>,
    <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
    <literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
-   <literal>CREATE</>, <literal>TEMPORARY</>, <literal>EXECUTE</>,
-   and <literal>USAGE</>. For more
-   information on the different types of privileges supported by
+   <literal>CREATE</>, <literal>CONNECT</>, <literal>TEMPORARY</>,
+   <literal>EXECUTE</>, and <literal>USAGE</>.
+   For more information on the different types of privileges supported by
    <productname>PostgreSQL</productname>, see the
    <xref linkend="sql-grant" endterm="sql-grant-title"> reference page.
   </para>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 3b9701db077..a74c28e5b3d 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.126 2006/04/30 02:09:07 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.127 2006/04/30 21:15:33 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -1368,7 +1368,7 @@ string_to_privilege(const char *privname)
 		return ACL_CREATE_TEMP;
 	if (strcmp(privname, "temp") == 0)
 		return ACL_CREATE_TEMP;
-	if (strcmp(privname, "connection") == 0)
+	if (strcmp(privname, "connect") == 0)
 		return ACL_CONNECT;
 	ereport(ERROR,
 			(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1404,7 +1404,7 @@ privilege_to_string(AclMode privilege)
 		case ACL_CREATE_TEMP:
 			return "TEMP";
 		case ACL_CONNECT:
-			return "CONNECTION";
+			return "CONNECT";
 		default:
 			elog(ERROR, "unrecognized privilege: %d", (int) privilege);
 	}
@@ -1661,10 +1661,6 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
 	ScanKeyData entry[1];
 	SysScanDesc scan;
 	HeapTuple	tuple;
-	Datum		aclDatum;
-	bool		isNull;
-	Acl		   *acl;
-	Oid			ownerId;
 
 	/* Superusers bypass all permission checking. */
 	if (superuser_arg(roleid))
@@ -1688,10 +1684,33 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
 				(errcode(ERRCODE_UNDEFINED_DATABASE),
 				 errmsg("database with OID %u does not exist", db_oid)));
 
-	ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
+	result = pg_database_tuple_aclmask(tuple, RelationGetDescr(pg_database),
+									   roleid, mask, how);
+
+	systable_endscan(scan);
+	heap_close(pg_database, AccessShareLock);
+
+	return result;
+}
+
+/*
+ * This is split out so that ReverifyMyDatabase can perform an ACL check
+ * without a whole extra search of pg_database
+ */
+AclMode
+pg_database_tuple_aclmask(HeapTuple db_tuple, TupleDesc tupdesc,
+						  Oid roleid, AclMode mask, AclMaskHow how)
+{
+	AclMode		result;
+	Datum		aclDatum;
+	bool		isNull;
+	Acl		   *acl;
+	Oid			ownerId;
+
+	ownerId = ((Form_pg_database) GETSTRUCT(db_tuple))->datdba;
 
-	aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
-							RelationGetDescr(pg_database), &isNull);
+	aclDatum = heap_getattr(db_tuple, Anum_pg_database_datacl,
+							tupdesc, &isNull);
 
 	if (isNull)
 	{
@@ -1711,9 +1730,6 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
 	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 		pfree(acl);
 
-	systable_endscan(scan);
-	heap_close(pg_database, AccessShareLock);
-
 	return result;
 }
 
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 4f64104ad3d..0fa61196ea7 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.132 2006/04/30 02:09:07 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.133 2006/04/30 21:15:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -553,7 +553,8 @@ acldefault(GrantObjectType objtype, Oid ownerId)
 			owner_default = ACL_ALL_RIGHTS_SEQUENCE;
 			break;
 		case ACL_OBJECT_DATABASE:
-			world_default = ACL_CREATE_TEMP | ACL_CONNECT;	/* not NO_RIGHTS! */
+			/* for backwards compatibility, grant some rights by default */
+			world_default = ACL_CREATE_TEMP | ACL_CONNECT;
 			owner_default = ACL_ALL_RIGHTS_DATABASE;
 			break;
 		case ACL_OBJECT_FUNCTION:
@@ -1341,6 +1342,8 @@ convert_priv_string(text *priv_type_text)
 		return ACL_CREATE_TEMP;
 	if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
 		return ACL_CREATE_TEMP;
+	if (pg_strcasecmp(priv_type, "CONNECT") == 0)
+		return ACL_CONNECT;
 
 	ereport(ERROR,
 			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -1778,6 +1781,11 @@ convert_database_priv_string(text *priv_type_text)
 	if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
 		return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
 
+	if (pg_strcasecmp(priv_type, "CONNECT") == 0)
+		return ACL_CONNECT;
+	if (pg_strcasecmp(priv_type, "CONNECT WITH GRANT OPTION") == 0)
+		return ACL_GRANT_OPTION_FOR(ACL_CONNECT);
+
 	ereport(ERROR,
 			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 			 errmsg("unrecognized privilege type: \"%s\"", priv_type)));
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 63135d2d1e3..e89df5bb3af 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.163 2006/04/30 02:09:07 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.164 2006/04/30 21:15:33 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -51,7 +51,7 @@
 
 
 static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);
-static void ReverifyMyDatabase(const char *name, const char *user_name);
+static void ReverifyMyDatabase(const char *name, bool am_superuser);
 static void InitCommunication(void);
 static void ShutdownPostgres(int code, Datum arg);
 static bool ThereIsAtLeastOneRole(void);
@@ -127,12 +127,11 @@ FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace)
  * of pg_database.
  *
  * To avoid having to read pg_database more times than necessary
- * during session startup, this place is also fitting to set up any
- * database-specific configuration variables.
+ * during session startup, this place is also fitting to check CONNECT
+ * privilege and set up any database-specific configuration variables.
  */
- 
 static void
-ReverifyMyDatabase(const char *name, const char *user_name)
+ReverifyMyDatabase(const char *name, bool am_superuser)
 {
 	Relation	pgdbrel;
 	SysScanDesc pgdbscan;
@@ -195,6 +194,22 @@ ReverifyMyDatabase(const char *name, const char *user_name)
 			 errmsg("database \"%s\" is not currently accepting connections",
 					name)));
 
+		/*
+		 * Check privilege to connect to the database.  To avoid making
+		 * a whole extra search of pg_database here, we don't go through
+		 * pg_database_aclcheck, but instead use a lower-level routine
+		 * that we can pass the pg_database tuple to.
+		 */
+		if (!am_superuser &&
+			pg_database_tuple_aclmask(tup, RelationGetDescr(pgdbrel),
+									  GetUserId(),
+									  ACL_CONNECT, ACLMASK_ANY) == 0)
+			ereport(FATAL,
+					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+					 errmsg("permission denied for database %s",
+							NameStr(dbform->datname)),
+					 errdetail("User does not have CONNECT privilege.")));
+
 		/*
 		 * Check connection limit for this database.
 		 *
@@ -206,29 +221,12 @@ ReverifyMyDatabase(const char *name, const char *user_name)
 		 * just document that the connection limit is approximate.
 		 */
 		if (dbform->datconnlimit >= 0 &&
-			!superuser() &&
+			!am_superuser &&
 			CountDBBackends(MyDatabaseId) > dbform->datconnlimit)
 			ereport(FATAL,
 					(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
 					 errmsg("too many connections for database \"%s\"",
 							name)));
-
-		/*
-		 * Checking for privilege to connect to the database
-		 * We want to bypass the test if we are running in bootstrap mode
-		 */
-		if (!IsBootstrapProcessingMode())
-		{
-				if(pg_database_aclcheck(MyDatabaseId,GetUserId()
-					,ACL_CONNECT) != ACLCHECK_OK )
-				{
-					ereport(FATAL,
-                			(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                 				errmsg("couldn't connect to database %s", NameStr(dbform->datname)),
-                 				errdetail("User %s doesn't have the CONNECTION privilege for database %s.",
-                                user_name, NameStr(dbform->datname))));				
-				}
-		}
 	}
 
 	/*
@@ -476,15 +474,20 @@ InitPostgres(const char *dbname, const char *username)
 	RelationCacheInitializePhase2();
 
 	/*
-	 * Figure out our postgres user id.  In standalone mode and in the
-	 * autovacuum process, we use a fixed id, otherwise we figure it out from
-	 * the authenticated user name.
+	 * Figure out our postgres user id, and see if we are a superuser.
+	 *
+	 * In standalone mode and in the autovacuum process, we use a fixed id,
+	 * otherwise we figure it out from the authenticated user name.
 	 */
 	if (bootstrap || autovacuum)
+	{
 		InitializeSessionUserIdStandalone();
+		am_superuser = true;
+	}
 	else if (!IsUnderPostmaster)
 	{
 		InitializeSessionUserIdStandalone();
+		am_superuser = true;
 		if (!ThereIsAtLeastOneRole())
 			ereport(WARNING,
 					(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -496,8 +499,12 @@ InitPostgres(const char *dbname, const char *username)
 	{
 		/* normal multiuser case */
 		InitializeSessionUserId(username);
+		am_superuser = superuser();
 	}
 
+	/* set up ACL framework (so ReverifyMyDatabase can check permissions) */
+	initialize_acl();
+
 	/*
 	 * Unless we are bootstrapping, double-check that InitMyDatabaseInfo() got
 	 * a correct result.  We can't do this until all the database-access
@@ -505,7 +512,7 @@ InitPostgres(const char *dbname, const char *username)
 	 * superuser, so the above stuff has to happen first.)
 	 */
 	if (!bootstrap)
-		ReverifyMyDatabase(dbname,username);
+		ReverifyMyDatabase(dbname, am_superuser);
 
 	/*
 	 * Final phase of relation cache startup: write a new cache file if
@@ -514,14 +521,6 @@ InitPostgres(const char *dbname, const char *username)
 	 */
 	RelationCacheInitializePhase3();
 
-	/*
-	 * Check if user is a superuser.
-	 */
-	if (bootstrap || autovacuum)
-		am_superuser = true;
-	else
-		am_superuser = superuser();
-
 	/*
 	 * Check a normal user hasn't connected to a superuser reserved slot.
 	 */
@@ -540,9 +539,6 @@ InitPostgres(const char *dbname, const char *username)
 	/* set default namespace search path */
 	InitializeSearchPath();
 
-	/* set up ACL framework (currently just sets RolMemCache callback) */
-	initialize_acl();
-
 	/* initialize client encoding */
 	InitializeClientEncoding();
 
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 77e6d43fe02..86c930b8add 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.26 2006/03/05 15:58:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.27 2006/04/30 21:15:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -605,6 +605,7 @@ do { \
 	else if (strcmp(type, "DATABASE") == 0)
 	{
 		CONVERT_PRIV('C', "CREATE");
+		CONVERT_PRIV('c', "CONNECT");
 		CONVERT_PRIV('T', "TEMPORARY");
 	}
 	else if (strcmp(type, "TABLESPACE") == 0)
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index a90d7eb72cf..ad8f0f841b2 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.150 2006/04/02 09:02:41 alvherre Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.151 2006/04/30 21:15:33 tgl Exp $
  */
 
 /*----------------------------------------------------------------------
@@ -1373,7 +1373,8 @@ psql_completion(char *text, int start, int end)
 	{
 		static const char *const list_privileg[] =
 		{"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
-		"TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
+		 "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
+		 "ALL", NULL};
 
 		COMPLETE_WITH_LIST(list_privileg);
 	}
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index c329b6aab81..7651fba290c 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.94 2006/04/30 02:09:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.95 2006/04/30 21:15:33 tgl Exp $
  *
  * NOTES
  *	  An ACL array is simply an array of AclItems, representing the union
@@ -24,6 +24,8 @@
 #ifndef ACL_H
 #define ACL_H
 
+#include "access/htup.h"
+#include "access/tupdesc.h"
 #include "nodes/parsenodes.h"
 #include "utils/array.h"
 
@@ -145,7 +147,7 @@ typedef ArrayType Acl;
  */
 #define ACL_ALL_RIGHTS_RELATION		(ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER)
 #define ACL_ALL_RIGHTS_SEQUENCE		(ACL_USAGE|ACL_SELECT|ACL_UPDATE)
-#define ACL_ALL_RIGHTS_DATABASE		(ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT )
+#define ACL_ALL_RIGHTS_DATABASE		(ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT)
 #define ACL_ALL_RIGHTS_FUNCTION		(ACL_EXECUTE)
 #define ACL_ALL_RIGHTS_LANGUAGE		(ACL_USAGE)
 #define ACL_ALL_RIGHTS_NAMESPACE	(ACL_USAGE|ACL_CREATE)
@@ -250,6 +252,8 @@ extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
 				 AclMode mask, AclMaskHow how);
 extern AclMode pg_database_aclmask(Oid db_oid, Oid roleid,
 					AclMode mask, AclMaskHow how);
+extern AclMode pg_database_tuple_aclmask(HeapTuple db_tuple, TupleDesc tupdesc,
+					Oid roleid, AclMode mask, AclMaskHow how);
 extern AclMode pg_proc_aclmask(Oid proc_oid, Oid roleid,
 				AclMode mask, AclMaskHow how);
 extern AclMode pg_language_aclmask(Oid lang_oid, Oid roleid,
-- 
GitLab