From 68281e00540a29e7f9bfc154c25a78b875f560d1 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Tue, 6 Dec 2011 08:48:15 -0500 Subject: [PATCH] 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. --- doc/src/sgml/ref/clusterdb.sgml | 12 ++++++++++ doc/src/sgml/ref/createdb.sgml | 13 ++++++++++ doc/src/sgml/ref/dropdb.sgml | 12 ++++++++++ doc/src/sgml/ref/reindexdb.sgml | 12 ++++++++++ doc/src/sgml/ref/vacuumdb.sgml | 12 ++++++++++ src/bin/scripts/clusterdb.c | 20 ++++++++++++---- src/bin/scripts/common.c | 42 ++++++++++++++++++++++++++++++++- src/bin/scripts/common.h | 5 ++++ src/bin/scripts/createdb.c | 19 +++++++++------ src/bin/scripts/createlang.c | 5 ++-- src/bin/scripts/createuser.c | 3 ++- src/bin/scripts/dropdb.c | 16 +++++++++---- src/bin/scripts/droplang.c | 5 ++-- src/bin/scripts/dropuser.c | 3 ++- src/bin/scripts/reindexdb.c | 25 ++++++++++++++------ src/bin/scripts/vacuumdb.c | 20 ++++++++++++---- 16 files changed, 188 insertions(+), 36 deletions(-) diff --git a/doc/src/sgml/ref/clusterdb.sgml b/doc/src/sgml/ref/clusterdb.sgml index c80cbac517..1573145b92 100644 --- a/doc/src/sgml/ref/clusterdb.sgml +++ b/doc/src/sgml/ref/clusterdb.sgml @@ -229,6 +229,18 @@ PostgreSQL documentation + + + + + + Specifies the name of the database to connect to discover what other + databases should be clustered. If not specified, the + postgres database will be used, + and if that does not exist, template1 will be used. + + + diff --git a/doc/src/sgml/ref/createdb.sgml b/doc/src/sgml/ref/createdb.sgml index 1516f3396d..cbbc5c0545 100644 --- a/doc/src/sgml/ref/createdb.sgml +++ b/doc/src/sgml/ref/createdb.sgml @@ -276,6 +276,19 @@ PostgreSQL documentation + + + + + + Specifies the name of the database to connect to when creating the + new database. If not specified, the postgres + database will be used; if that does not exist (or if it is the name + of the new database being created), template1 will + be used. + + + diff --git a/doc/src/sgml/ref/dropdb.sgml b/doc/src/sgml/ref/dropdb.sgml index aedfa58075..ba781cce52 100644 --- a/doc/src/sgml/ref/dropdb.sgml +++ b/doc/src/sgml/ref/dropdb.sgml @@ -196,6 +196,18 @@ PostgreSQL documentation + + + + + + Specifies the name of the database to connect to in order to drop the + target database. If not specified, the postgres + database will be used; if that does not exist (or is the database + being dropped), template1 will be used. + + + diff --git a/doc/src/sgml/ref/reindexdb.sgml b/doc/src/sgml/ref/reindexdb.sgml index 7b0263c5a1..9caaa95266 100644 --- a/doc/src/sgml/ref/reindexdb.sgml +++ b/doc/src/sgml/ref/reindexdb.sgml @@ -243,6 +243,18 @@ PostgreSQL documentation + + + + + + Specifies the name of the database to connect to discover what other + databases should be vacuumed. If not specified, the + postgres database will be used, + and if that does not exist, template1 will be used. + + + diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml index 4effa4188a..89d634747d 100644 --- a/doc/src/sgml/ref/vacuumdb.sgml +++ b/doc/src/sgml/ref/vacuumdb.sgml @@ -284,6 +284,18 @@ PostgreSQL documentation + + + + + + Specifies the name of the database to connect to discover what other + databases should be vacuumed. If not specified, the + postgres database will be used, + and if that does not exist, template1 will be used. + + + diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c index 3742091e2a..fc88692b4e 100644 --- a/src/bin/scripts/clusterdb.c +++ b/src/bin/scripts/clusterdb.c @@ -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 .\n")); } diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c index 9a7cc2c264..99be4ae83a 100644 --- a/src/bin/scripts/common.c +++ b/src/bin/scripts/common.c @@ -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. diff --git a/src/bin/scripts/common.h b/src/bin/scripts/common.h index caa9e81f45..9ebd72873d 100644 --- a/src/bin/scripts/common.h +++ b/src/bin/scripts/common.h @@ -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, diff --git a/src/bin/scripts/createdb.c b/src/bin/scripts/createdb.c index d7c3928eb6..6410541258 100644 --- a/src/bin/scripts/createdb.c +++ b/src/bin/scripts/createdb.c @@ -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 .\n")); } diff --git a/src/bin/scripts/createlang.c b/src/bin/scripts/createlang.c index 2f667e864a..a0720de339 100644 --- a/src/bin/scripts/createlang.c +++ b/src/bin/scripts/createlang.c @@ -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 diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c index d6e05dd793..4ed400a2bd 100644 --- a/src/bin/scripts/createuser.c +++ b/src/bin/scripts/createuser.c @@ -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); diff --git a/src/bin/scripts/dropdb.c b/src/bin/scripts/dropdb.c index 0e6749efec..621c0aecc0 100644 --- a/src/bin/scripts/dropdb.c +++ b/src/bin/scripts/dropdb.c @@ -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 .\n")); } diff --git a/src/bin/scripts/droplang.c b/src/bin/scripts/droplang.c index f136a760ff..d04b4dd973 100644 --- a/src/bin/scripts/droplang.c +++ b/src/bin/scripts/droplang.c @@ -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 diff --git a/src/bin/scripts/dropuser.c b/src/bin/scripts/dropuser.c index bfd5b1cfd5..f67fb0bcb8 100644 --- a/src/bin/scripts/dropuser.c +++ b/src/bin/scripts/dropuser.c @@ -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); diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c index caeed7511e..9ff15d85d6 100644 --- a/src/bin/scripts/reindexdb.c +++ b/src/bin/scripts/reindexdb.c @@ -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 .\n")); } diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index 7457e6d304..a82e10a2a2 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -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 .\n")); }