postgresql/src/bin/scripts/clusterdb.c
Tom Lane 6f7fc0bade Cause initdb to create a third standard database "postgres", which
unlike template0 and template1 does not have any special status in
terms of backend functionality.  However, all external utilities such
as createuser and createdb now connect to "postgres" instead of
template1, and the documentation is changed to encourage people to use
"postgres" instead of template1 as a play area.  This should fix some
longstanding gotchas involving unexpected propagation of database
objects by createdb (when you used template1 without understanding
the implications), as well as ameliorating the problem that CREATE
DATABASE is unhappy if anyone else is connected to template1.
Patch by Dave Page, minor editing by Tom Lane.  All per recent
pghackers discussions.
2005-06-21 04:02:34 +00:00

252 lines
6.2 KiB
C

/*-------------------------------------------------------------------------
*
* clusterdb
*
* Portions Copyright (c) 2002-2005, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/bin/scripts/clusterdb.c,v 1.13 2005/06/21 04:02:33 tgl 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}
};
const 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]);
set_pglocale_pgservice(argv[0], "pgscripts");
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");
fflush(stdout);
}
}
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("postgres", 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\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\n"));
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"));
}