From 7af5ea736f680109de569b00f2c36ea8e0211aea Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Tue, 27 Aug 2002 18:57:26 +0000
Subject: [PATCH] Reimplement pg_dumpall in C.  Currently no change in
 functionality, except that it's more robust, reconnects less often, and is
 NLS'ed.

---
 doc/src/sgml/ref/pg_dump.sgml        |  26 +-
 doc/src/sgml/ref/pg_dumpall.sgml     | 225 ++++++----
 src/bin/pg_dump/Makefile             |  21 +-
 src/bin/pg_dump/dumputils.c          | 131 ++++++
 src/bin/pg_dump/dumputils.h          |  26 ++
 src/bin/pg_dump/nls.mk               |   6 +-
 src/bin/pg_dump/pg_backup.h          |   7 +-
 src/bin/pg_dump/pg_backup_archiver.c | 117 +-----
 src/bin/pg_dump/pg_backup_db.c       |   3 +-
 src/bin/pg_dump/pg_dump.c            |  17 +-
 src/bin/pg_dump/pg_dumpall.c         | 604 +++++++++++++++++++++++++++
 src/bin/pg_dump/pg_dumpall.sh        | 289 -------------
 src/bin/pg_dump/pg_restore.c         |   3 +-
 13 files changed, 954 insertions(+), 521 deletions(-)
 create mode 100644 src/bin/pg_dump/dumputils.c
 create mode 100644 src/bin/pg_dump/dumputils.h
 create mode 100644 src/bin/pg_dump/pg_dumpall.c
 delete mode 100644 src/bin/pg_dump/pg_dumpall.sh

diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml
index e96a443e0c3..fbfdcb3c2a4 100644
--- a/doc/src/sgml/ref/pg_dump.sgml
+++ b/doc/src/sgml/ref/pg_dump.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.48 2002/08/18 09:36:25 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_dump.sgml,v 1.49 2002/08/27 18:57:26 petere Exp $
 PostgreSQL documentation
 -->
 
@@ -112,13 +112,13 @@ PostgreSQL documentation
    does not block other users accessing the database (readers or
    writers).
   </para>
+ </refsect1>
 
-  <refsect2 id="pg-dump-options">
-   <title>Options</title>
+ <refsect1 id="pg-dump-options">
+  <title>Options</title>
 
-   <para>
-    <command>pg_dump</command> accepts the following command
-    line arguments.  (Long option forms are only available on some platforms.)
+  <para>
+   The following command-line options are used to control the output format.
 
     <variablelist>
      <varlistentry>
@@ -408,7 +408,9 @@ PostgreSQL documentation
       <term><option>--verbose</></term>
       <listitem>
        <para>
-	Specifies verbose mode.
+	Specifies verbose mode.  This will cause
+	<application>pg_dump</application> to print progress messages
+	to standard error.
        </para>
       </listitem>
      </varlistentry>
@@ -499,13 +501,11 @@ PostgreSQL documentation
        </para>
       </listitem>
      </varlistentry>
-
-
     </variablelist>
    </para>
+
    <para>
-    <command>pg_dump</command> also accepts 
-    the following command line arguments for connection parameters:
+    The following command-line options control the database connection parameters.
 
     <variablelist>
      <varlistentry>
@@ -555,8 +555,10 @@ PostgreSQL documentation
      </varlistentry>
     </variablelist>
    </para>
-  </refsect2>
 
+  <para>
+   Long option forms are only available on some platforms.
+  </para>
  </refsect1>
 
  <refsect1>
diff --git a/doc/src/sgml/ref/pg_dumpall.sgml b/doc/src/sgml/ref/pg_dumpall.sgml
index 9f46b43a82c..869f480a341 100644
--- a/doc/src/sgml/ref/pg_dumpall.sgml
+++ b/doc/src/sgml/ref/pg_dumpall.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_dumpall.sgml,v 1.31 2002/08/27 03:55:17 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/pg_dumpall.sgml,v 1.32 2002/08/27 18:57:26 petere Exp $
 PostgreSQL documentation
 -->
 
@@ -12,18 +12,13 @@ PostgreSQL documentation
 
  <refnamediv>
   <refname>pg_dumpall</refname>
-  <refpurpose>extract all <productname>PostgreSQL</productname> databases into a script file</refpurpose>
+  <refpurpose>extract a <productname>PostgreSQL</productname> database cluster into a script file</refpurpose>
  </refnamediv>
 
  <refsynopsisdiv>
   <cmdsynopsis>
    <command>pg_dumpall</command>
-   <group><arg>-c</arg><arg>--clean</arg></group>
-   <group><arg>-g</arg><arg>--globals-only</arg></group>
-   <arg>-h <replaceable>host</replaceable></arg>
-   <arg>-p <replaceable>port</replaceable></arg>
-   <arg>-U <replaceable>username</replaceable></arg>
-   <arg>-W</arg>
+   <arg rep="repeat"><replaceable>options</replaceable></arg>
   </cmdsynopsis>
  </refsynopsisdiv>
 
@@ -66,97 +61,161 @@ PostgreSQL documentation
    The SQL script will be written to the standard output.  Shell
    operators should be used to redirect it into a file.
   </para>
-
-
-  <para>
-  <application>pg_dumpall</application> will need to connect several times to the
-  <productname>PostgreSQL</productname> server, asking for the password each
-  time. It will probably be very convenient to have a PGPASSWORDFILE in that case.
-  </para>
-
  </refsect1>
 
  <refsect1>
   <title>Options</title>
 
-  <para>
-   <application>pg_dumpall</application> accepts the following
-   command line arguments:
+   <para>
+    The following command-line options are used to control the output format.
 
-   <variablelist>
-    <varlistentry>
-     <term>-c, --clean</term>
-     <listitem>
-      <para>
+    <variablelist>
+     <varlistentry>
+      <term>-c, --clean</term>
+      <listitem>
+       <para>
 	Include SQL commands to clean (drop) database objects before
 	recreating them.  (This option is fairly useless, since the
 	output script expects to create the databases themselves;
 	they would always be empty upon creation.)
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term>-g, --globals-only</term>
-     <listitem>
-      <para>
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><option>-d</option></term>
+      <term><option>--inserts</option></term>
+      <listitem>
+       <para>
+	Dump data as <command>INSERT</command> commands (rather
+	than <command>COPY</command>). This will make restoration very
+	slow, but it makes the output more portable to other RDBMS
+	packages.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><option>-D</option></term>
+      <term><option>--column-inserts</option></term>
+      <term><option>--attribute-inserts</option></term>
+      <listitem>
+       <para>
+	Dump data as <command>INSERT</command> commands with explicit
+	column names (<literal>INSERT INTO
+	<replaceable>table</replaceable>
+	(<replaceable>column</replaceable>, ...) VALUES
+	...</literal>).  This will make restoration very slow,
+	but it is necessary if you desire to rearrange column ordering.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term>-g, --globals-only</term>
+      <listitem>
+       <para>
 	Only dump global objects (users and groups), no databases.
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term>-h <replaceable>host</replaceable></term>
-     <listitem>
-      <para>
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><option>-i</></term>
+      <term><option>--ignore-version</></term>
+      <listitem>
+       <para>
+        Ignore version mismatch between
+        <application>pg_dumpall</application> and the database server.
+        Since <application>pg_dumpall</application> knows a great deal
+        about system catalogs, any given version of
+        <application>pg_dumpall</application> is only intended to work
+        with the corresponding release of the database server.  Use
+        this option if you need to override the version check (and if
+        <application>pg_dumpall</application> then fails, don't say
+        you weren't warned).
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><option>-o</></term>
+      <term><option>--oids</></term>
+      <listitem>
+       <para>
+	Dump object identifiers (<acronym>OID</acronym>s) for every
+	table.  Use this option if your application references the OID
+	columns in some way (e.g., in a foreign key constraint).
+	Otherwise, this option should not be used.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><option>-v</></term>
+      <term><option>--verbose</></term>
+      <listitem>
+       <para>
+	Specifies verbose mode.  This will cause
+	<application>pg_dumpall</application> to print progress
+	messages to standard error.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+
+  <para>
+   The following command-line options control the database connection parameters.
+
+   <variablelist>
+     <varlistentry>
+      <term>-h <replaceable>host</replaceable></term>
+      <listitem>
+       <para>
 	Specifies the host name of the machine on which the database
 	server is running.  If host begins with a slash, it is used as
 	the directory for the Unix domain socket.  The default is
 	taken from the <envar>PGHOST</envar> environment variable, if
 	set, else a Unix domain socket connection is attempted.
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term>-p <replaceable>port</replaceable></term>
-     <listitem>
-      <para>
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term>-p <replaceable>port</replaceable></term>
+      <listitem>
+       <para>
         The port number on which the server is listening.  Defaults to
         the <envar>PGPORT</envar> environment variable, if set, or a
         compiled-in default.
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term>-U <replaceable>username</replaceable></term>
-     <listitem>
-      <para>
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term>-U <replaceable>username</replaceable></term>
+      <listitem>
+       <para>
         Connect as the given user.
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term>-W</term>
-     <listitem>
-      <para>
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term>-W</term>
+      <listitem>
+       <para>
         Force a password prompt.  This should happen automatically if
         the server requires password authentication.
-      </para>
-     </listitem>
-    </varlistentry>
+       </para>
+      </listitem>
+     </varlistentry>
    </variablelist>
   </para>
 
   <para>
-    Any other command line parameters are passed to the underlying
-    <xref linkend="app-pgdump">
-    calls.  This is useful to control some aspects of the output
-    format, but some options such as <option>-f</option>,
-    <option>-F</option>, <option>-t</option>, and <replaceable
-    class="parameter">dbname</replaceable> should be avoided.
+   Long options are only available on some platforms.
   </para>
  </refsect1>
 
@@ -180,6 +239,26 @@ PostgreSQL documentation
  </refsect1>
 
 
+ <refsect1>
+  <title>Notes</title>
+
+  <para>
+   Since <application>pg_dumpall</application> calls
+   <application>pg_dump</application> internally, some diagnostic
+   messages will refer to <application>pg_dump</application>.
+  </para>
+
+  <para>
+   <application>pg_dumpall</application> will need to connect several
+   times to the <productname>PostgreSQL</productname> server.  If password
+   authentication is configured, it will ask for a password each time. In
+   that case it would be convenient to set up a password file.
+  </para>
+
+  <comment>But where is that password file documented?</comment>
+ </refsect1>
+
+
  <refsect1 id="app-pg-dumpall-ex">
   <title>Examples</title>
   <para>
diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
index 069fd45d3ec..f18280b9580 100644
--- a/src/bin/pg_dump/Makefile
+++ b/src/bin/pg_dump/Makefile
@@ -5,7 +5,7 @@
 # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/pg_dump/Makefile,v 1.37 2002/08/18 09:36:25 petere Exp $
+# $Header: /cvsroot/pgsql/src/bin/pg_dump/Makefile,v 1.38 2002/08/27 18:57:26 petere Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -14,11 +14,12 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS= pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
-      pg_backup_files.o pg_backup_null.o pg_backup_tar.o sprompt.o
+      pg_backup_files.o pg_backup_null.o pg_backup_tar.o \
+      sprompt.o dumputils.o
 
 EXTRA_OBJS = $(top_builddir)/src/backend/parser/keywords.o
 
-override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
+override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -DBINDIR=\"$(bindir)\"
 
 
 all: submake-libpq submake-libpgport submake-backend pg_dump pg_restore pg_dumpall
@@ -29,12 +30,8 @@ pg_dump: pg_dump.o common.o $(OBJS) $(libpq_builddir)/libpq.a
 pg_restore: pg_restore.o $(OBJS) $(libpq_builddir)/libpq.a
 	$(CC) $(CFLAGS) pg_restore.o $(OBJS) $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@
 
-pg_dumpall: pg_dumpall.sh
-	sed -e 's,@VERSION@,$(VERSION),g' \
-	    -e 's,@MULTIBYTE@,$(MULTIBYTE),g' \
-	    -e 's,@bindir@,$(bindir),g' \
-	  $< >$@
-	chmod a+x $@
+pg_dumpall: pg_dumpall.o $(libpq_builddir)/libpq.a
+	$(CC) $(CFLAGS) pg_dumpall.o dumputils.o sprompt.o $(EXTRA_OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@
 
 .PHONY: submake-backend
 submake-backend:
@@ -44,13 +41,13 @@ submake-backend:
 install: all installdirs
 	$(INSTALL_PROGRAM) pg_dump$(X) $(DESTDIR)$(bindir)/pg_dump$(X)
 	$(INSTALL_PROGRAM) pg_restore$(X) $(DESTDIR)$(bindir)/pg_restore$(X)
-	$(INSTALL_SCRIPT) pg_dumpall $(DESTDIR)$(bindir)/pg_dumpall
+	$(INSTALL_PROGRAM) pg_dumpall$(X) $(DESTDIR)$(bindir)/pg_dumpall$(X)
 
 installdirs:
 	$(mkinstalldirs) $(DESTDIR)$(bindir)
 
 uninstall:
-	rm -f $(addprefix $(DESTDIR)$(bindir)/, pg_dump$(X) pg_restore$(X) pg_dumpall)
+	rm -f $(addprefix $(DESTDIR)$(bindir)/, pg_dump$(X) pg_restore$(X) pg_dumpall$(X))
 
 clean distclean maintainer-clean:
-	rm -f pg_dump$(X) pg_restore$(X) $(OBJS) pg_dump.o common.o pg_restore.o pg_dumpall
+	rm -f pg_dump$(X) pg_restore$(X) pg_dumpall$(X) $(OBJS) pg_dump.o common.o pg_restore.o pg_dumpall.o
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
new file mode 100644
index 00000000000..314cf88b5c9
--- /dev/null
+++ b/src/bin/pg_dump/dumputils.c
@@ -0,0 +1,131 @@
+/*-------------------------------------------------------------------------
+ *
+ * Utility routines for SQL dumping
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/dumputils.c,v 1.1 2002/08/27 18:57:26 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include "dumputils.h"
+
+#include "parser/keywords.h"
+
+
+
+/*
+ *	Quotes input string if it's not a legitimate SQL identifier as-is.
+ *
+ *	Note that the returned string must be used before calling fmtId again,
+ *	since we re-use the same return buffer each time.  Non-reentrant but
+ *	avoids memory leakage.
+ */
+const char *
+fmtId(const char *rawid)
+{
+	static PQExpBuffer id_return = NULL;
+	const char *cp;
+	bool need_quotes = false;
+
+	if (id_return)				/* first time through? */
+		resetPQExpBuffer(id_return);
+	else
+		id_return = createPQExpBuffer();
+
+	/* These checks need to match the identifier production in scan.l.
+	 * Don't use islower() etc. */
+
+	if (ScanKeywordLookup(rawid))
+		need_quotes = true;
+	/* slightly different rules for first character */
+	else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
+		need_quotes = true;
+	else
+	{
+		/* otherwise check the entire string */
+		for (cp = rawid; *cp; cp++)
+		{
+			if (!((*cp >= 'a' && *cp <= 'z')
+				  || (*cp >= '0' && *cp <= '9')
+				  || (*cp == '_')))
+			{
+				need_quotes = true;
+				break;
+			}
+		}
+	}
+
+	if (!need_quotes)
+	{
+		/* no quoting needed */
+		appendPQExpBufferStr(id_return, rawid);
+	}
+	else
+	{
+		appendPQExpBufferChar(id_return, '\"');
+		for (cp = rawid; *cp; cp++)
+		{
+			/*
+			 * Did we find a double-quote in the string? Then make this a
+			 * double double-quote per SQL99. Before, we put in a
+			 * backslash/double-quote pair. - thomas 2000-08-05
+			 */
+			if (*cp == '\"')
+				appendPQExpBufferChar(id_return, '\"');
+			appendPQExpBufferChar(id_return, *cp);
+		}
+		appendPQExpBufferChar(id_return, '\"');
+	}
+
+	return id_return->data;
+}
+
+
+
+/*
+ * Convert a string value to an SQL string literal and append it to
+ * the given buffer.
+ *
+ * Special characters are escaped. Quote mark ' goes to '' per SQL
+ * standard, other stuff goes to \ sequences.  If escapeAll is false,
+ * whitespace characters are not escaped (tabs, newlines, etc.).  This
+ * is appropriate for dump file output.
+ */
+void
+appendStringLiteral(PQExpBuffer buf, const char *str, bool escapeAll)
+{
+	appendPQExpBufferChar(buf, '\'');
+	while (*str)
+	{
+		char		ch = *str++;
+
+		if (ch == '\\' || ch == '\'')
+		{
+			appendPQExpBufferChar(buf, ch);		/* double these */
+			appendPQExpBufferChar(buf, ch);
+		}
+		else if ((unsigned char) ch < (unsigned char) ' ' &&
+				 (escapeAll
+				  || (ch != '\t' && ch != '\n' && ch != '\v' && ch != '\f' && ch != '\r')
+				  ))
+		{
+			/*
+			 * generate octal escape for control chars other than
+			 * whitespace
+			 */
+			appendPQExpBufferChar(buf, '\\');
+			appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
+			appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
+			appendPQExpBufferChar(buf, (ch & 7) + '0');
+		}
+		else
+			appendPQExpBufferChar(buf, ch);
+	}
+	appendPQExpBufferChar(buf, '\'');
+}
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
new file mode 100644
index 00000000000..0266ee8f0cb
--- /dev/null
+++ b/src/bin/pg_dump/dumputils.h
@@ -0,0 +1,26 @@
+/*-------------------------------------------------------------------------
+ *
+ * Utility routines for SQL dumping
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/dumputils.h,v 1.1 2002/08/27 18:57:26 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef DUMPUTILS_H
+#define DUMPUTILS_H
+
+#include "postgres_fe.h"
+
+#include "pqexpbuffer.h"
+
+extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
+
+extern const char *fmtId(const char *identifier);
+extern void appendStringLiteral(PQExpBuffer buf, const char *str, bool escapeAll);
+
+#endif DUMPUTILS_H
diff --git a/src/bin/pg_dump/nls.mk b/src/bin/pg_dump/nls.mk
index baf67d603c5..ca39896dfcd 100644
--- a/src/bin/pg_dump/nls.mk
+++ b/src/bin/pg_dump/nls.mk
@@ -1,8 +1,8 @@
-# $Header: /cvsroot/pgsql/src/bin/pg_dump/nls.mk,v 1.6 2001/12/21 22:30:49 petere Exp $
+# $Header: /cvsroot/pgsql/src/bin/pg_dump/nls.mk,v 1.7 2002/08/27 18:57:26 petere Exp $
 CATALOG_NAME	:= pg_dump
 AVAIL_LANGUAGES	:= cs de ru sv zh_CN zh_TW
 GETTEXT_FILES	:= pg_dump.c common.c pg_backup_archiver.c pg_backup_custom.c \
                    pg_backup_db.c pg_backup_files.c pg_backup_null.c \
-                   pg_backup_tar.c pg_restore.c
+                   pg_backup_tar.c pg_restore.c pg_dumpall.c
 GETTEXT_TRIGGERS:= write_msg:2 die_horribly:3 exit_horribly:3 simple_prompt \
-                   ExecuteSqlCommand:3 ahlog:3
+                   ExecuteSqlCommand:3 ahlog:3 _
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index eaa46c29afa..de840e1b77f 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.22 2002/08/20 17:54:44 petere Exp $
+ *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.23 2002/08/27 18:57:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -118,11 +118,6 @@ extern void
 exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
 __attribute__((format(printf, 3, 4)));
 
-extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
-
-extern const char *fmtId(const char *identifier);
-extern void appendStringLiteral(PQExpBuffer buf, const char *str, bool escapeAll);
-
 
 /* Lets the archive know we have a DB connection to shutdown if it dies */
 
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 6ba15a913ec..aefd094b534 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.55 2002/08/20 17:54:44 petere Exp $
+ *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.56 2002/08/27 18:57:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,14 +24,14 @@
 #include "pg_dump.h"
 #include "pg_backup_archiver.h"
 #include "pg_backup_db.h"
+#include "dumputils.h"
 
 #include <ctype.h>
 #include <errno.h>
-#include <unistd.h>				/* for dup */
+#include <unistd.h>
 
 #include "pqexpbuffer.h"
 #include "libpq/libpq-fs.h"
-#include "parser/keywords.h"
 
 
 typedef enum _teReqs_
@@ -2105,117 +2105,6 @@ _selectOutputSchema(ArchiveHandle *AH, const char *schemaName)
 }
 
 
-/*
- *	Quotes input string if it's not a legitimate SQL identifier as-is.
- *
- *	Note that the returned string must be used before calling fmtId again,
- *	since we re-use the same return buffer each time.  Non-reentrant but
- *	avoids memory leakage.
- */
-const char *
-fmtId(const char *rawid)
-{
-	static PQExpBuffer id_return = NULL;
-	const char *cp;
-	bool need_quotes = false;
-
-	if (id_return)				/* first time through? */
-		resetPQExpBuffer(id_return);
-	else
-		id_return = createPQExpBuffer();
-
-	/* These checks need to match the identifier production in scan.l.
-	 * Don't use islower() etc. */
-
-	if (ScanKeywordLookup(rawid))
-		need_quotes = true;
-	/* slightly different rules for first character */
-	else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
-		need_quotes = true;
-	else
-	{
-		/* otherwise check the entire string */
-		for (cp = rawid; *cp; cp++)
-		{
-			if (!((*cp >= 'a' && *cp <= 'z')
-				  || (*cp >= '0' && *cp <= '9')
-				  || (*cp == '_')))
-			{
-				need_quotes = true;
-				break;
-			}
-		}
-	}
-
-	if (!need_quotes)
-	{
-		/* no quoting needed */
-		appendPQExpBufferStr(id_return, rawid);
-	}
-	else
-	{
-		appendPQExpBufferChar(id_return, '\"');
-		for (cp = rawid; *cp; cp++)
-		{
-			/*
-			 * Did we find a double-quote in the string? Then make this a
-			 * double double-quote per SQL99. Before, we put in a
-			 * backslash/double-quote pair. - thomas 2000-08-05
-			 */
-			if (*cp == '\"')
-				appendPQExpBufferChar(id_return, '\"');
-			appendPQExpBufferChar(id_return, *cp);
-		}
-		appendPQExpBufferChar(id_return, '\"');
-	}
-
-	return id_return->data;
-}
-
-
-/*
- * Convert a string value to an SQL string literal and append it to
- * the given buffer.
- *
- * Special characters are escaped. Quote mark ' goes to '' per SQL
- * standard, other stuff goes to \ sequences.  If escapeAll is false,
- * whitespace characters are not escaped (tabs, newlines, etc.).  This
- * is appropriate for dump file output.
- */
-void
-appendStringLiteral(PQExpBuffer buf, const char *str, bool escapeAll)
-{
-	appendPQExpBufferChar(buf, '\'');
-	while (*str)
-	{
-		char		ch = *str++;
-
-		if (ch == '\\' || ch == '\'')
-		{
-			appendPQExpBufferChar(buf, ch);		/* double these */
-			appendPQExpBufferChar(buf, ch);
-		}
-		else if ((unsigned char) ch < (unsigned char) ' ' &&
-				 (escapeAll
-				  || (ch != '\t' && ch != '\n' && ch != '\v' && ch != '\f' && ch != '\r')
-				  ))
-		{
-			/*
-			 * generate octal escape for control chars other than
-			 * whitespace
-			 */
-			appendPQExpBufferChar(buf, '\\');
-			appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
-			appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
-			appendPQExpBufferChar(buf, (ch & 7) + '0');
-		}
-		else
-			appendPQExpBufferChar(buf, ch);
-	}
-	appendPQExpBufferChar(buf, '\'');
-}
-
-
 
 static int
 _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData)
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
index ed77984e178..f54153d4aec 100644
--- a/src/bin/pg_dump/pg_backup_db.c
+++ b/src/bin/pg_dump/pg_backup_db.c
@@ -5,7 +5,7 @@
  *	Implements the basic DB functions used by the archiver.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.38 2002/08/20 17:54:44 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.39 2002/08/27 18:57:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -13,6 +13,7 @@
 #include "pg_backup.h"
 #include "pg_backup_archiver.h"
 #include "pg_backup_db.h"
+#include "dumputils.h"
 
 #include <unistd.h>
 #include <ctype.h>
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 645e295aa07..c3a1ace2d04 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.291 2002/08/22 21:35:50 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.292 2002/08/27 18:57:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,6 +63,7 @@
 #include "pg_dump.h"
 #include "pg_backup.h"
 #include "pg_backup_archiver.h"
+#include "dumputils.h"
 
 
 typedef struct _dumpContext
@@ -269,9 +270,9 @@ main(int argc, char **argv)
 	}
 
 #ifdef HAVE_GETOPT_LONG
-	while ((c = getopt_long(argc, argv, "abcCdDf:F:h:ioOp:RsS:t:uU:vWxX:zZ:V?", long_options, &optindex)) != -1)
+	while ((c = getopt_long(argc, argv, "abcCdDf:F:h:ioOp:RsS:t:uU:vWxX:Z:", long_options, &optindex)) != -1)
 #else
-	while ((c = getopt(argc, argv, "abcCdDf:F:h:ioOp:RsS:t:uU:vWxX:zZ:V?-")) != -1)
+	while ((c = getopt(argc, argv, "abcCdDf:F:h:ioOp:RsS:t:uU:vWxX:Z:-")) != -1)
 #endif
 
 	{
@@ -477,7 +478,7 @@ main(int argc, char **argv)
 	if (dumpData == true && oids == true)
 	{
 		write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together.\n");
-		write_msg(NULL, "(The INSERT command cannot set oids.)\n");
+		write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
 		exit(1);
 	}
 
@@ -660,9 +661,7 @@ help(const char *progname)
 		"  -h, --host=HOSTNAME      database server host name\n"
 		"  -i, --ignore-version     proceed even when server version mismatches\n"
 		"                           pg_dump version\n"
-		"  -n, --no-quotes          suppress most quotes around identifiers\n"
-		"  -N, --quotes             enable most quotes around identifiers\n"
-		"  -o, --oids               include oids in dump\n"
+		"  -o, --oids               include OIDs in dump\n"
 		"  -O, --no-owner           do not output \\connect commands in plain\n"
 		"                           text format\n"
 		"  -p, --port=PORT          database server port number\n"
@@ -696,9 +695,7 @@ help(const char *progname)
 		"  -h HOSTNAME              database server host name\n"
 		"  -i                       proceed even when server version mismatches\n"
 		"                           pg_dump version\n"
-		"  -n                       suppress most quotes around identifiers\n"
-		"  -N                       enable most quotes around identifiers\n"
-		"  -o                       include oids in dump\n"
+		"  -o                       include OIDs in dump\n"
 		"  -O                       do not output \\connect commands in plain\n"
 		"                           text format\n"
 		"  -p PORT                  database server port number\n"
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
new file mode 100644
index 00000000000..5e1e66404c8
--- /dev/null
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -0,0 +1,604 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_dumpall
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.1 2002/08/27 18:57:26 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include <unistd.h>
+#ifdef ENABLE_NLS
+#include <locale.h>
+#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#ifndef HAVE_STRDUP
+#include "strdup.h"
+#endif
+#include <errno.h>
+
+#include "dumputils.h"
+#include "libpq-fe.h"
+#include "pg_backup.h"
+#include "pqexpbuffer.h"
+
+#define _(x) gettext((x))
+
+
+static char *progname;
+
+static void help(void);
+static void dumpUsers(PGconn *conn);
+static void dumpGroups(PGconn *conn);
+static void dumpCreateDB(PGconn *conn);
+static void dumpDatabases(PGconn *conn);
+static int runPgDump(const char *dbname);
+static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
+							   const char *pguser, bool require_password);
+static PGresult *executeQuery(PGconn *conn, const char *query);
+static char *findPgDump(const char *argv0);
+
+
+char *pgdumploc;
+PQExpBuffer pgdumpopts;
+bool output_clean = false;
+bool verbose = false;
+
+
+
+int
+main(int argc, char *argv[])
+{
+	char	   *pghost = NULL;
+	char	   *pgport = NULL;
+	char	   *pguser = NULL;
+	bool		force_password = false;
+	bool		globals_only = false;
+	PGconn	   *conn;
+	int			c;
+
+#ifdef HAVE_GETOPT_LONG
+	static struct option long_options[] = {
+		{"clean", no_argument, NULL, 'c'},
+		{"inserts", no_argument, NULL, 'd'},
+		{"attribute-inserts", no_argument, NULL, 'D'},
+		{"column-inserts", no_argument, NULL, 'D'},
+		{"host", required_argument, NULL, 'h'},
+		{"ignore-version", no_argument, NULL, 'i'},
+		{"oids", no_argument, NULL, 'o'},
+		{"port", required_argument, NULL, 'p'},
+		{"password", no_argument, NULL, 'W'},
+		{"username", required_argument, NULL, 'U'},
+		{"verbose", no_argument, NULL, 'v'},
+		{NULL, 0, NULL, 0}
+	};
+
+	int			optindex;
+#endif
+
+#ifdef ENABLE_NLS
+	setlocale(LC_ALL, "");
+	bindtextdomain("pg_dump", LOCALEDIR);
+	textdomain("pg_dump");
+#endif
+
+	if (!strrchr(argv[0], '/'))
+		progname = argv[0];
+	else
+		progname = strrchr(argv[0], '/') + 1;
+
+	if (argc > 1)
+	{
+		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
+		{
+			help();
+			exit(0);
+		}
+		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
+		{
+			puts("pg_dumpall (PostgreSQL) " PG_VERSION);
+			exit(0);
+		}
+	}
+
+	pgdumploc = findPgDump(argv[0]);
+	pgdumpopts = createPQExpBuffer();
+
+#ifdef HAVE_GETOPT_LONG
+	while ((c = getopt_long(argc, argv, "cdDgh:iop:U:vW", long_options, &optindex)) != -1)
+#else
+	while ((c = getopt(argc, argv, "cdDgh:iop:U:vW")) != -1)
+#endif
+	{
+		switch (c)
+		{
+			case 'c':
+				output_clean = true;
+				appendPQExpBuffer(pgdumpopts, " -c");
+				break;
+
+			case 'd':
+			case 'D':
+				appendPQExpBuffer(pgdumpopts, " -%c", c);
+				break;
+
+			case 'g':
+				globals_only = true;
+				break;
+
+			case 'h':
+				pghost = optarg;
+				appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost);
+				break;
+
+			case 'i':
+			case 'o':
+				appendPQExpBuffer(pgdumpopts, " -%c", c);
+				break;
+
+			case 'p':
+				pgport = optarg;
+				appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport);
+				break;
+
+			case 'U':
+				pguser = optarg;
+				appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser);
+				break;
+
+			case 'v':
+				verbose = true;
+				appendPQExpBuffer(pgdumpopts, " -v");
+				break;
+
+			case 'W':
+				force_password = true;
+				appendPQExpBuffer(pgdumpopts, " -W");
+				break;
+
+            default:
+                fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
+                exit(1);
+		}
+	}
+
+    if (optind < argc)
+    {
+        fprintf(stderr,
+				_("%s: too many command line options (first is '%s')\n"
+				  "Try '%s --help' for more information.\n"),
+                progname, argv[optind], progname);
+        exit(1);
+    }
+
+
+	conn = connectDatabase("template1", pghost, pgport, pguser, force_password);
+
+	printf("--\n");
+	printf("-- PostgreSQL database cluster dump\n");
+	printf("--\n\n");
+	printf("\\connect \"template1\"\n\n");
+
+	dumpUsers(conn);
+	dumpGroups(conn);
+
+	if (globals_only)
+		goto end;
+
+	dumpCreateDB(conn);
+	dumpDatabases(conn);
+
+end:
+	PQfinish(conn);
+	exit(0);
+}
+
+
+
+static void
+help(void)
+{
+	printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
+	printf(_("Usage:\n"));
+	printf(_("  %s [OPTIONS]\n\n"), progname);
+
+	printf(_("Options:\n"));
+#ifdef HAVE_GETOPT_LONG
+    printf(_("  -c, --clean              clean (drop) schema prior to create\n"));
+	printf(_("  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"));
+	printf(_("  -D, --column-inserts     dump data as INSERT commands with column names\n"));
+	printf(_("  -g, --globals-only       only dump global objects, no databases\n"));
+    printf(_("  -h, --host=HOSTNAME      database server host name\n"));
+	printf(_("  -i, --ignore-version     proceed even when server version mismatches\n"
+			 "                           pg_dumpall version\n"));
+	printf(_("  -o, --oids               include OIDs in dump\n"));
+    printf(_("  -p, --port=PORT          database server port number\n"));
+    printf(_("  -U, --username=NAME      connect as specified database user\n"));
+	printf(_("  -v, --verbose            verbose mode\n"));
+    printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
+#else /* not HAVE_GETOPT_LONG */
+    printf(_("  -c                       clean (drop) schema prior to create\n"));
+	printf(_("  -d                       dump data as INSERT, rather than COPY, commands\n"));
+	printf(_("  -D                       dump data as INSERT commands with column names\n"));
+	printf(_("  -g                       only dump global objects, no databases\n"));
+    printf(_("  -h HOSTNAME              database server host name\n"));
+	printf(_("  -i                       proceed even when server version mismatches\n"
+			 "                           pg_dumpall version\n"));
+	printf(_("  -o                       include oids in dump\n"));
+    printf(_("  -p PORT                  database server port number\n"));
+    printf(_("  -U NAME                  connect as specified database user\n"));
+	printf(_("  -v                       verbose mode\n"));
+    printf(_("  -W                       force password prompt (should happen automatically)\n"));
+#endif /* not HAVE_GETOPT_LONG */
+
+	printf(_("\nThe SQL script will be written to the standard output.\n\n"));
+	printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
+}
+
+
+
+/*
+ * Dump users (but not the user created by initdb).
+ */
+static void
+dumpUsers(PGconn *conn)
+{
+	PGresult *res;
+	int i;
+
+	printf("DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');\n\n");
+
+	res = executeQuery(conn,
+					   "SELECT usename, usesysid, passwd, usecreatedb, usesuper, CAST(valuntil AS timestamp) "
+					   "FROM pg_shadow "
+					   "WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');");
+
+	for (i = 0; i < PQntuples(res); i++)
+	{
+		PQExpBuffer buf = createPQExpBuffer();
+
+		appendPQExpBuffer(buf, "CREATE USER %s WITH SYSID %s",
+						  fmtId(PQgetvalue(res, i, 0)),
+						  PQgetvalue(res, i, 1));
+
+		if (!PQgetisnull(res, i, 2))
+		{
+			appendPQExpBuffer(buf, " PASSWORD ");
+			appendStringLiteral(buf, PQgetvalue(res, i, 2), true);
+		}
+
+		if (strcmp(PQgetvalue(res, i, 3), "t")==0)
+			appendPQExpBuffer(buf, " CREATEDB");
+		else
+			appendPQExpBuffer(buf, " NOCREATEDB");
+
+		if (strcmp(PQgetvalue(res, i, 4), "t")==0)
+			appendPQExpBuffer(buf, " CREATEUSER");
+		else
+			appendPQExpBuffer(buf, " NOCREATEUSER");
+
+		if (!PQgetisnull(res, i, 5))
+			appendPQExpBuffer(buf, " VALID UNTIL '%s'", PQgetvalue(res, i, 5));
+
+		appendPQExpBuffer(buf, ";\n");
+
+		printf("%s", buf->data);
+		destroyPQExpBuffer(buf);
+	}
+
+	PQclear(res);
+	printf("\n\n");
+}
+
+
+
+/*
+ * Dump groups.
+ */
+static void
+dumpGroups(PGconn *conn)
+{
+	PGresult *res;
+	int i;
+
+	printf("DELETE FROM pg_group;\n\n");
+
+	res = executeQuery(conn, "SELECT groname, grosysid, grolist FROM pg_group;");
+
+	for (i = 0; i < PQntuples(res); i++)
+	{
+		PQExpBuffer buf = createPQExpBuffer();
+		char *val;
+		char *tok;
+
+		appendPQExpBuffer(buf, "CREATE GROUP %s WITH SYSID %s;\n",
+						  fmtId(PQgetvalue(res, i, 0)),
+						  PQgetvalue(res, i, 1));
+
+		val = strdup(PQgetvalue(res, i, 2));
+		tok = strtok(val, ",{}");
+		do
+		{
+			PGresult *res2;
+			PQExpBuffer buf2 = createPQExpBuffer();
+			int j;
+
+			appendPQExpBuffer(buf2, "SELECT usename FROM pg_shadow WHERE usesysid = %s;", tok);
+			res2 = executeQuery(conn, buf2->data);
+			destroyPQExpBuffer(buf2);
+
+			for (j = 0; j < PQntuples(res2); j++)
+			{
+				appendPQExpBuffer(buf, "ALTER GROUP %s ", fmtId(PQgetvalue(res, i, 0)));
+				appendPQExpBuffer(buf, "ADD USER %s;\n", fmtId(PQgetvalue(res2, j, 0)));
+			}
+
+			PQclear(res2);
+
+			tok = strtok(NULL, "{},");
+		}
+		while (tok);
+
+		printf("%s", buf->data);
+		destroyPQExpBuffer(buf);
+	}
+
+	PQclear(res);
+	printf("\n\n");
+}
+
+
+
+/*
+ * Dump commands to create each database.
+ *
+ * To minimize the number of reconnections (and possibly ensuing
+ * password prompts) required by the output script, we emit all CREATE
+ * DATABASE commands during the initial phase of the script, and then
+ * run pg_dump for each database to dump the contents of that
+ * database.  We skip databases marked not datallowconn, since we'd be
+ * unable to connect to them anyway (and besides, we don't want to
+ * dump template0).
+ */
+static void
+dumpCreateDB(PGconn *conn)
+{
+	PGresult *res;
+	int i;
+
+	/* Basically this query returns: dbname, dbowner, encoding, istemplate, dbpath */
+	res = executeQuery(conn, "SELECT datname, coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), pg_encoding_to_char(d.encoding), datistemplate, datpath FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) WHERE datallowconn ORDER BY 1;");
+
+	for (i = 0; i < PQntuples(res); i++)
+	{
+		PQExpBuffer buf = createPQExpBuffer();
+		char *dbname = PQgetvalue(res, i, 0);
+		char *dbowner = PQgetvalue(res, i, 1);
+		char *dbencoding = PQgetvalue(res, i, 2);
+		char *dbistemplate = PQgetvalue(res, i, 3);
+		char *dbpath = PQgetvalue(res, i, 4);
+
+		if (strcmp(dbname, "template1")==0)
+			continue;
+
+		if (output_clean)
+			appendPQExpBuffer(buf, "DROP DATABASE %s\n;", fmtId(dbname));
+
+		appendPQExpBuffer(buf, "CREATE DATABASE %s", fmtId(dbname));
+		appendPQExpBuffer(buf, " WITH OWNER = %s TEMPLATE = template0", fmtId(dbowner));
+
+		if (strcmp(dbpath, "")!=0)
+		{
+			appendPQExpBuffer(buf, " LOCATION = ");
+			appendStringLiteral(buf, dbpath, true);
+		}
+
+		appendPQExpBuffer(buf, " ENCODING = ");
+		appendStringLiteral(buf, dbencoding, true);
+
+		appendPQExpBuffer(buf, ";\n");
+
+		if (strcmp(dbistemplate, "t")==0)
+		{
+			appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
+			appendStringLiteral(buf, dbname, true);
+			appendPQExpBuffer(buf, ";\n");
+		}
+		printf("%s", buf->data);
+		destroyPQExpBuffer(buf);
+	}
+
+	PQclear(res);
+	printf("\n\n");
+}
+
+
+
+/*
+ * Dump contents of databases.
+ */
+static void
+dumpDatabases(PGconn *conn)
+{
+	PGresult *res;
+	int i;
+
+	res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;");
+	for (i = 0; i < PQntuples(res); i++)
+	{
+		int ret;
+
+		char *dbname = PQgetvalue(res, i, 0);
+		if (verbose)
+			fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
+
+		printf("\\connect %s\n", fmtId(dbname));
+		ret = runPgDump(dbname);
+		if (ret != 0)
+		{
+			fprintf(stderr, _("%s: pg_dump failed on %s, exiting\n"), progname, dbname);
+			exit(1);
+		}
+	}
+
+	PQclear(res);
+}
+
+
+
+/*
+ * Run pg_dump on dbname.
+ */
+static int
+runPgDump(const char *dbname)
+{
+	PQExpBuffer cmd = createPQExpBuffer();
+	int ret;
+
+	appendPQExpBuffer(cmd, "%s %s -X use-set-session-authorization -Fp %s",
+					  pgdumploc, pgdumpopts->data, dbname);
+	if (verbose)
+		fprintf(stderr, _("%s: running %s\n"), progname, cmd->data);
+
+	ret = system(cmd->data);
+	destroyPQExpBuffer(cmd);
+
+	return ret;
+}
+
+
+
+/*
+ * Make a database connection with the given parameters.  An
+ * interactive password prompt is automatically issued if required.
+ */
+static PGconn *
+connectDatabase(const char *dbname, const char *pghost, const char *pgport,
+				const char *pguser, bool require_password)
+{
+	PGconn	   *conn;
+	char	   *password = NULL;
+	bool		need_pass = false;
+
+	if (require_password)
+		password = simple_prompt("Password: ", 100, false);
+
+	/*
+	 * Start the connection.  Loop until we have a password if requested
+	 * by backend.
+	 */
+	do
+	{
+		need_pass = false;
+		conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);
+
+		if (!conn)
+		{
+			fprintf(stderr, _("%s: could not connection to database %s\n"),
+					progname, dbname);
+			exit(0);
+		}
+
+		if (PQstatus(conn) == CONNECTION_BAD &&
+			strcmp(PQerrorMessage(conn), "fe_sendauth: no password supplied\n") == 0 &&
+			!feof(stdin))
+		{
+			PQfinish(conn);
+			need_pass = true;
+			free(password);
+			password = NULL;
+			password = simple_prompt("Password: ", 100, false);
+		}
+	} while (need_pass);
+
+	if (password)
+		free(password);
+
+	/* check to see that the backend connection was successfully made */
+	if (PQstatus(conn) == CONNECTION_BAD)
+	{
+		fprintf(stderr, _("%s: could not connection to database %s: %s\n"),
+					progname, dbname, PQerrorMessage(conn));
+		exit(0);
+	}
+
+	return conn;
+}
+
+
+
+/*
+ * Run a query, return the results, exit program on failure.
+ */
+static PGresult *
+executeQuery(PGconn *conn, const char *query)
+{
+	PGresult *res;
+
+	res = PQexec(conn, query);
+	if (!res ||
+		PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		fprintf(stderr, _("%s: query failed: %s"), progname, PQerrorMessage(conn));
+		fprintf(stderr, _("%s: query was: %s"), progname, query);
+		PQfinish(conn);
+		exit(1);
+	}
+
+	return res;
+}
+
+
+
+/*
+ * Find location of pg_dump executable.
+ */
+static char *
+findPgDump(const char *argv0)
+{
+	char	   *last;
+	PQExpBuffer cmd;
+	static char *result = NULL;
+
+	if (result)
+		return result;
+
+	cmd = createPQExpBuffer();
+	last = strrchr(argv0, '/');
+
+	if (!last)
+		appendPQExpBuffer(cmd, "pg_dump");
+	else
+	{
+		char *dir = strdup(argv0);
+		*(dir + (last - argv0)) = '\0';
+		appendPQExpBuffer(cmd, "%s/pg_dump", dir);
+	}
+
+	result = strdup(cmd->data);
+
+	appendPQExpBuffer(cmd, " -V >/dev/null 2>&1");
+	if (system(cmd->data)==0)
+		goto end;
+
+	result = BINDIR "/pg_dump";
+	if (system(BINDIR "/pg_dump -V >/dev/null 2>&1")==0)
+		goto end;
+
+	fprintf(stderr, _("%s: could not find pg_dump\n"
+					  "Make sure it is in the path or in the same directory as %s.\n"),
+			progname, progname);
+	exit(1);
+
+end:
+	destroyPQExpBuffer(cmd);
+	return result;
+}
diff --git a/src/bin/pg_dump/pg_dumpall.sh b/src/bin/pg_dump/pg_dumpall.sh
deleted file mode 100644
index 6a8ec8d3ebc..00000000000
--- a/src/bin/pg_dump/pg_dumpall.sh
+++ /dev/null
@@ -1,289 +0,0 @@
-#! /bin/sh
-
-# pg_dumpall
-#
-# Dumps all databases to standard output. It also dumps the "pg_shadow"
-# and "pg_group" tables, which belong to the whole installation rather
-# than any one individual database.
-#
-# $Header: /cvsroot/pgsql/src/bin/pg_dump/Attic/pg_dumpall.sh,v 1.21 2002/04/12 09:37:10 momjian Exp $
-
-CMDNAME="`basename $0`"
-
-# substituted at build
-VERSION='@VERSION@'
-MULTIBYTE='@MULTIBYTE@'
-bindir='@bindir@'
-
-# These handle spaces/tabs in identifiers
-_IFS="$IFS"
-NL="
-"
-
-#
-# Find out where we're located
-#
-PGPATH=
-if echo "$0" | grep '/' > /dev/null 2>&1 ; then
-    # explicit dir name given
-    PGPATH=`echo "$0" | sed 's,/[^/]*$,,'`       # (dirname command is not portable)
-else
-    # look for it in PATH ('which' command is not portable)
-    echo "$PATH" | sed "s/:/$NL/g" | 
-    while :; do
-        IFS="$NL"
-        read dir || break
-        IFS="$_IFS"
-        # empty entry in path means current dir
-        [ x"$dir" = x ] && dir='.'
-        if [ -f "$dir/$CMDNAME" ] ; then
-            PGPATH="$dir"
-            break
-        fi
-    done
-fi
-IFS="$_IFS"
-
-# As last resort use the installation directory. We don't want to use
-# this as first resort because depending on how users do release upgrades
-# they might temporarily move the installation tree elsewhere, so we'd
-# accidentally invoke the newly installed versions of pg_dump and psql.
-if [ x"$PGPATH" = x"" ]; then
-    PGPATH="$bindir"
-fi
-
-#
-# Look for needed programs
-#
-for prog in pg_dump psql ; do
-    if [ ! -x "$PGPATH/$prog" ] ; then
-      (
-        echo "The program $prog needed by $CMDNAME could not be found. It was"
-        echo "expected at:"
-        echo "    $PGPATH/$prog"
-        echo "If this is not the correct directory, please start $CMDNAME"
-        echo "with a full search path. Otherwise make sure that the program"
-        echo "was installed successfully."
-      ) 1>&2
-        exit 1
-    fi
-done
-
-#
-# to adapt to System V vs. BSD 'echo'
-#
-if echo '\\' | grep '\\\\' >/dev/null 2>&1
-then	
-    BS='\' dummy='\'            # BSD
-else
-    BS='\\'                     # System V
-fi
-# The dummy assignment is necessary to prevent Emacs' font-lock
-# mode from going ballistic when editing this file.
-
-
-usage=
-cleanschema=
-globals_only=
-
-
-while [ "$#" -gt 0 ] ; do
-    case "$1" in
-        --help)
-                usage=t
-                break
-                ;;
-        --version)
-                echo "pg_dumpall (PostgreSQL) $VERSION"
-                exit 0
-                ;;
-	--host|-h)
-		connectopts="$connectopts -h $2"
-		shift;;
-        -h*)
-                connectopts="$connectopts $1"
-                ;;
-        --host=*)
-                connectopts="$connectopts -h `echo $1 | sed 's/^--host=//'`"
-                ;;
-	--port|-p)
-		connectopts="$connectopts -p $2"
-		shift;;
-        -p*)
-                connectopts="$connectopts $1"
-                ;;
-        --port=*)
-                connectopts="$connectopts -p `echo $1 | sed 's/^--port=//'`"
-                ;;
-	--user|--username|-U)
-		connectopts="$connectopts -U $2"
-		shift;;
-	-U*)
-		connectopts="$connectopts $1"
-		;;
-	--user=*|--username=*)
-		connectopts="$connectopts -U `echo $1 | sed 's/^--user[^=]*=//'`"
-		;;
-	-W|--password)
-		connectopts="$connectopts -W"
-		;;
-
-        -c|--clean)
-                cleanschema=yes
-                pgdumpextraopts="$pgdumpextraopts -c"
-                ;;
-        -g|--globals-only)
-                globals_only=yes
-                ;;
-        -F*|--format=*|-f|--file=*|-t|--table=*)
-                echo "pg_dump can not process option $1, exiting" 1>&2
-                exit 1
-                ;;
-        *)
-                pgdumpextraopts="$pgdumpextraopts $1"
-                ;;
-    esac
-    shift
-done
-
-
-if [ "$usage" ] ; then
-    echo "$CMDNAME extracts a PostgreSQL database cluster into an SQL script file."
-    echo
-    echo "Usage:"
-    echo "  $CMDNAME [ options... ]"
-    echo
-    echo "Options:"
-    echo "  -c, --clean            Clean (drop) schema prior to create"
-    echo "  -g, --globals-only     Only dump global objects, no databases"
-    echo "  -h, --host=HOSTNAME    Server host name"
-    echo "  -p, --port=PORT        Server port number"
-    echo "  -U, --username=NAME    Connect as specified database user"
-    echo "  -W, --password         Force password prompts (should happen automatically)"
-    echo "Any other options will be passed to pg_dump.  The dump will be written"
-    echo "to the standard output."
-    echo
-    echo "Report bugs to <pgsql-bugs@postgresql.org>."
-    exit 0
-fi
-
-
-PSQL="${PGPATH}/psql $connectopts"
-PGDUMP="${PGPATH}/pg_dump $connectopts $pgdumpextraopts -X use-set-session-authorization -Fp"
-
-
-echo "--"
-echo "-- pg_dumpall ($VERSION) $connectopts $pgdumpextraopts"
-echo "--"
-echo "${BS}connect \"template1\""
-
-#
-# Dump users (but not the user created by initdb)
-#
-echo "DELETE FROM pg_shadow WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');"
-echo
-
-echo "connected to template1..." 1>&2
-$PSQL -d template1 -At -c "\
-SELECT
-  'CREATE USER \"' || usename || '\" WITH SYSID ' || usesysid
-  || CASE WHEN passwd IS NOT NULL THEN ' PASSWORD ''' || passwd || '''' else '' end
-  || CASE WHEN usecreatedb THEN ' CREATEDB'::text ELSE ' NOCREATEDB' END
-  || CASE WHEN usesuper THEN ' CREATEUSER'::text ELSE ' NOCREATEUSER' END
-  || CASE WHEN valuntil IS NOT NULL THEN ' VALID UNTIL '''::text
-    || CAST(valuntil AS TIMESTAMP) || '''' ELSE '' END || ';'
-FROM pg_shadow
-WHERE usesysid <> (SELECT datdba FROM pg_database WHERE datname = 'template0');" \
-|| exit 1
-echo
-
-#
-# Dump groups
-#
-echo "DELETE FROM pg_group;"
-echo
-
-
-$PSQL -d template1 -At -F "$NL" \
-    -c 'SELECT groname,grosysid,grolist FROM pg_group;' | \
-while : ; do
-    IFS="$NL"
-    read GRONAME || break
-    read GROSYSID || break
-    read GROLIST || break
-    IFS="$_IFS"
-    echo "CREATE GROUP \"$GRONAME\" WITH SYSID ${GROSYSID};"
-    echo "$GROLIST" | sed 's/^{\(.*\)}$/\1/' | tr ',' '\n' |
-    while read userid; do
-        username="`$PSQL -d template1 -At -c \"SELECT usename FROM pg_shadow WHERE usesysid = ${userid};\"`"
-        echo "  ALTER GROUP \"$GRONAME\" ADD USER \"$username\";"
-    done
-done
-IFS="$_IFS"
-
-test "$globals_only" = yes && exit 0
-
-
-# Save stdin for pg_dump password prompts.
-exec 4<&0
-
-# To minimize the number of reconnections (and possibly ensuing password
-# prompts) required by the output script, we emit all CREATE DATABASE
-# commands during the initial phase of the script, and then run pg_dump
-# for each database to dump the contents of that database.
-# We skip databases marked not datallowconn, since we'd be unable to
-# connect to them anyway (and besides, we don't want to dump template0).
-
-$PSQL -d template1 -At -F "$NL" \
-    -c "SELECT datname, coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), pg_encoding_to_char(d.encoding), datistemplate, datpath FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) WHERE datallowconn ORDER BY 1;" | \
-while : ; do
-    IFS="$NL"
-    read DATABASE || break
-    read DBOWNER || break
-    read ENCODING || break
-    read ISTEMPLATE || break
-    read DBPATH || break
-    IFS="$_IFS"
-    if [ "$DATABASE" != template1 ] ; then
-	echo
-
-	if [ "$cleanschema" = yes ] ; then
-	    echo "DROP DATABASE \"$DATABASE\";"
-	fi
-
-	createdbcmd="CREATE DATABASE \"$DATABASE\" WITH OWNER = \"$DBOWNER\" TEMPLATE = template0"
-	if [ x"$DBPATH" != x"" ] ; then
-	    createdbcmd="$createdbcmd LOCATION = '$DBPATH'"
-	fi
-	if [ x"$MULTIBYTE" != x"" ] ; then
-	    createdbcmd="$createdbcmd ENCODING = '$ENCODING'"
-	fi
-	echo "$createdbcmd;"
-	if [ x"$ISTEMPLATE" = xt ] ; then
-	    echo "UPDATE pg_database SET datistemplate = 't' WHERE datname = '$DATABASE';"
-	fi
-    fi
-done
-IFS="$_IFS"
-
-$PSQL -d template1 -At -F "$NL" \
-    -c "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;" | \
-while :; do
-    IFS="$NL"
-    read DATABASE || break
-    IFS="$_IFS"
-    echo "dumping database \"$DATABASE\"..." 1>&2
-    echo
-    echo "--"
-    echo "-- Database $DATABASE"
-    echo "--"
-    echo "${BS}connect \"$DATABASE\""
-
-    $PGDUMP "$DATABASE" <&4
-    if [ "$?" -ne 0 ] ; then
-        echo "pg_dump failed on $DATABASE, exiting" 1>&2
-        exit 1
-    fi
-done
-
-exit 0
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
index 319af0a9876..f6602ff9e75 100644
--- a/src/bin/pg_dump/pg_restore.c
+++ b/src/bin/pg_dump/pg_restore.c
@@ -34,13 +34,14 @@
  *
  *
  * IDENTIFICATION
- *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.38 2002/08/10 16:57:32 petere Exp $
+ *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.39 2002/08/27 18:57:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "pg_backup.h"
 #include "pg_backup_archiver.h"
+#include "dumputils.h"
 
 #include <ctype.h>
 
-- 
GitLab