Make command-line tools smarter about finding a DB to connect to.

If unable to connect to "postgres", try "template1".  This allows things to
work more smoothly in the case where the postgres database has been
dropped.  And just in case that's not good enough, also allow the user to
specify a maintenance database to be used for the initial connection, to
cover the case where neither postgres nor template1 is suitable.
This commit is contained in:
Robert Haas 2011-12-06 08:48:15 -05:00
parent 6ef4ae1d4e
commit 68281e0054
16 changed files with 188 additions and 36 deletions

View File

@ -229,6 +229,18 @@ PostgreSQL documentation
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--maintenance-db=<replaceable class="parameter">dbname</replaceable></></term>
<listitem>
<para>
Specifies the name of the database to connect to discover what other
databases should be clustered. If not specified, the
<literal>postgres</literal> database will be used,
and if that does not exist, <literal>template1</literal> will be used.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>

View File

@ -276,6 +276,19 @@ PostgreSQL documentation
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--maintenance-db=<replaceable class="parameter">dbname</replaceable></></term>
<listitem>
<para>
Specifies the name of the database to connect to when creating the
new database. If not specified, the <literal>postgres</literal>
database will be used; if that does not exist (or if it is the name
of the new database being created), <literal>template1</literal> will
be used.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>

View File

@ -196,6 +196,18 @@ PostgreSQL documentation
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--maintenance-db=<replaceable class="parameter">dbname</replaceable></></term>
<listitem>
<para>
Specifies the name of the database to connect to in order to drop the
target database. If not specified, the <literal>postgres</literal>
database will be used; if that does not exist (or is the database
being dropped), <literal>template1</literal> will be used.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>

View File

@ -243,6 +243,18 @@ PostgreSQL documentation
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--maintenance-db=<replaceable class="parameter">dbname</replaceable></></term>
<listitem>
<para>
Specifies the name of the database to connect to discover what other
databases should be vacuumed. If not specified, the
<literal>postgres</literal> database will be used,
and if that does not exist, <literal>template1</literal> will be used.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>

View File

@ -284,6 +284,18 @@ PostgreSQL documentation
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--maintenance-db=<replaceable class="parameter">dbname</replaceable></></term>
<listitem>
<para>
Specifies the name of the database to connect to discover what other
databases should be vacuumed. If not specified, the
<literal>postgres</literal> database will be used,
and if that does not exist, <literal>template1</literal> will be used.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>

View File

@ -18,7 +18,8 @@ static void cluster_one_database(const char *dbname, bool verbose, const char *t
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo);
static void cluster_all_databases(bool verbose, const char *host, const char *port,
static void cluster_all_databases(bool verbose, const char *maintenance_db,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo, bool quiet);
@ -40,6 +41,7 @@ main(int argc, char *argv[])
{"all", no_argument, NULL, 'a'},
{"table", required_argument, NULL, 't'},
{"verbose", no_argument, NULL, 'v'},
{"maintenance-db", required_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
@ -48,6 +50,7 @@ main(int argc, char *argv[])
int c;
const char *dbname = NULL;
const char *maintenance_db = NULL;
char *host = NULL;
char *port = NULL;
char *username = NULL;
@ -100,6 +103,9 @@ main(int argc, char *argv[])
case 'v':
verbose = true;
break;
case 2:
maintenance_db = optarg;
break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
@ -137,7 +143,7 @@ main(int argc, char *argv[])
exit(1);
}
cluster_all_databases(verbose, host, port, username, prompt_password,
cluster_all_databases(verbose, maintenance_db, host, port, username, prompt_password,
progname, echo, quiet);
}
else
@ -180,7 +186,8 @@ cluster_one_database(const char *dbname, bool verbose, const char *table,
appendPQExpBuffer(&sql, " %s", table);
appendPQExpBuffer(&sql, ";\n");
conn = connectDatabase(dbname, host, port, username, prompt_password, progname);
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false);
if (!executeMaintenanceCommand(conn, sql.data, echo))
{
if (table)
@ -198,7 +205,8 @@ cluster_one_database(const char *dbname, bool verbose, const char *table,
static void
cluster_all_databases(bool verbose, const char *host, const char *port,
cluster_all_databases(bool verbose, const char *maintenance_db,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo, bool quiet)
{
@ -206,7 +214,8 @@ cluster_all_databases(bool verbose, const char *host, const char *port,
PGresult *result;
int i;
conn = connectDatabase("postgres", host, port, username, prompt_password, progname);
conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
prompt_password, progname);
result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo);
PQfinish(conn);
@ -250,6 +259,7 @@ help(const char *progname)
printf(_(" -U, --username=USERNAME user name to connect as\n"));
printf(_(" -w, --no-password never prompt for password\n"));
printf(_(" -W, --password force password prompt\n"));
printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
printf(_("\nRead the description of the SQL command CLUSTER for details.\n"));
printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
}

View File

@ -93,7 +93,7 @@ handle_help_version_opts(int argc, char *argv[],
PGconn *
connectDatabase(const char *dbname, const char *pghost, const char *pgport,
const char *pguser, enum trivalue prompt_password,
const char *progname)
const char *progname, bool fail_ok)
{
PGconn *conn;
char *password = NULL;
@ -163,6 +163,11 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) == CONNECTION_BAD)
{
if (fail_ok)
{
PQfinish(conn);
return NULL;
}
fprintf(stderr, _("%s: could not connect to database %s: %s"),
progname, dbname, PQerrorMessage(conn));
exit(1);
@ -171,6 +176,41 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
return conn;
}
/*
* Try to connect to the appropriate maintenance database.
*/
PGconn *
connectMaintenanceDatabase(const char *maintenance_db, const char *pghost,
const char *pgport, const char *pguser,
enum trivalue prompt_password,
const char *progname)
{
PGconn *conn;
/* If a maintenance database name was specified, just connect to it. */
if (maintenance_db)
return connectDatabase(maintenance_db, pghost, pgport, pguser,
prompt_password, progname, false);
/* Otherwise, try postgres first and then template1. */
conn = connectDatabase("postgres", pghost, pgport, pguser, prompt_password,
progname, true);
if (!conn)
conn = connectDatabase("template1", pghost, pgport, pguser,
prompt_password, progname, true);
if (!conn)
{
fprintf(stderr, _("%s: could not connect to databases \"postgres\" or \"template1\"\n"
"Please specify an alternative maintenance database.\n"),
progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
return conn;
}
/*
* Run a query, return the results, exit program on failure.

View File

@ -30,6 +30,11 @@ extern void handle_help_version_opts(int argc, char *argv[],
extern PGconn *connectDatabase(const char *dbname, const char *pghost,
const char *pgport, const char *pguser,
enum trivalue prompt_password, const char *progname,
bool fail_ok);
extern PGconn *connectMaintenanceDatabase(const char *maintenance_db,
const char *pghost, const char *pgport, const char *pguser,
enum trivalue prompt_password, const char *progname);
extern PGresult *executeQuery(PGconn *conn, const char *query,

View File

@ -35,6 +35,7 @@ main(int argc, char *argv[])
{"lc-collate", required_argument, NULL, 1},
{"lc-ctype", required_argument, NULL, 2},
{"locale", required_argument, NULL, 'l'},
{"maintenance-db", required_argument, NULL, 3},
{NULL, 0, NULL, 0}
};
@ -43,6 +44,7 @@ main(int argc, char *argv[])
int c;
const char *dbname = NULL;
const char *maintenance_db = NULL;
char *comment = NULL;
char *host = NULL;
char *port = NULL;
@ -110,6 +112,9 @@ main(int argc, char *argv[])
case 'l':
locale = optarg;
break;
case 3:
maintenance_db = optarg;
break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
@ -192,13 +197,12 @@ main(int argc, char *argv[])
appendPQExpBuffer(&sql, ";\n");
/*
* Connect to the 'postgres' database by default, except have the
* 'postgres' user use 'template1' so he can create the 'postgres'
* database.
*/
conn = connectDatabase(strcmp(dbname, "postgres") == 0 ? "template1" : "postgres",
host, port, username, prompt_password, progname);
/* No point in trying to use postgres db when creating postgres db. */
if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0)
maintenance_db = "template1";
conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
prompt_password, progname);
if (echo)
printf("%s", sql.data);
@ -264,6 +268,7 @@ help(const char *progname)
printf(_(" -U, --username=USERNAME user name to connect as\n"));
printf(_(" -w, --no-password never prompt for password\n"));
printf(_(" -W, --password force password prompt\n"));
printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
printf(_("\nBy default, a database with the same name as the current user is created.\n"));
printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
}

View File

@ -132,7 +132,7 @@ main(int argc, char *argv[])
static const bool translate_columns[] = {false, true};
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname);
progname, false);
printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
@ -169,7 +169,8 @@ main(int argc, char *argv[])
if (*p >= 'A' && *p <= 'Z')
*p += ('a' - 'A');
conn = connectDatabase(dbname, host, port, username, prompt_password, progname);
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false);
/*
* Make sure the language isn't already installed

View File

@ -230,7 +230,8 @@ main(int argc, char *argv[])
if (login == 0)
login = TRI_YES;
conn = connectDatabase("postgres", host, port, username, prompt_password, progname);
conn = connectDatabase("postgres", host, port, username, prompt_password,
progname, false);
initPQExpBuffer(&sql);

View File

@ -32,6 +32,7 @@ main(int argc, char *argv[])
{"echo", no_argument, NULL, 'e'},
{"interactive", no_argument, NULL, 'i'},
{"if-exists", no_argument, &if_exists, 1},
{"maintenance-db", required_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
@ -40,6 +41,7 @@ main(int argc, char *argv[])
int c;
char *dbname = NULL;
char *maintenance_db = NULL;
char *host = NULL;
char *port = NULL;
char *username = NULL;
@ -85,6 +87,9 @@ main(int argc, char *argv[])
case 0:
/* this covers the long options */
break;
case 2:
maintenance_db = optarg;
break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
@ -119,11 +124,11 @@ main(int argc, char *argv[])
appendPQExpBuffer(&sql, "DROP DATABASE %s%s;\n",
(if_exists ? "IF EXISTS " : ""), fmtId(dbname));
/*
* Connect to the 'postgres' database by default, except have the
* 'postgres' user use 'template1' so he can drop the 'postgres' database.
*/
conn = connectDatabase(strcmp(dbname, "postgres") == 0 ? "template1" : "postgres",
/* Avoid trying to drop postgres db while we are connected to it. */
if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0)
maintenance_db = "template1";
conn = connectMaintenanceDatabase(maintenance_db,
host, port, username, prompt_password, progname);
if (echo)
@ -161,5 +166,6 @@ help(const char *progname)
printf(_(" -U, --username=USERNAME user name to connect as\n"));
printf(_(" -w, --no-password never prompt for password\n"));
printf(_(" -W, --password force password prompt\n"));
printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
}

View File

@ -131,7 +131,7 @@ main(int argc, char *argv[])
static const bool translate_columns[] = {false, true};
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname);
progname, false);
printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
@ -170,7 +170,8 @@ main(int argc, char *argv[])
if (*p >= 'A' && *p <= 'Z')
*p += ('a' - 'A');
conn = connectDatabase(dbname, host, port, username, prompt_password, progname);
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false);
/*
* Force schema search path to be just pg_catalog, so that we don't have

View File

@ -119,7 +119,8 @@ main(int argc, char *argv[])
appendPQExpBuffer(&sql, "DROP ROLE %s%s;\n",
(if_exists ? "IF EXISTS " : ""), fmtId(dropuser));
conn = connectDatabase("postgres", host, port, username, prompt_password, progname);
conn = connectDatabase("postgres", host, port, username, prompt_password,
progname, false);
if (echo)
printf("%s", sql.data);

View File

@ -19,7 +19,8 @@ static void reindex_one_database(const char *name, const char *dbname,
const char *port, const char *username,
enum trivalue prompt_password, const char *progname,
bool echo);
static void reindex_all_databases(const char *host, const char *port,
static void reindex_all_databases(const char *maintenance_db,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo,
bool quiet);
@ -45,6 +46,7 @@ main(int argc, char *argv[])
{"system", no_argument, NULL, 's'},
{"table", required_argument, NULL, 't'},
{"index", required_argument, NULL, 'i'},
{"maintenance-db", required_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
@ -53,6 +55,7 @@ main(int argc, char *argv[])
int c;
const char *dbname = NULL;
const char *maintenance_db = NULL;
const char *host = NULL;
const char *port = NULL;
const char *username = NULL;
@ -110,6 +113,9 @@ main(int argc, char *argv[])
case 'i':
index = optarg;
break;
case 2:
maintenance_db = optarg;
break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
@ -154,8 +160,8 @@ main(int argc, char *argv[])
exit(1);
}
reindex_all_databases(host, port, username, prompt_password,
progname, echo, quiet);
reindex_all_databases(maintenance_db, host, port, username,
prompt_password, progname, echo, quiet);
}
else if (syscatalog)
{
@ -230,7 +236,8 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
appendPQExpBuffer(&sql, " DATABASE %s", fmtId(name));
appendPQExpBuffer(&sql, ";\n");
conn = connectDatabase(dbname, host, port, username, prompt_password, progname);
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false);
if (!executeMaintenanceCommand(conn, sql.data, echo))
{
@ -252,7 +259,8 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
}
static void
reindex_all_databases(const char *host, const char *port,
reindex_all_databases(const char *maintenance_db,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo, bool quiet)
{
@ -260,7 +268,8 @@ reindex_all_databases(const char *host, const char *port,
PGresult *result;
int i;
conn = connectDatabase("postgres", host, port, username, prompt_password, progname);
conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
prompt_password, progname);
result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo);
PQfinish(conn);
@ -294,7 +303,8 @@ reindex_system_catalogs(const char *dbname, const char *host, const char *port,
appendPQExpBuffer(&sql, "REINDEX SYSTEM %s;\n", dbname);
conn = connectDatabase(dbname, host, port, username, prompt_password, progname);
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false);
if (!executeMaintenanceCommand(conn, sql.data, echo))
{
fprintf(stderr, _("%s: reindexing of system catalogs failed: %s"),
@ -328,6 +338,7 @@ help(const char *progname)
printf(_(" -U, --username=USERNAME user name to connect as\n"));
printf(_(" -w, --no-password never prompt for password\n"));
printf(_(" -W, --password force password prompt\n"));
printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
printf(_("\nRead the description of the SQL command REINDEX for details.\n"));
printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
}

View File

@ -21,6 +21,7 @@ static void vacuum_one_database(const char *dbname, bool full, bool verbose,
const char *progname, bool echo);
static void vacuum_all_databases(bool full, bool verbose, bool and_analyze,
bool analyze_only, bool freeze,
const char *maintenance_db,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo, bool quiet);
@ -47,6 +48,7 @@ main(int argc, char *argv[])
{"table", required_argument, NULL, 't'},
{"full", no_argument, NULL, 'f'},
{"verbose", no_argument, NULL, 'v'},
{"maintenance-db", required_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
@ -55,6 +57,7 @@ main(int argc, char *argv[])
int c;
const char *dbname = NULL;
const char *maintenance_db = NULL;
char *host = NULL;
char *port = NULL;
char *username = NULL;
@ -123,6 +126,9 @@ main(int argc, char *argv[])
case 'v':
verbose = true;
break;
case 2:
maintenance_db = optarg;
break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
@ -178,8 +184,8 @@ main(int argc, char *argv[])
}
vacuum_all_databases(full, verbose, and_analyze, analyze_only, freeze,
host, port, username, prompt_password,
progname, echo, quiet);
maintenance_db, host, port, username,
prompt_password, progname, echo, quiet);
}
else
{
@ -216,7 +222,8 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool and_analyz
initPQExpBuffer(&sql);
conn = connectDatabase(dbname, host, port, username, prompt_password, progname);
conn = connectDatabase(dbname, host, port, username, prompt_password,
progname, false);
if (analyze_only)
{
@ -290,7 +297,8 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool and_analyz
static void
vacuum_all_databases(bool full, bool verbose, bool and_analyze, bool analyze_only,
bool freeze, const char *host, const char *port,
bool freeze, const char *maintenance_db,
const char *host, const char *port,
const char *username, enum trivalue prompt_password,
const char *progname, bool echo, bool quiet)
{
@ -298,7 +306,8 @@ vacuum_all_databases(bool full, bool verbose, bool and_analyze, bool analyze_onl
PGresult *result;
int i;
conn = connectDatabase("postgres", host, port, username, prompt_password, progname);
conn = connectMaintenanceDatabase(maintenance_db, host, port,
username, prompt_password, progname);
result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo);
PQfinish(conn);
@ -346,6 +355,7 @@ help(const char *progname)
printf(_(" -U, --username=USERNAME user name to connect as\n"));
printf(_(" -w, --no-password never prompt for password\n"));
printf(_(" -W, --password force password prompt\n"));
printf(_(" --maintenance-db=DBNAME alternate maintenance database\n"));
printf(_("\nRead the description of the SQL command VACUUM for details.\n"));
printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
}