Change clusterdb and vacuumdb into C programs.
authorPeter Eisentraut <peter_e@gmx.net>
Wed, 18 Jun 2003 12:19:11 +0000 (12:19 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Wed, 18 Jun 2003 12:19:11 +0000 (12:19 +0000)
doc/src/sgml/maintenance.sgml
doc/src/sgml/ref/clusterdb.sgml
doc/src/sgml/ref/dropuser.sgml
doc/src/sgml/ref/vacuumdb.sgml
src/bin/scripts/Makefile
src/bin/scripts/clusterdb [deleted file]
src/bin/scripts/clusterdb.c [new file with mode: 0644]
src/bin/scripts/nls.mk
src/bin/scripts/vacuumdb [deleted file]
src/bin/scripts/vacuumdb.c [new file with mode: 0644]

index 353b8cf2f361ad4d1a908d109794d758de21ebe7..122137ad2b9654c9e97a8834836043c53456b34c 100644 (file)
@@ -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>
index 4200481c1da60fe5aa22b157276453a5a7eecc27..eb8142618764a9d40cb4d319f478116abf5c6d73 100644 (file)
@@ -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>
index d781b2a64f1ca197a74153208c72205dce3813d2..24e8d8ecf45367cb540ed8eafddfdd58c4ba8bf6 100644 (file)
@@ -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>
 
index 84583e9aea321a1fa118a4ea29ecd65bb4e52e49..e04cf16c3fe17ce3960c842280429f42c6f3fec8 100644 (file)
@@ -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>
 
 
index 79b60940dc6005c295e2c61fb2335acf3eed4f59..66f13c45333db30f6c1058bc9df7ec245d07f99b 100644 (file)
@@ -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 (file)
index 70386bf..0000000
+++ /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 (file)
index 0000000..41cdfc4
--- /dev/null
@@ -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"));
+}
index 365b8797274648791cc79431cdab1de0655e1b33..260afe29449472718ad205ac6f4b200c143d1d82 100644 (file)
@@ -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 (file)
index 7b002a8..0000000
+++ /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 (file)
index 0000000..88729ef
--- /dev/null
@@ -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"));
+}