Skip to content

Commit 83dec5a

Browse files
committed
vacuumdb: don't prompt for passwords over and over
Having the script prompt for passwords over and over was a preexisting problem when it processed multiple databases or when it processed multiple analyze stages, but the parallel mode introduced in commit a179232 made it worse. Fix the annoyance by keeping a copy of the password used by the first connection that requires one. Since users can (currently) only have a single password, there's no need for more complex arrangements (such as remembering one password per database). Per bug #13741 reported by Eric Brown. Patch authored and cross-reviewed by Haribabu Kommi and Michael Paquier, slightly tweaked by Álvaro Herrera. Discussion: http://www.postgresql.org/message-id/20151027193919.931.54948@wrigleys.postgresql.org Backpatch to 9.5, where parallel vacuumdb was introduced.
1 parent fe702a7 commit 83dec5a

File tree

9 files changed

+98
-45
lines changed

9 files changed

+98
-45
lines changed

src/bin/scripts/clusterdb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ cluster_one_database(const char *dbname, bool verbose, const char *table,
203203
appendPQExpBuffer(&sql, " %s", table);
204204
appendPQExpBufferChar(&sql, ';');
205205

206-
conn = connectDatabase(dbname, host, port, username, prompt_password,
206+
conn = connectDatabase(dbname, host, port, username, NULL, prompt_password,
207207
progname, false);
208208
if (!executeMaintenanceCommand(conn, sql.data, echo))
209209
{

src/bin/scripts/common.c

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,24 @@ handle_help_version_opts(int argc, char *argv[],
5252

5353

5454
/*
55-
* Make a database connection with the given parameters. An
56-
* interactive password prompt is automatically issued if required.
55+
* Make a database connection with the given parameters.
56+
*
57+
* A password can be given, but if not (or if user forces us to) we prompt
58+
* interactively for one, unless caller prohibited us from doing so.
5759
*/
5860
PGconn *
5961
connectDatabase(const char *dbname, const char *pghost, const char *pgport,
60-
const char *pguser, enum trivalue prompt_password,
61-
const char *progname, bool fail_ok)
62+
const char *pguser, const char *pgpassword,
63+
enum trivalue prompt_password, const char *progname,
64+
bool fail_ok)
6265
{
6366
PGconn *conn;
64-
char *password = NULL;
67+
char *password;
6568
bool new_pass;
6669

67-
if (prompt_password == TRI_YES)
70+
password = pgpassword ? strdup(pgpassword) : NULL;
71+
72+
if (prompt_password == TRI_YES && !pgpassword)
6873
password = simple_prompt("Password: ", 100, false);
6974

7075
/*
@@ -95,22 +100,26 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport,
95100
new_pass = false;
96101
conn = PQconnectdbParams(keywords, values, true);
97102

98-
free(keywords);
99-
free(values);
100-
101103
if (!conn)
102104
{
103-
fprintf(stderr, _("%s: could not connect to database %s\n"),
105+
fprintf(stderr, _("%s: could not connect to database %s: out of memory\n"),
104106
progname, dbname);
105107
exit(1);
106108
}
107109

110+
pg_free(keywords);
111+
pg_free(values);
112+
113+
/*
114+
* No luck? Trying asking (again) for a password.
115+
*/
108116
if (PQstatus(conn) == CONNECTION_BAD &&
109117
PQconnectionNeedsPassword(conn) &&
110-
password == NULL &&
111118
prompt_password != TRI_NO)
112119
{
113120
PQfinish(conn);
121+
if (password)
122+
free(password);
114123
password = simple_prompt("Password: ", 100, false);
115124
new_pass = true;
116125
}
@@ -148,14 +157,14 @@ connectMaintenanceDatabase(const char *maintenance_db, const char *pghost,
148157

149158
/* If a maintenance database name was specified, just connect to it. */
150159
if (maintenance_db)
151-
return connectDatabase(maintenance_db, pghost, pgport, pguser,
160+
return connectDatabase(maintenance_db, pghost, pgport, pguser, NULL,
152161
prompt_password, progname, false);
153162

154163
/* Otherwise, try postgres first and then template1. */
155-
conn = connectDatabase("postgres", pghost, pgport, pguser, prompt_password,
156-
progname, true);
164+
conn = connectDatabase("postgres", pghost, pgport, pguser, NULL,
165+
prompt_password, progname, true);
157166
if (!conn)
158-
conn = connectDatabase("template1", pghost, pgport, pguser,
167+
conn = connectDatabase("template1", pghost, pgport, pguser, NULL,
159168
prompt_password, progname, false);
160169

161170
return conn;

src/bin/scripts/common.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ extern void handle_help_version_opts(int argc, char *argv[],
3131

3232
extern PGconn *connectDatabase(const char *dbname, const char *pghost,
3333
const char *pgport, const char *pguser,
34-
enum trivalue prompt_password, const char *progname,
35-
bool fail_ok);
34+
const char *pgpassword, enum trivalue prompt_password,
35+
const char *progname, bool fail_ok);
3636

3737
extern PGconn *connectMaintenanceDatabase(const char *maintenance_db,
3838
const char *pghost, const char *pgport, const char *pguser,

src/bin/scripts/createlang.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ main(int argc, char *argv[])
140140
printQueryOpt popt;
141141
static const bool translate_columns[] = {false, true};
142142

143-
conn = connectDatabase(dbname, host, port, username, prompt_password,
144-
progname, false);
143+
conn = connectDatabase(dbname, host, port, username, NULL,
144+
prompt_password, progname, false);
145145

146146
printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
147147
"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
@@ -180,8 +180,8 @@ main(int argc, char *argv[])
180180
if (*p >= 'A' && *p <= 'Z')
181181
*p += ('a' - 'A');
182182

183-
conn = connectDatabase(dbname, host, port, username, prompt_password,
184-
progname, false);
183+
conn = connectDatabase(dbname, host, port, username, NULL,
184+
prompt_password, progname, false);
185185

186186
/*
187187
* Make sure the language isn't already installed

src/bin/scripts/createuser.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,8 @@ main(int argc, char *argv[])
250250
if (login == 0)
251251
login = TRI_YES;
252252

253-
conn = connectDatabase("postgres", host, port, username, prompt_password,
254-
progname, false);
253+
conn = connectDatabase("postgres", host, port, username, NULL,
254+
prompt_password, progname, false);
255255

256256
initPQExpBuffer(&sql);
257257

src/bin/scripts/droplang.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ main(int argc, char *argv[])
139139
printQueryOpt popt;
140140
static const bool translate_columns[] = {false, true};
141141

142-
conn = connectDatabase(dbname, host, port, username, prompt_password,
143-
progname, false);
142+
conn = connectDatabase(dbname, host, port, username, NULL,
143+
prompt_password, progname, false);
144144

145145
printfPQExpBuffer(&sql, "SELECT lanname as \"%s\", "
146146
"(CASE WHEN lanpltrusted THEN '%s' ELSE '%s' END) as \"%s\" "
@@ -181,8 +181,8 @@ main(int argc, char *argv[])
181181
if (*p >= 'A' && *p <= 'Z')
182182
*p += ('a' - 'A');
183183

184-
conn = connectDatabase(dbname, host, port, username, prompt_password,
185-
progname, false);
184+
conn = connectDatabase(dbname, host, port, username, NULL,
185+
prompt_password, progname, false);
186186

187187
/*
188188
* Force schema search path to be just pg_catalog, so that we don't have

src/bin/scripts/dropuser.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ main(int argc, char *argv[])
128128
appendPQExpBuffer(&sql, "DROP ROLE %s%s;",
129129
(if_exists ? "IF EXISTS " : ""), fmtId(dropuser));
130130

131-
conn = connectDatabase("postgres", host, port, username, prompt_password,
132-
progname, false);
131+
conn = connectDatabase("postgres", host, port, username, NULL,
132+
prompt_password, progname, false);
133133

134134
if (echo)
135135
printf("%s\n", sql.data);

src/bin/scripts/reindexdb.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
297297
appendPQExpBuffer(&sql, " DATABASE %s", fmtId(name));
298298
appendPQExpBufferChar(&sql, ';');
299299

300-
conn = connectDatabase(dbname, host, port, username, prompt_password,
301-
progname, false);
300+
conn = connectDatabase(dbname, host, port, username, NULL,
301+
prompt_password, progname, false);
302302

303303
if (!executeMaintenanceCommand(conn, sql.data, echo))
304304
{
@@ -372,8 +372,8 @@ reindex_system_catalogs(const char *dbname, const char *host, const char *port,
372372

373373
appendPQExpBuffer(&sql, " SYSTEM %s;", dbname);
374374

375-
conn = connectDatabase(dbname, host, port, username, prompt_password,
376-
progname, false);
375+
conn = connectDatabase(dbname, host, port, username, NULL,
376+
prompt_password, progname, false);
377377
if (!executeMaintenanceCommand(conn, sql.data, echo))
378378
{
379379
fprintf(stderr, _("%s: reindexing of system catalogs failed: %s"),

src/bin/scripts/vacuumdb.c

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ static void vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
4343
const char *host, const char *port,
4444
const char *username, enum trivalue prompt_password,
4545
int concurrentCons,
46-
const char *progname, bool echo, bool quiet);
46+
const char *progname, bool echo, bool quiet,
47+
char **password);
4748

4849
static void vacuum_all_databases(vacuumingOptions *vacopts,
4950
bool analyze_in_stages,
@@ -275,6 +276,8 @@ main(int argc, char *argv[])
275276
}
276277
else
277278
{
279+
char *password = NULL;
280+
278281
if (dbname == NULL)
279282
{
280283
if (getenv("PGDATABASE"))
@@ -296,7 +299,8 @@ main(int argc, char *argv[])
296299
&tables,
297300
host, port, username, prompt_password,
298301
concurrentCons,
299-
progname, echo, quiet);
302+
progname, echo, quiet,
303+
&password);
300304
}
301305
}
302306
else
@@ -305,7 +309,10 @@ main(int argc, char *argv[])
305309
&tables,
306310
host, port, username, prompt_password,
307311
concurrentCons,
308-
progname, echo, quiet);
312+
progname, echo, quiet,
313+
&password);
314+
315+
pg_free(password);
309316
}
310317

311318
exit(0);
@@ -323,15 +330,21 @@ main(int argc, char *argv[])
323330
* If concurrentCons is > 1, multiple connections are used to vacuum tables
324331
* in parallel. In this case and if the table list is empty, we first obtain
325332
* a list of tables from the database.
333+
*
334+
* 'password' is both an input and output parameter. If one is not passed,
335+
* then whatever is used in a connection is returned so that caller can
336+
* reuse it in future connections.
326337
*/
327338
static void
328339
vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
329340
int stage,
330341
SimpleStringList *tables,
331342
const char *host, const char *port,
332-
const char *username, enum trivalue prompt_password,
343+
const char *username,
344+
enum trivalue prompt_password,
333345
int concurrentCons,
334-
const char *progname, bool echo, bool quiet)
346+
const char *progname, bool echo, bool quiet,
347+
char **password)
335348
{
336349
PQExpBufferData sql;
337350
PGconn *conn;
@@ -365,8 +378,15 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
365378
fflush(stdout);
366379
}
367380

368-
conn = connectDatabase(dbname, host, port, username, prompt_password,
369-
progname, false);
381+
conn = connectDatabase(dbname, host, port, username, *password,
382+
prompt_password, progname, false);
383+
384+
/*
385+
* If no password was not specified by caller and the connection required
386+
* one, remember it; this suppresses further password prompts.
387+
*/
388+
if (PQconnectionUsedPassword(conn) && *password == NULL)
389+
*password = pg_strdup(PQpass(conn));
370390

371391
initPQExpBuffer(&sql);
372392

@@ -424,10 +444,20 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
424444
init_slot(slots, conn);
425445
if (parallel)
426446
{
447+
const char *pqpass;
448+
449+
/*
450+
* If a password was supplied for the initial connection, use it for
451+
* subsequent ones too. (Note that since we're connecting to the same
452+
* database with the same user, there's no need to update the stored
453+
* password any further.)
454+
*/
455+
pqpass = PQpass(conn);
456+
427457
for (i = 1; i < concurrentCons; i++)
428458
{
429-
conn = connectDatabase(dbname, host, port, username, prompt_password,
430-
progname, false);
459+
conn = connectDatabase(dbname, host, port, username, pqpass,
460+
prompt_password, progname, false);
431461
init_slot(slots + i, conn);
432462
}
433463
}
@@ -542,12 +572,23 @@ vacuum_all_databases(vacuumingOptions *vacopts,
542572
PGresult *result;
543573
int stage;
544574
int i;
575+
char *password = NULL;
545576

546577
conn = connectMaintenanceDatabase(maintenance_db, host, port,
547578
username, prompt_password, progname);
579+
548580
result = executeQuery(conn,
549581
"SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;",
550582
progname, echo);
583+
584+
/*
585+
* Remember the password for further connections. If no password was
586+
* required for the maintenance db connection, this gets updated for the
587+
* first connection that does.
588+
*/
589+
if (PQconnectionUsedPassword(conn))
590+
password = pg_strdup(PQpass(conn));
591+
551592
PQfinish(conn);
552593

553594
if (analyze_in_stages)
@@ -572,7 +613,8 @@ vacuum_all_databases(vacuumingOptions *vacopts,
572613
NULL,
573614
host, port, username, prompt_password,
574615
concurrentCons,
575-
progname, echo, quiet);
616+
progname, echo, quiet,
617+
&password);
576618
}
577619
}
578620
}
@@ -588,11 +630,13 @@ vacuum_all_databases(vacuumingOptions *vacopts,
588630
NULL,
589631
host, port, username, prompt_password,
590632
concurrentCons,
591-
progname, echo, quiet);
633+
progname, echo, quiet,
634+
&password);
592635
}
593636
}
594637

595638
PQclear(result);
639+
pg_free(password);
596640
}
597641

598642
/*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy