diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml index 353b8cf2f3..122137ad2b 100644 --- a/doc/src/sgml/maintenance.sgml +++ b/doc/src/sgml/maintenance.sgml @@ -1,5 +1,5 @@ @@ -136,7 +136,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/maintenance.sgml,v 1.22 2003/03/25 16:15:37 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 vacuumdb script may be helpful.) + vacuum each one; the program vacuumdb may be helpful.) Use plain VACUUM, not VACUUM FULL, for routine vacuuming for space recovery. diff --git a/doc/src/sgml/ref/clusterdb.sgml b/doc/src/sgml/ref/clusterdb.sgml index 4200481c1d..eb81426187 100644 --- a/doc/src/sgml/ref/clusterdb.sgml +++ b/doc/src/sgml/ref/clusterdb.sgml @@ -1,5 +1,5 @@ @@ -41,16 +41,13 @@ PostgreSQL documentation - clusterdb is a shell script wrapper around the - backend command - via - the PostgreSQL interactive terminal - . There is no effective - difference between clustering databases via this or other methods. - psql 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 psql - and the libpq front-end library do apply. + clusterdb is a wrapper around the SQL + command . + 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 libpq front-end + library will apply. diff --git a/doc/src/sgml/ref/dropuser.sgml b/doc/src/sgml/ref/dropuser.sgml index d781b2a64f..24e8d8ecf4 100644 --- a/doc/src/sgml/ref/dropuser.sgml +++ b/doc/src/sgml/ref/dropuser.sgml @@ -1,5 +1,5 @@ @@ -37,13 +37,13 @@ PostgreSQL documentation - dropuser is a shell script wrapper - around the SQL command . 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 libpq front-end library will apply. + dropuser is a wrapper around the + SQL command . 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 libpq + front-end library will apply. diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml index 84583e9aea..e04cf16c3f 100644 --- a/doc/src/sgml/ref/vacuumdb.sgml +++ b/doc/src/sgml/ref/vacuumdb.sgml @@ -1,5 +1,5 @@ @@ -48,16 +48,13 @@ PostgreSQL documentation - vacuumdb is a shell script wrapper around the - backend command - via - the PostgreSQL interactive terminal - . There is no effective - difference between vacuuming databases via this or other methods. - psql 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 psql - and the libpq front-end library do apply. + vacuumdb is a wrapper around the SQL + command . + 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 libpq front-end + library will apply. diff --git a/src/bin/scripts/Makefile b/src/bin/scripts/Makefile index 79b60940dc..66f13c4533 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 70386bf779..0000000000 --- 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 ." - 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 0000000000..41cdfc486f --- /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 .\n")); +} diff --git a/src/bin/scripts/nls.mk b/src/bin/scripts/nls.mk index 365b879727..260afe2944 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 7b002a8fb6..0000000000 --- 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 ." - 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 0000000000..88729ef236 --- /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 .\n")); +}