diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index 353b8cf2f361ad4d1a908d109794d758de21ebe7..122137ad2b9654c9e97a8834836043c53456b34c 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/maintenance.sgml,v 1.22 2003/03/25 16:15:37 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/maintenance.sgml,v 1.23 2003/06/18 12:19:11 petere Exp $
 -->
 
 <chapter id="maintenance">
@@ -136,7 +136,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/maintenance.sgml,v 1.22 2003/03/25 16:15:37
     <command>VACUUM</> once a day at a low-usage time of day, supplemented
     by more frequent vacuuming of heavily-updated tables if necessary.
     (If you have multiple databases in a cluster, don't forget to
-    vacuum each one; the <filename>vacuumdb</> script may be helpful.)
+    vacuum each one; the program <filename>vacuumdb</> may be helpful.)
     Use plain <command>VACUUM</>, not <command>VACUUM FULL</>, for routine
     vacuuming for space recovery.
    </para>
diff --git a/doc/src/sgml/ref/clusterdb.sgml b/doc/src/sgml/ref/clusterdb.sgml
index 4200481c1da60fe5aa22b157276453a5a7eecc27..eb8142618764a9d40cb4d319f478116abf5c6d73 100644
--- a/doc/src/sgml/ref/clusterdb.sgml
+++ b/doc/src/sgml/ref/clusterdb.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/clusterdb.sgml,v 1.9 2003/03/24 14:32:51 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/clusterdb.sgml,v 1.10 2003/06/18 12:19:11 petere Exp $
 PostgreSQL documentation
 -->
 
@@ -41,16 +41,13 @@ PostgreSQL documentation
   </para>
 
   <para>
-   <application>clusterdb</application> is a shell script wrapper around the
-   backend command
-   <xref linkend="SQL-CLUSTER" endterm="sql-cluster-title"> via
-   the <productname>PostgreSQL</productname> interactive terminal
-   <xref linkend="APP-PSQL">. There is no effective
-   difference between clustering databases via this or other methods.
-   <application>psql</application> must be found by the script and
-   a database server must be running at the targeted host. Also, any default
-   settings and environment variables available to <application>psql</application>
-   and the <application>libpq</application> front-end library do apply.
+   <application>clusterdb</application> is a wrapper around the SQL
+   command <xref linkend="SQL-CLUSTER" endterm="sql-cluster-title">.
+   There is no effective difference between clustering databases via
+   this or other methods.  The database server must be running at the
+   targeted host.  Also, any default settings and environment
+   variables used by the <application>libpq</application> front-end
+   library will apply.
   </para>
 
  </refsect1>
diff --git a/doc/src/sgml/ref/dropuser.sgml b/doc/src/sgml/ref/dropuser.sgml
index d781b2a64f1ca197a74153208c72205dce3813d2..24e8d8ecf45367cb540ed8eafddfdd58c4ba8bf6 100644
--- a/doc/src/sgml/ref/dropuser.sgml
+++ b/doc/src/sgml/ref/dropuser.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/dropuser.sgml,v 1.25 2003/05/26 17:50:09 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/dropuser.sgml,v 1.26 2003/06/18 12:19:11 petere Exp $
 PostgreSQL documentation
 -->
 
@@ -37,13 +37,13 @@ PostgreSQL documentation
   </para>
 
   <para>
-   <application>dropuser</application> is a shell script wrapper
-   around the <acronym>SQL</acronym> command <xref
-   linkend="SQL-DROPUSER" endterm="SQL-DROPUSER-title">.  The database 
-   server must be running on the targeted host. There
-   is nothing special about removing users via this or other
-   methods. Also, any default settings and environment variables
-   used by the <application>libpq</application> front-end library will apply.
+   <application>dropuser</application> is a wrapper around the
+   <acronym>SQL</acronym> command <xref linkend="SQL-DROPUSER"
+   endterm="SQL-DROPUSER-title">.  The database server must be running
+   on the targeted host.  There is nothing special about removing
+   users via this or other methods.  Also, any default settings and
+   environment variables used by the <application>libpq</application>
+   front-end library will apply.
   </para>
  </refsect1>
 
diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml
index 84583e9aea321a1fa118a4ea29ecd65bb4e52e49..e04cf16c3fe17ce3960c842280429f42c6f3fec8 100644
--- a/doc/src/sgml/ref/vacuumdb.sgml
+++ b/doc/src/sgml/ref/vacuumdb.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/vacuumdb.sgml,v 1.28 2003/03/24 14:32:51 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/vacuumdb.sgml,v 1.29 2003/06/18 12:19:11 petere Exp $
 PostgreSQL documentation
 -->
 
@@ -48,16 +48,13 @@ PostgreSQL documentation
   </para>
 
   <para>
-   <application>vacuumdb</application> is a shell script wrapper around the
-   backend command
-   <xref linkend="SQL-VACUUM" endterm="SQL-VACUUM-title"> via
-   the <productname>PostgreSQL</productname> interactive terminal
-   <xref linkend="APP-PSQL">. There is no effective
-   difference between vacuuming databases via this or other methods.
-   <application>psql</application> must be found by the script and
-   a database server must be running at the targeted host. Also, any default
-   settings and environment variables available to <application>psql</application>
-   and the <application>libpq</application> front-end library do apply.
+   <application>vacuumdb</application> is a wrapper around the SQL
+   command <xref linkend="SQL-VACUUM" endterm="SQL-VACUUM-title">.
+   There is no effective difference between vacuuming databases via
+   this or other methods.  The database server must be running at the
+   targeted host.  Also, any default settings and environment
+   variables used by the <application>libpq</application> front-end
+   library will apply.
   </para>
 
 
diff --git a/src/bin/scripts/Makefile b/src/bin/scripts/Makefile
index 79b60940dc6005c295e2c61fb2335acf3eed4f59..66f13c45333db30f6c1058bc9df7ec245d07f99b 100644
--- a/src/bin/scripts/Makefile
+++ b/src/bin/scripts/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/scripts/Makefile,v 1.20 2003/04/16 05:23:55 tgl Exp $
+# $Header: /cvsroot/pgsql/src/bin/scripts/Makefile,v 1.21 2003/06/18 12:19:11 petere Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -13,8 +13,7 @@ subdir = src/bin/scripts
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-SCRIPTS := vacuumdb clusterdb
-PROGRAMS = createdb createlang createuser dropdb droplang dropuser
+PROGRAMS = createdb createlang createuser dropdb droplang dropuser clusterdb vacuumdb
 
 override CPPFLAGS := -I$(top_srcdir)/src/bin/pg_dump -I$(top_srcdir)/src/bin/psql -I$(libpq_srcdir) $(CPPFLAGS)
 
@@ -30,6 +29,8 @@ createuser: createuser.o common.o dumputils.o sprompt.o $(top_builddir)/src/back
 dropdb: dropdb.o common.o dumputils.o sprompt.o $(top_builddir)/src/backend/parser/keywords.o
 droplang: droplang.o common.o sprompt.o print.o mbprint.o
 dropuser: dropuser.o common.o dumputils.o sprompt.o $(top_builddir)/src/backend/parser/keywords.o
+clusterdb: clusterdb.o common.o dumputils.o sprompt.o $(top_builddir)/src/backend/parser/keywords.o
+vacuumdb: vacuumdb.o common.o sprompt.o
 
 dumputils.c sprompt.c : % : $(top_srcdir)/src/bin/pg_dump/%
 	rm -f $@ && $(LN_S) $< .
@@ -49,14 +50,14 @@ install: all installdirs
 	$(INSTALL_PROGRAM) droplang$(X)   $(DESTDIR)$(bindir)/droplang$(X)
 	$(INSTALL_PROGRAM) createuser$(X) $(DESTDIR)$(bindir)/createuser$(X)
 	$(INSTALL_PROGRAM) dropuser$(X)   $(DESTDIR)$(bindir)/dropuser$(X)
-	$(INSTALL_SCRIPT) $(srcdir)/clusterdb $(DESTDIR)$(bindir)/clusterdb
-	$(INSTALL_SCRIPT) $(srcdir)/vacuumdb  $(DESTDIR)$(bindir)/vacuumdb
+	$(INSTALL_PROGRAM) clusterdb$(X)  $(DESTDIR)$(bindir)/clusterdb$(X)
+	$(INSTALL_PROGRAM) vacuumdb$(X)   $(DESTDIR)$(bindir)/vacuumdb$(X)
 
 installdirs:
 	$(mkinstalldirs) $(DESTDIR)$(bindir)
 
 uninstall:
-	rm -f $(addprefix $(DESTDIR)$(bindir)/, $(SCRIPTS) $(addsuffix $(X), $(PROGRAMS)))
+	rm -f $(addprefix $(DESTDIR)$(bindir)/, $(addsuffix $(X), $(PROGRAMS)))
 
 
 clean distclean maintainer-clean:
diff --git a/src/bin/scripts/clusterdb b/src/bin/scripts/clusterdb
deleted file mode 100644
index 70386bf779925245bc17c46aed9be0db7822f719..0000000000000000000000000000000000000000
--- a/src/bin/scripts/clusterdb
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/bin/sh
-#-------------------------------------------------------------------------
-#
-# clusterdb--
-#    cluster a postgres database
-#
-#    This script runs psql with the "-c" option to cluster
-#    the requested database.
-#
-# Copyright (c) 2002, PostgreSQL Global Development Group
-#
-#
-# IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/bin/scripts/Attic/clusterdb,v 1.12 2003/06/11 05:13:12 momjian Exp $
-#
-#-------------------------------------------------------------------------
-
-CMDNAME=`basename "$0"`
-PATHNAME=`echo "$0" | sed "s,$CMDNAME\$,,"`
-
-PSQLOPT=
-table=
-dbname=
-alldb=
-quiet=0
-
-while [ "$#" -gt 0 ]
-do
-	case "$1" in
-	--help|-\?)
-		usage=t
-		break
-		;;
-# options passed on to psql
-	--host|-h)
-		PSQLOPT="$PSQLOPT -h $2"
-		shift;;
-	-h*)
-		PSQLOPT="$PSQLOPT $1"
-		;;
-	--host=*)
-		PSQLOPT="$PSQLOPT -h `echo \"$1\" | sed 's/^--host=//'`"
-		;;
-	--port|-p)
-		PSQLOPT="$PSQLOPT -p $2"
-		shift;;
-	-p*)
-		PSQLOPT="$PSQLOPT $1"
-		;;
-	--port=*)
-		PSQLOPT="$PSQLOPT -p `echo \"$1\" | sed 's/^--port=//'`"
-		;;
-	--username|-U)
-		PSQLOPT="$PSQLOPT -U $2"
-		shift;;
-	-U*)
-		PSQLOPT="$PSQLOPT $1"
-		;;
-	--username=*)
-		PSQLOPT="$PSQLOPT -U `echo \"$1\" | sed 's/^--username=//'`"
-		;;
-	--password|-W)
-		PSQLOPT="$PSQLOPT -W"
-		;;
-	--echo|-e)
-		ECHOOPT="-e"
-		;;
-	--quiet|-q)
-		ECHOOPT="$ECHOOPT -o /dev/null"
-		quiet=1
-		;;
-	--dbname|-d)
-		dbname="$2"
-		shift;;
-	-d*)
-		dbname=`echo $1 | sed 's/^-d//'`
-		;;
-	--dbname=*)
-		dbname=`echo $1 | sed 's/^--dbname=//'`
-		;;
-	-a|--alldb)
-		alldb=1
-		;;
-# options converted into SQL command
-	--table|-t)
-		table="$2"
-		shift;;
-	-t*)
-		table=`echo $1 | sed 's/^-t//'`
-		;;
-	--table=*)
-		table=`echo $1 | sed 's/^--table=//'`
-		;;
-	-*)
-		echo "$CMDNAME: invalid option: $1" 1>&2
-		echo "Try '$CMDNAME --help' for more information." 1>&2
-		exit 1
-		;;
-	*)
-		dbname="$1"
-		if [ "$#" -ne 1 ]; then
-			echo "$CMDNAME: invalid option: $2" 1>&2
-			echo "Try '$CMDNAME --help' for more information." 1>&2
-			exit 1
-		fi
-		;;
-	esac
-	shift
-done
-
-if [ "$usage" ]; then	
-	echo "$CMDNAME cluster all previously clustered tables in a database."
-	echo
-	echo "Usage:"
-	echo "  $CMDNAME [OPTION]... [DBNAME]"
-	echo
-	echo "Options:"
-	echo "  -a, --all                 cluster all databases"
-	echo "  -d, --dbname=DBNAME       database to cluster"
-	echo "  -t, --table='TABLE'       cluster specific table only"
-	echo "  -e, --echo                show the commands sent to the backend"
-	echo "  -q, --quiet               don't write any output"
-	echo "  --help                    show this help, then exit"
-	echo
-	echo "Connection options:"
-	echo "  -h, --host=HOSTNAME       database server host or socket directory"
-	echo "  -p, --port=PORT           database server port"
-	echo "  -U, --username=USERNAME   user name to connect as"
-	echo "  -W, --password            prompt for password"
-	echo
-	echo "Read the description of the SQL command CLUSTER for details."
-	echo
-	echo "Report bugs to <pgsql-bugs@postgresql.org>."
-	exit 0
-fi
-
-if [ "$alldb" ]; then
-	if [ "$dbname" -o "$table" ]; then
-		echo "$CMDNAME: cannot cluster all databases and a specific one at the same time" 1>&2
-		exit 1
-	fi
-	dbname=`${PATHNAME}psql $PSQLOPT -q -t -A -d template1 -c 'SELECT datname FROM pg_database WHERE datallowconn'`
-	[ "$?" -ne 0 ] && exit 1
-
-elif [ -z "$dbname" ]; then
-	if [ "$PGDATABASE" ]; then
-		dbname="$PGDATABASE"
-	elif [ "$PGUSER" ]; then
-		dbname="$PGUSER"
-	else
-		dbname=`${PATHNAME}pg_id -u -n`
-	fi
-	[ "$?" -ne 0 ] && exit 1
-fi
-
-for db in $dbname
-do
-	[ "$alldb" ] && echo "Clustering $db"
-	if [ -z "$table" ]; then
-		${PATHNAME}psql $PSQLOPT $ECHOOPT -c "CLUSTER" -d $db
-		[ "$?" -ne 0 ] && exit 1
-	else
-		${PATHNAME}psql $PSQLOPT $ECHOOPT -c "CLUSTER $table" -d $db
-		[ "$?" -ne 0 ] && exit 1
-	fi
-done
-
-exit 0
diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c
new file mode 100644
index 0000000000000000000000000000000000000000..41cdfc486f9d7abb421eaae4f9a0eb5669bf872f
--- /dev/null
+++ b/src/bin/scripts/clusterdb.c
@@ -0,0 +1,245 @@
+/*-------------------------------------------------------------------------
+ *
+ * clusterdb
+ *
+ * Portions Copyright (c) 2002-2003, PostgreSQL Global Development Group
+ *
+ * $Header: /cvsroot/pgsql/src/bin/scripts/clusterdb.c,v 1.1 2003/06/18 12:19:11 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+#include "common.h"
+#include "dumputils.h"
+
+
+static
+void cluster_one_database(const char *dbname, const char *table,
+						  const char *host, const char *port, const char *username, bool password,
+						  const char *progname, bool echo, bool quiet);
+static
+void cluster_all_databases(const char *host, const char *port, const char *username, bool password,
+						   const char *progname, bool echo, bool quiet);
+
+static void help(const char *progname);
+
+
+int
+main(int argc, char *argv[])
+{
+	static struct option long_options[] = {
+		{"host", required_argument, NULL, 'h'},
+		{"port", required_argument, NULL, 'p'},
+		{"username", required_argument, NULL, 'U'},
+		{"password", no_argument, NULL, 'W'},
+		{"echo", no_argument, NULL, 'e'},
+		{"quiet", no_argument, NULL, 'q'},
+		{"dbname", required_argument, NULL, 'd'},
+		{"all", no_argument, NULL, 'a'},
+		{"table", required_argument, NULL, 't'},
+		{NULL, 0, NULL, 0}
+	};
+
+	char	   *progname;
+	int			optindex;
+	int			c;
+
+	const char *dbname = NULL;
+	char	   *host = NULL;
+	char	   *port = NULL;
+	char	   *username = NULL;
+	bool		password = false;
+	bool		echo = false;
+	bool		quiet = false;
+	bool		alldb = false;
+	char	   *table = NULL;
+
+	progname = get_progname(argv[0]);
+	init_nls();
+	handle_help_version_opts(argc, argv, "clusterdb", help);
+
+	while ((c = getopt_long(argc, argv, "h:p:U:Weqd:at:", long_options, &optindex)) != -1)
+	{
+		switch (c)
+		{
+			case 'h':
+				host = optarg;
+				break;
+			case 'p':
+				port = optarg;
+				break;
+			case 'U':
+				username = optarg;
+				break;
+			case 'W':
+				password = true;
+				break;
+			case 'e':
+				echo = true;
+				break;
+			case 'q':
+				quiet = true;
+				break;
+			case 'd':
+				dbname = optarg;
+				break;
+			case 'a':
+				alldb = true;
+				break;
+			case 't':
+				table = optarg;
+				break;
+			default:
+				fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
+				exit(1);
+		}
+	}
+
+	switch (argc - optind)
+	{
+		case 0:
+			break;
+		case 1:
+			dbname = argv[optind];
+			break;
+		default:
+			fprintf(stderr,	_("%s: too many command-line arguments (first is '%s')\n"),
+					progname, argv[optind + 1]);
+			fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
+			exit(1);
+	}
+
+	if (alldb)
+	{
+		if (dbname)
+		{
+			fprintf(stderr, _("%s: cannot cluster all databases and a specific one at the same time\n"),
+					progname);
+			exit(1);
+		}
+		if (table)
+		{
+			fprintf(stderr, _("%s: cannot cluster a specific table in all databases\n"),
+					progname);
+			exit(1);
+		}
+	
+		cluster_all_databases(host, port, username, password,
+							  progname, echo, quiet);
+	}
+	else
+	{
+		if (dbname == NULL)
+		{
+			if (getenv("PGDATABASE"))
+				dbname = getenv("PGDATABASE");
+			else if (getenv("PGUSER"))
+				dbname = getenv("PGUSER");
+			else
+				dbname = get_user_name(progname);
+		}
+
+		cluster_one_database(dbname, table,
+							 host, port, username, password,
+							 progname, echo, quiet);
+	}
+
+	exit(0);
+}
+
+
+static
+void cluster_one_database(const char *dbname, const char *table,
+						  const char *host, const char *port, const char *username, bool password,
+						  const char *progname, bool echo, bool quiet)
+{
+	PQExpBufferData sql;
+
+	PGconn	   *conn;
+	PGresult   *result;
+
+	initPQExpBuffer(&sql);
+
+	appendPQExpBuffer(&sql, "CLUSTER");
+	if (table)
+		appendPQExpBuffer(&sql, " %s", fmtId(table));
+	appendPQExpBuffer(&sql, ";\n");
+
+	conn = connectDatabase(dbname, host, port, username, password, progname);
+
+	if (echo)
+		printf("%s", sql.data);
+	result = PQexec(conn, sql.data);
+
+	if (PQresultStatus(result) != PGRES_COMMAND_OK)
+	{
+		if (table)
+			fprintf(stderr, _("%s: clustering of table \"%s\" in database \"%s\" failed: %s"),
+					progname, table, dbname, PQerrorMessage(conn));
+		else
+			fprintf(stderr, _("%s: clustering of database \"%s\" failed: %s"),
+					progname, dbname, PQerrorMessage(conn));
+		PQfinish(conn);
+		exit(1);
+	}
+
+	PQclear(result);
+	PQfinish(conn);
+	termPQExpBuffer(&sql);
+
+	if (!quiet)
+		puts("CLUSTER");
+}
+
+
+static
+void cluster_all_databases(const char *host, const char *port, const char *username, bool password,
+						   const char *progname, bool echo, bool quiet)
+{
+	PGconn	   *conn;
+	PGresult   *result;
+	int			i;
+
+	conn = connectDatabase("template1", host, port, username, password, progname);
+	result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn;", progname, echo);
+	PQfinish(conn);
+
+	for (i = 0; i < PQntuples(result); i++)
+	{
+		char	   *dbname = PQgetvalue(result, i, 0);
+
+		if (!quiet)
+			fprintf(stderr, _("%s: clustering database \"%s\"\n"), progname, dbname);
+
+		cluster_one_database(dbname, NULL,
+							 host, port, username, password,
+							 progname, echo, quiet);
+	}
+
+	PQclear(result);
+}
+
+
+static void
+help(const char *progname)
+{
+	printf(_("%s clusters all previously clustered tables in a database.\n"), progname);
+	printf(_("Usage:\n"));
+	printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
+	printf(_("\nOptions:\n"));
+	printf(_("  -a, --all                 cluster all databases\n"));
+	printf(_("  -d, --dbname=DBNAME       database to cluster\n"));
+	printf(_("  -t, --table=TABLE         cluster specific table only"));
+	printf(_("  -e, --echo                show the commands being sent to the server\n"));
+	printf(_("  -q, --quiet               don't write any messages\n"));
+	printf(_("  --help                    show this help, then exit\n"));
+	printf(_("  --version                 output version information, then exit\n"));
+	printf(_("\nConnection options:\n"));
+	printf(_("  -h, --host=HOSTNAME       database server host or socket directory\n"));
+	printf(_("  -p, --port=PORT           database server port\n"));
+	printf(_("  -U, --username=USERNAME   user name to connect as\n"));
+	printf(_("  -W, --password            prompt for password\n"));
+	printf(_("\nRead the description of the SQL command CLUSTER for details.\n"));
+	printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
+}
diff --git a/src/bin/scripts/nls.mk b/src/bin/scripts/nls.mk
index 365b8797274648791cc79431cdab1de0655e1b33..260afe29449472718ad205ac6f4b200c143d1d82 100644
--- a/src/bin/scripts/nls.mk
+++ b/src/bin/scripts/nls.mk
@@ -1,7 +1,8 @@
-# $Header: /cvsroot/pgsql/src/bin/scripts/nls.mk,v 1.1 2003/03/18 22:19:47 petere Exp $
+# $Header: /cvsroot/pgsql/src/bin/scripts/nls.mk,v 1.2 2003/06/18 12:19:11 petere Exp $
 CATALOG_NAME    := pgscripts
 AVAIL_LANGUAGES := 
 GETTEXT_FILES   := createdb.c createlang.c createuser.c \
                    dropdb.c droplang.c dropuser.c \
+                   clusterdb.c vacuumdb.c \
                    common.c
 GETTEXT_TRIGGERS:= _ simple_prompt
diff --git a/src/bin/scripts/vacuumdb b/src/bin/scripts/vacuumdb
deleted file mode 100644
index 7b002a8fb6cc24b62033f1a0afaba848071ac52a..0000000000000000000000000000000000000000
--- a/src/bin/scripts/vacuumdb
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/bin/sh
-#-------------------------------------------------------------------------
-#
-# vacuumdb--
-#    vacuum a postgres database
-#
-#    This script runs psql with the "-c" option to vacuum
-#    the requested database.
-#
-# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
-# Portions Copyright (c) 1994, Regents of the University of California
-#
-#
-# IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/bin/scripts/Attic/vacuumdb,v 1.28 2003/06/11 05:13:12 momjian Exp $
-#
-#-------------------------------------------------------------------------
-
-CMDNAME=`basename "$0"`
-PATHNAME=`echo "$0" | sed "s,$CMDNAME\$,,"`
-
-PSQLOPT=
-full=
-verbose=
-analyze=
-table=
-dbname=
-alldb=
-quiet=0
-
-while [ "$#" -gt 0 ]
-do
-    case "$1" in
-	--help|-\?)
-		usage=t
-                break
-		;;
-# options passed on to psql
-	--host|-h)
-		PSQLOPT="$PSQLOPT -h $2"
-		shift;;
-        -h*)
-                PSQLOPT="$PSQLOPT $1"
-                ;;
-        --host=*)
-                PSQLOPT="$PSQLOPT -h `echo \"$1\" | sed 's/^--host=//'`"
-                ;;
-	--port|-p)
-		PSQLOPT="$PSQLOPT -p $2"
-		shift;;
-        -p*)
-                PSQLOPT="$PSQLOPT $1"
-                ;;
-        --port=*)
-                PSQLOPT="$PSQLOPT -p `echo \"$1\" | sed 's/^--port=//'`"
-                ;;
-	--username|-U)
-		PSQLOPT="$PSQLOPT -U $2"
-		shift;;
-        -U*)
-                PSQLOPT="$PSQLOPT $1"
-                ;;
-        --username=*)
-                PSQLOPT="$PSQLOPT -U `echo \"$1\" | sed 's/^--username=//'`"
-                ;;
-	--password|-W)
-		PSQLOPT="$PSQLOPT -W"
-		;;
-	--echo|-e)
-		ECHOOPT="-e"
-		;;
-	--quiet|-q)
-		ECHOOPT="$ECHOOPT -o /dev/null"
-                quiet=1
-		;;
-	--dbname|-d)
-		dbname="$2"
-		shift;;
-        -d*)
-                dbname=`echo $1 | sed 's/^-d//'`
-                ;;
-        --dbname=*)
-                dbname=`echo $1 | sed 's/^--dbname=//'`
-                ;;
-# options converted into SQL command
-	--analyze|-z)
-		analyze="ANALYZE"
-		;;
-	--all|-a)
-		alldb=Y
-		;;
-	--table|-t)
-		table="$2"
-		shift;;
-        -t*)
-                table=`echo $1 | sed 's/^-t//'`
-                ;;
-        --table=*)
-                table=`echo $1 | sed 's/^--table=//'`
-                ;;
-	--full|-f)
-		full="FULL"
-		;;
-	--verbose|-v)
-		verbose="VERBOSE"
-		;;
-
-	-*)
-		echo "$CMDNAME: invalid option: $1" 1>&2
-                echo "Try '$CMDNAME --help' for more information." 1>&2
-		exit 1
-		;;
-	*)
-		dbname="$1"
-		if [ "$#" -ne 1 ]; then
-			echo "$CMDNAME: invalid option: $2" 1>&2
-	                echo "Try '$CMDNAME --help' for more information." 1>&2
-			exit 1
-		fi
-		;;
-    esac
-    shift
-done
-
-if [ "$usage" ]; then	
-        echo "$CMDNAME cleans and analyzes a PostgreSQL database."
-        echo
-	echo "Usage:"
-        echo "  $CMDNAME [OPTION]... [DBNAME]"
-	echo
-        echo "Options:"
-	echo "  -a, --all                       vacuum all databases"
-	echo "  -d, --dbname=DBNAME             database to vacuum"
-	echo "  -t, --table='TABLE[(columns)]'  vacuum specific table only"
-	echo "  -f, --full                      do full vacuuming"
-	echo "  -z, --analyze                   update optimizer hints"
-	echo "  -e, --echo                      show the command being sent to the backend"
-        echo "  -q, --quiet                     don't write any output"
-	echo "  -v, --verbose                   write a lot of output"
-	echo " --help                           show this help, then exit"
-	echo
-	echo "Connection options:"
-	echo "  -h, --host=HOSTNAME             database server host or socket directory"
-	echo "  -p, --port=PORT                 database server port"
-	echo "  -U, --username=USERNAME         user name to connect as"
-	echo "  -W, --password                  prompt for password"
-        echo
-        echo "Read the description of the SQL command VACUUM for details."
-        echo
-	echo "Report bugs to <pgsql-bugs@postgresql.org>."
-	exit 0
-fi
-
-if [ "$alldb" ]; then
-        if [ "$dbname" -o "$table" ]; then
-                echo "$CMDNAME: cannot vacuum all databases and a specific one at the same time" 1>&2
-                exit 1
-        fi
-	dbname=`${PATHNAME}psql $PSQLOPT -q -t -A -d template1 -c 'SELECT datname FROM pg_database WHERE datallowconn'`
-
-elif [ -z "$dbname" ]; then
-        if [ "$PGDATABASE" ]; then
-                dbname="$PGDATABASE"
-        elif [ "$PGUSER" ]; then
-                dbname="$PGUSER"
-        else
-                dbname=`${PATHNAME}pg_id -u -n`
-        fi
-        [ "$?" -ne 0 ] && exit 1
-fi
-
-for db in $dbname
-do
-        [ "$alldb" -a "$quiet" -ne 1 ] && echo "Vacuuming $db"
-	${PATHNAME}psql $PSQLOPT $ECHOOPT -c "VACUUM $full $verbose $analyze $table" -d $db
-	if [ "$?" -ne 0 ]; then
-	    echo "$CMDNAME: vacuum $table $db failed" 1>&2
-	    exit 1
-	fi
-done
-
-exit 0
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
new file mode 100644
index 0000000000000000000000000000000000000000..88729ef236d8bdd0a0e2e11871125f50fdbcfbd5
--- /dev/null
+++ b/src/bin/scripts/vacuumdb.c
@@ -0,0 +1,272 @@
+/*-------------------------------------------------------------------------
+ *
+ * vacuumdb
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Header: /cvsroot/pgsql/src/bin/scripts/vacuumdb.c,v 1.1 2003/06/18 12:19:11 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+#include "common.h"
+
+
+static
+void vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze, const char *table,
+						 const char *host, const char *port, const char *username, bool password,
+						 const char *progname, bool echo, bool quiet);
+static
+void vacuum_all_databases(bool full, bool verbose, bool analyze,
+						  const char *host, const char *port, const char *username, bool password,
+						  const char *progname, bool echo, bool quiet);
+
+static void help(const char *progname);
+
+
+int
+main(int argc, char *argv[])
+{
+	static struct option long_options[] = {
+		{"host", required_argument, NULL, 'h'},
+		{"port", required_argument, NULL, 'p'},
+		{"username", required_argument, NULL, 'U'},
+		{"password", no_argument, NULL, 'W'},
+		{"echo", no_argument, NULL, 'e'},
+		{"quiet", no_argument, NULL, 'q'},
+		{"dbname", required_argument, NULL, 'd'},
+		{"analyze", no_argument, NULL, 'z'},
+		{"all", no_argument, NULL, 'a'},
+		{"table", required_argument, NULL, 't'},
+		{"full", no_argument, NULL, 'f'},
+		{"verbose", no_argument, NULL, 'v'},
+		{NULL, 0, NULL, 0}
+	};
+
+	char	   *progname;
+	int			optindex;
+	int			c;
+
+	const char *dbname = NULL;
+	char	   *host = NULL;
+	char	   *port = NULL;
+	char	   *username = NULL;
+	bool		password = false;
+	bool		echo = false;
+	bool		quiet = false;
+	bool		analyze = false;
+	bool		alldb = false;
+	char	   *table = NULL;
+	bool		full = false;
+	bool		verbose = false;
+
+	progname = get_progname(argv[0]);
+	init_nls();
+	handle_help_version_opts(argc, argv, "vacuumdb", help);
+
+	while ((c = getopt_long(argc, argv, "h:p:U:Weqd:zat:fv", long_options, &optindex)) != -1)
+	{
+		switch (c)
+		{
+			case 'h':
+				host = optarg;
+				break;
+			case 'p':
+				port = optarg;
+				break;
+			case 'U':
+				username = optarg;
+				break;
+			case 'W':
+				password = true;
+				break;
+			case 'e':
+				echo = true;
+				break;
+			case 'q':
+				quiet = true;
+				break;
+			case 'd':
+				dbname = optarg;
+				break;
+			case 'z':
+				analyze = true;
+				break;
+			case 'a':
+				alldb = true;
+				break;
+			case 't':
+				table = optarg;
+				break;
+			case 'f':
+				full = true;
+				break;
+			case 'v':
+				verbose = true;
+				break;
+			default:
+				fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
+				exit(1);
+		}
+	}
+
+	switch (argc - optind)
+	{
+		case 0:
+			break;
+		case 1:
+			dbname = argv[optind];
+			break;
+		default:
+			fprintf(stderr,	_("%s: too many command-line arguments (first is '%s')\n"),
+					progname, argv[optind + 1]);
+			fprintf(stderr, _("Try '%s --help' for more information.\n"), progname);
+			exit(1);
+	}
+
+	if (alldb)
+	{
+		if (dbname)
+		{
+			fprintf(stderr, _("%s: cannot vacuum all databases and a specific one at the same time\n"),
+					progname);
+			exit(1);
+		}
+		if (table)
+		{
+			fprintf(stderr, _("%s: cannot vacuum a specific table in all databases\n"),
+					progname);
+			exit(1);
+		}
+	
+		vacuum_all_databases(full, verbose, analyze,
+							 host, port, username, password,
+							 progname, echo, quiet);
+	}
+	else
+	{
+		if (dbname == NULL)
+		{
+			if (getenv("PGDATABASE"))
+				dbname = getenv("PGDATABASE");
+			else if (getenv("PGUSER"))
+				dbname = getenv("PGUSER");
+			else
+				dbname = get_user_name(progname);
+		}
+
+		vacuum_one_database(dbname, full, verbose, analyze, table,
+							host, port, username, password,
+							progname, echo, quiet);
+	}
+
+	exit(0);
+}
+
+
+static
+void vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze, const char *table,
+						 const char *host, const char *port, const char *username, bool password,
+						 const char *progname, bool echo, bool quiet)
+{
+	PQExpBufferData sql;
+
+	PGconn	   *conn;
+	PGresult   *result;
+
+	initPQExpBuffer(&sql);
+
+	appendPQExpBuffer(&sql, "VACUUM");
+	if (full)
+		appendPQExpBuffer(&sql, " FULL");
+	if (verbose)
+		appendPQExpBuffer(&sql, " VERBOSE");
+	if (analyze)
+		appendPQExpBuffer(&sql, " ANALYZE");
+	if (table)
+		appendPQExpBuffer(&sql, " %s", table);
+	appendPQExpBuffer(&sql, ";\n");
+
+	conn = connectDatabase(dbname, host, port, username, password, progname);
+
+	if (echo)
+		printf("%s", sql.data);
+	result = PQexec(conn, sql.data);
+
+	if (PQresultStatus(result) != PGRES_COMMAND_OK)
+	{
+		if (table)
+			fprintf(stderr, _("%s: vacuuming of table \"%s\" in database \"%s\" failed: %s"),
+					progname, table, dbname, PQerrorMessage(conn));
+		else
+			fprintf(stderr, _("%s: vacuuming of database \"%s\" failed: %s"),
+					progname, dbname, PQerrorMessage(conn));
+		PQfinish(conn);
+		exit(1);
+	}
+
+	PQclear(result);
+	PQfinish(conn);
+	termPQExpBuffer(&sql);
+
+	if (!quiet)
+		puts("VACUUM");
+}
+
+
+static
+void vacuum_all_databases(bool full, bool verbose, bool analyze,
+						  const char *host, const char *port, const char *username, bool password,
+						  const char *progname, bool echo, bool quiet)
+{
+	PGconn	   *conn;
+	PGresult   *result;
+	int			i;
+
+	conn = connectDatabase("template1", host, port, username, password, progname);
+	result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn;", progname, echo);
+	PQfinish(conn);
+
+	for (i = 0; i < PQntuples(result); i++)
+	{
+		char	   *dbname = PQgetvalue(result, i, 0);
+
+		if (!quiet)
+			fprintf(stderr, _("%s: vacuuming database \"%s\"\n"), progname, dbname);
+
+		vacuum_one_database(dbname, full, verbose, analyze, NULL,
+							host, port, username, password,
+							progname, echo, quiet);
+	}
+
+	PQclear(result);
+}
+
+
+static void
+help(const char *progname)
+{
+	printf(_("%s cleans and analyzes a PostgreSQL database.\n\n"), progname);
+	printf(_("Usage:\n"));
+	printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
+	printf(_("\nOptions:\n"));
+	printf(_("  -a, --all                       vacuum all databases\n"));
+	printf(_("  -d, --dbname=DBNAME             database to vacuum\n"));
+	printf(_("  -t, --table='TABLE[(COLUMNS)]'  vacuum specific table only\n"));
+	printf(_("  -f, --full                      do full vacuuming\n"));
+	printf(_("  -z, --analyze                   update optimizer hints\n"));
+	printf(_("  -e, --echo                      show the commands being sent to the server\n"));
+	printf(_("  -q, --quiet                     don't write any messages\n"));
+	printf(_("  -v, --verbose                   write a lot of output\n"));
+	printf(_("  --help                          show this help, then exit\n"));
+	printf(_("  --version                       output version information, then exit\n"));
+	printf(_("\nConnection options:\n"));
+	printf(_("  -h, --host=HOSTNAME       database server host or socket directory\n"));
+	printf(_("  -p, --port=PORT           database server port\n"));
+	printf(_("  -U, --username=USERNAME   user name to connect as\n"));
+	printf(_("  -W, --password            prompt for password\n"));
+	printf(_("\nRead the description of the SQL command VACUUM for details.\n"));
+	printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
+}