From 916710fc914b94995438fee36f4480b17ce420ed Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Sun, 19 Jul 1998 05:24:51 +0000
Subject: [PATCH] pg_dump -z has gotten rather thoroughly broken in the last
 couple of days --- it was emitting stuff like 	REVOKE ALL on 'table' from
 PUBLIC; GRANT ALL on "table" to 	"Public"; neither of which work. 
 While I was at it I cleaned up a few other things:

* \connect commands are issued only in -z mode.  In this way,
reloading a pg_dump script made without -z will generate a simple
database wholly owned by the invoking user, rather than a mishmash
of tables owned by various people but lacking in access rights.
(Analogy: cp versus cp -p.)

* \connect commands are issued just before COPY FROM stdin commands;
without this, reloading a database containing non-world-writable
tables tended to fail because the COPY was not necessarily attempted
as the table owner.

* Redundant \connect commands are suppressed (each one costs a
backend launch, so...).

* Man page updated (-z wasn't ever documented).

The first two items were discussed in a pgsql-hackers thread around
6 May 98 ("An item for the TODO list: pg_dump and multiple table
owners") but no one had bothered to deal with 'em yet.

			regards, tom lane
---
 src/bin/pg_dump/pg_dump.c | 84 +++++++++++++++++++++++++++------------
 src/man/pg_dump.1         | 19 ++++++---
 2 files changed, 71 insertions(+), 32 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 45e9a8135df..ad68b9fcde7 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -21,7 +21,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.77 1998/07/08 14:33:19 thomas Exp $
+ *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.78 1998/07/19 05:24:49 momjian Exp $
  *
  * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
  *
@@ -95,6 +95,7 @@ static void setMaxOid(FILE *fout);
 static char *AddAcl(char *s, const char *add);
 static char *GetPrivledges(char *s);
 static ACL *ParseACL(const char *acls, int *count);
+static void becomeUser(FILE *fout, const char *username);
 
 extern char *optarg;
 extern int	optind,
@@ -110,6 +111,7 @@ int			dumpData;			/* dump data using proper insert strings */
 int			attrNames;			/* put attr names into insert strings */
 int			schemaOnly;
 int			dataOnly;
+int			aclsOption;
 
 char		g_opaque_type[10];	/* name for the opaque type */
 
@@ -141,12 +143,12 @@ usage(const char *progname)
 			"\t -s          \t\t dump out only the schema, no data\n");
 	fprintf(stderr,
 			"\t -t table    \t\t dump for this table only\n");
+	fprintf(stderr,
+			"\t -u          \t\t use password authentication\n");
 	fprintf(stderr,
 			"\t -v          \t\t verbose\n");
 	fprintf(stderr,
 			"\t -z          \t\t dump ACLs (grant/revoke)\n");
-	fprintf(stderr,
-			"\t -u          \t\t use password authentication\n");
 	fprintf(stderr,
 			"\nIf dbname is not supplied, then the DATABASE environment "
 			"variable value is used.\n");
@@ -435,7 +437,7 @@ dumpClasses(const TableInfo tblinfo[], const int numTables, FILE *fout,
 				if (g_verbose)
 					fprintf(stderr, "%s dumping out schema of sequence '%s' %s\n",
 					 g_comment_start, tblinfo[i].relname, g_comment_end);
-				fprintf(fout, "\\connect - %s\n", tblinfo[i].usename);
+				becomeUser(fout, tblinfo[i].usename);
 				dumpSequence(fout, tblinfo[i]);
 			}
 		}
@@ -458,6 +460,8 @@ dumpClasses(const TableInfo tblinfo[], const int numTables, FILE *fout,
 				fprintf(stderr, "%s dumping out the contents of Table '%s' %s\n",
 						g_comment_start, classname, g_comment_end);
 
+			becomeUser(fout, tblinfo[i].usename);
+
 			if (!dumpData)
 				dumpClasses_nodumpData(fout, classname, oids);
 			else
@@ -534,8 +538,7 @@ main(int argc, char **argv)
 	const char *pghost = NULL;
 	const char *pgport = NULL;
 	char	   *tablename = NULL;
-	int			oids = 0,
-				acls = 0;
+	int			oids = 0;
 	TableInfo  *tblinfo;
 	int			numTables;
 	char		connect_string[512] = "";
@@ -598,8 +601,8 @@ main(int argc, char **argv)
 			case 'v':			/* verbose */
 				g_verbose = true;
 				break;
-			case 'z':			/* Dump oids */
-				acls = 1;
+			case 'z':			/* Dump ACLs and table ownership info */
+				aclsOption = 1;
 				break;
 			case 'u':
 				use_password = 1;
@@ -657,11 +660,11 @@ main(int argc, char **argv)
 		strcat(connect_string, tmp_string);
 		sprintf(tmp_string, "password=%s ", password);
 		strcat(connect_string, tmp_string);
-		bzero(tmp_string, sizeof(tmp_string));
-		bzero(password, sizeof(password));
+		MemSet(tmp_string, 0, sizeof(tmp_string));
+		MemSet(password, 0, sizeof(password));
 	}
 	g_conn = PQconnectdb(connect_string);
-	bzero(connect_string, sizeof(connect_string));
+	MemSet(connect_string, 0, sizeof(connect_string));
 	/* check to see that the backend connection was successfully made */
 	if (PQstatus(g_conn) == CONNECTION_BAD)
 	{
@@ -679,10 +682,10 @@ main(int argc, char **argv)
 		if (g_verbose)
 			fprintf(stderr, "%s last builtin oid is %d %s\n",
 					g_comment_start, g_last_builtin_oid, g_comment_end);
-		tblinfo = dumpSchema(g_fout, &numTables, tablename, acls);
+		tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsOption);
 	}
 	else
-		tblinfo = dumpSchema(NULL, &numTables, tablename, acls);
+		tblinfo = dumpSchema(NULL, &numTables, tablename, aclsOption);
 
 	if (!schemaOnly)
 		dumpClasses(tblinfo, numTables, g_fout, tablename, oids);
@@ -1961,7 +1964,7 @@ dumpTypes(FILE *fout, FuncInfo *finfo, int numFuncs,
 		if (funcInd != -1)
 			dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
 
-		fprintf(fout, "\\connect - %s\n", tinfo[i].usename);
+		becomeUser(fout, tinfo[i].usename);
 
 		sprintf(q,
 				"CREATE TYPE \"%s\" "
@@ -2028,7 +2031,7 @@ dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
 	else
 		finfo[i].dumped = 1;
 
-	fprintf(fout, "\\connect - %s\n", finfo[i].usename);
+	becomeUser(fout, finfo[i].usename);
 
 	sprintf(q, "CREATE FUNCTION \"%s\" (", finfo[i].proname);
 	for (j = 0; j < finfo[i].nargs; j++)
@@ -2143,7 +2146,7 @@ dumpOprs(FILE *fout, OprInfo *oprinfo, int numOperators,
 									 oprinfo[i].oprlsortop));
 		}
 
-		fprintf(fout, "\\connect - %s\n", oprinfo[i].usename);
+		becomeUser(fout, oprinfo[i].usename);
 
 		sprintf(q,
 				"CREATE OPERATOR %s "
@@ -2238,7 +2241,7 @@ dumpAggs(FILE *fout, AggInfo *agginfo, int numAggs,
 		else
 			comma2[0] = '\0';
 
-		fprintf(fout, "\\connect - %s\n", agginfo[i].usename);
+		becomeUser(fout, agginfo[i].usename);
 
 		sprintf(q, "CREATE AGGREGATE %s ( %s %s%s %s%s %s );\n",
 				agginfo[i].aggname,
@@ -2349,7 +2352,7 @@ ParseACL(const char *acls, int *count)
 	s = strdup(acls);
 
 	/* Setup up public */
-	ParsedAcl[0].user = strdup("Public");
+	ParsedAcl[0].user = NULL;	/* indicates PUBLIC */
 	tok = strtok(s, ",");
 	ParsedAcl[0].privledges = GetPrivledges(strchr(tok, '='));
 
@@ -2397,16 +2400,23 @@ dumpACL(FILE *fout, TableInfo tbinfo)
 
 	/* Revoke Default permissions for PUBLIC */
 	fprintf(fout,
-			"REVOKE ALL on '%s' from PUBLIC;\n",
+			"REVOKE ALL on \"%s\" from PUBLIC;\n",
 			tbinfo.relname);
 
 	for (k = 0; k < l; k++)
 	{
 		if (ACLlist[k].privledges != (char *) NULL)
-			fprintf(fout,
-					"GRANT %s on \"%s\" to \"%s\";\n",
-					ACLlist[k].privledges, tbinfo.relname,
-					ACLlist[k].user);
+		{
+			if (ACLlist[k].user == (char *) NULL)
+				fprintf(fout,
+						"GRANT %s on \"%s\" to PUBLIC;\n",
+						ACLlist[k].privledges, tbinfo.relname);
+			else
+				fprintf(fout,
+						"GRANT %s on \"%s\" to \"%s\";\n",
+						ACLlist[k].privledges, tbinfo.relname,
+						ACLlist[k].user);
+		}
 	}
 }
 
@@ -2437,7 +2447,7 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
 			continue;
 		if (!tablename || (!strcmp(tblinfo[i].relname, tablename)))
 		{
-			fprintf(fout, "\\connect - %s\n", tblinfo[i].usename);
+			becomeUser(fout, tblinfo[i].usename);
 			dumpSequence(fout, tblinfo[i]);
 			if (acls)
 				dumpACL(fout, tblinfo[i]);
@@ -2459,7 +2469,7 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
 			parentRels = tblinfo[i].parentRels;
 			numParents = tblinfo[i].numParents;
 
-			fprintf(fout, "\\connect - %s\n", tblinfo[i].usename);
+			becomeUser(fout, tblinfo[i].usename);
 
 			sprintf(q, "CREATE TABLE \"%s\" (", fmtId(tblinfo[i].relname));
 			actual_atts = 0;
@@ -2954,8 +2964,30 @@ dumpTriggers(FILE *fout, const char *tablename,
 			continue;
 		for (j = 0; j < tblinfo[i].ntrig; j++)
 		{
-			fprintf(fout, "\\connect - %s\n", tblinfo[i].usename);
+			becomeUser(fout, tblinfo[i].usename);
 			fputs(tblinfo[i].triggers[j], fout);
 		}
 	}
 }
+
+
+/* Issue a psql \connect command to become the specified user.
+ * We want to do this only if we are dumping ACLs,
+ * and only if the new username is different from the last one
+ * (to avoid the overhead of useless backend launches).
+ */
+
+static void becomeUser(FILE *fout, const char *username)
+{
+	static const char *lastusername = "";
+
+	if (! aclsOption)
+		return;
+
+	if (strcmp(lastusername, username) == 0)
+		return;
+
+	fprintf(fout, "\\connect - %s\n", username);
+
+	lastusername = username;
+}
diff --git a/src/man/pg_dump.1 b/src/man/pg_dump.1
index c34fe322a7d..67f04e67c0a 100644
--- a/src/man/pg_dump.1
+++ b/src/man/pg_dump.1
@@ -1,7 +1,7 @@
 .\" This is -*-nroff-*-
 .\" XXX standard disclaimer belongs here....
-.\" $Header: /cvsroot/pgsql/src/man/Attic/pg_dump.1,v 1.11 1998/06/24 13:21:28 momjian Exp $
-.TH PG_DUMP UNIX 1/20/96 PostgreSQL PostgreSQL
+.\" $Header: /cvsroot/pgsql/src/man/Attic/pg_dump.1,v 1.12 1998/07/19 05:24:51 momjian Exp $
+.TH PG_DUMP UNIX 7/15/98 PostgreSQL PostgreSQL
 .SH NAME
 pg_dump - dumps out a Postgres database into a script file
 .SH SYNOPSIS
@@ -36,23 +36,27 @@ port]
 .BR "-t"
 table]
 [\c
+.BR "-u"
+]
+[\c
 .BR "-v"
 ]
 [\c
-.BR "-u"]
+.BR "-z"
+]
 dbname
 .in -5n
 .SH DESCRIPTION
 .IR "pg_dump"
 is a utility for dumping out a 
 Postgres database into a script file containing query commands.  The script
-files are in a ASCII format and can be used to reconstruct the database,
+files are in ASCII format and can be used to reconstruct the database,
 even on other machines and other architectures.  
 .IR "pg_dump" 
 will produce the queries necessary to re-generate all
 user-defined types, functions, tables, indices, aggregates, and
 operators.  In addition, all the data is copied out in ASCII format so
-that it can be readily copied in again, as well, as imported into tools
+that it can be readily copied in again, as well as imported into tools
 for textual editing.
 .PP
 .IR "pg_dump" 
@@ -92,10 +96,13 @@ Dump out only the schema, no data
 Dump for this table only
 .TP
 .BR "-u"
-Use password authentication. Prompts for username and password.
+Use password authentication. Prompts for username and password
 .TP
 .BR "-v" ""
 Specifies verbose mode
+.TP
+.BR "-z" ""
+Include ACLs (grant/revoke commands) and table ownership information
 .PP
 If dbname is not supplied, then the DATABASE environment variable value is used.
 .SH "CAVEATS AND LIMITATIONS"
-- 
GitLab