783 lines
25 KiB
Diff
783 lines
25 KiB
Diff
From bb3ab8bfb690721923e987d2dfab683b462c1e88 Mon Sep 17 00:00:00 2001
|
|
From: Tom Lane <tgl@sss.pgh.pa.us>
|
|
Date: Thu, 24 Sep 2020 18:19:39 -0400
|
|
Subject: [PATCH] Fix handling of -d "connection string" in pg_dump/pg_restore.
|
|
|
|
Parallel pg_dump failed if its -d parameter was a connection string
|
|
containing any essential information other than host, port, or username.
|
|
The same was true for pg_restore with --create.
|
|
|
|
The reason is that these scenarios failed to preserve the connection
|
|
string from the command line; the code felt free to replace that with
|
|
just the database name when reconnecting from a pg_dump parallel worker
|
|
or after creating the target database. By chance, parallel pg_restore
|
|
did not suffer this defect, as long as you didn't say --create.
|
|
|
|
In practice it seems that the error would be obvious only if the
|
|
connstring included essential, non-default SSL or GSS parameters.
|
|
This may explain why it took us so long to notice. (It also makes
|
|
it very difficult to craft a regression test case illustrating the
|
|
problem, since the test would fail in builds without those options.)
|
|
|
|
Fix by refactoring so that ConnectDatabase always receives all the
|
|
relevant options directly from the command line, rather than
|
|
reconstructed values. Inject a different database name, when necessary,
|
|
by relying on libpq's rules for handling multiple "dbname" parameters.
|
|
|
|
While here, let's get rid of the essentially duplicate _connectDB
|
|
function, as well as some obsolete nearby cruft.
|
|
|
|
Per bug #16604 from Zsolt Ero. Back-patch to all supported branches.
|
|
|
|
Discussion: https://postgr.es/m/16604-933f4b8791227b15@postgresql.org
|
|
---
|
|
src/bin/pg_dump/pg_backup.h | 36 ++--
|
|
src/bin/pg_dump/pg_backup_archiver.c | 96 +++--------
|
|
src/bin/pg_dump/pg_backup_archiver.h | 3 +-
|
|
src/bin/pg_dump/pg_backup_db.c | 249 +++++++--------------------
|
|
src/bin/pg_dump/pg_dump.c | 24 +--
|
|
src/bin/pg_dump/pg_restore.c | 14 +-
|
|
6 files changed, 131 insertions(+), 291 deletions(-)
|
|
|
|
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
|
|
index 560de01884..72c6a8db6c 100644
|
|
--- a/src/bin/pg_dump/pg_backup.h
|
|
+++ b/src/bin/pg_dump/pg_backup.h
|
|
@@ -58,6 +58,20 @@ typedef enum _teSection
|
|
SECTION_POST_DATA /* stuff to be processed after data */
|
|
} teSection;
|
|
|
|
+/* Parameters needed by ConnectDatabase; same for dump and restore */
|
|
+typedef struct _connParams
|
|
+{
|
|
+ /* These fields record the actual command line parameters */
|
|
+ char *dbname; /* this may be a connstring! */
|
|
+ char *pgport;
|
|
+ char *pghost;
|
|
+ char *username;
|
|
+ trivalue promptPassword;
|
|
+ /* If not NULL, this overrides the dbname obtained from command line */
|
|
+ /* (but *only* the DB name, not anything else in the connstring) */
|
|
+ char *override_dbname;
|
|
+} ConnParams;
|
|
+
|
|
typedef struct _restoreOptions
|
|
{
|
|
int createDB; /* Issue commands to create the database */
|
|
@@ -106,12 +120,9 @@ typedef struct _restoreOptions
|
|
SimpleStringList tableNames;
|
|
|
|
int useDB;
|
|
- char *dbname; /* subject to expand_dbname */
|
|
- char *pgport;
|
|
- char *pghost;
|
|
- char *username;
|
|
+ ConnParams cparams; /* parameters to use if useDB */
|
|
+
|
|
int noDataForFailedTables;
|
|
- trivalue promptPassword;
|
|
int exit_on_error;
|
|
int compression;
|
|
int suppressDumpWarnings; /* Suppress output of WARNING entries
|
|
@@ -126,10 +137,8 @@ typedef struct _restoreOptions
|
|
|
|
typedef struct _dumpOptions
|
|
{
|
|
- const char *dbname; /* subject to expand_dbname */
|
|
- const char *pghost;
|
|
- const char *pgport;
|
|
- const char *username;
|
|
+ ConnParams cparams;
|
|
+
|
|
bool oids;
|
|
|
|
int binary_upgrade;
|
|
@@ -239,12 +248,9 @@ typedef void (*SetupWorkerPtrType) (Archive *AH);
|
|
* Main archiver interface.
|
|
*/
|
|
|
|
-extern void ConnectDatabase(Archive *AH,
|
|
- const char *dbname,
|
|
- const char *pghost,
|
|
- const char *pgport,
|
|
- const char *username,
|
|
- trivalue prompt_password);
|
|
+extern void ConnectDatabase(Archive *AHX,
|
|
+ const ConnParams *cparams,
|
|
+ bool isReconnect);
|
|
extern void DisconnectDatabase(Archive *AHX);
|
|
extern PGconn *GetConnection(Archive *AHX);
|
|
|
|
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
|
|
index 8892b17790..4003ab3b13 100644
|
|
--- a/src/bin/pg_dump/pg_backup_archiver.c
|
|
+++ b/src/bin/pg_dump/pg_backup_archiver.c
|
|
@@ -144,6 +144,7 @@ InitDumpOptions(DumpOptions *opts)
|
|
memset(opts, 0, sizeof(DumpOptions));
|
|
/* set any fields that shouldn't default to zeroes */
|
|
opts->include_everything = true;
|
|
+ opts->cparams.promptPassword = TRI_DEFAULT;
|
|
opts->dumpSections = DUMP_UNSECTIONED;
|
|
}
|
|
|
|
@@ -157,6 +158,11 @@ dumpOptionsFromRestoreOptions(RestoreOptions *ropt)
|
|
DumpOptions *dopt = NewDumpOptions();
|
|
|
|
/* this is the inverse of what's at the end of pg_dump.c's main() */
|
|
+ dopt->cparams.dbname = ropt->cparams.dbname ? pg_strdup(ropt->cparams.dbname) : NULL;
|
|
+ dopt->cparams.pgport = ropt->cparams.pgport ? pg_strdup(ropt->cparams.pgport) : NULL;
|
|
+ dopt->cparams.pghost = ropt->cparams.pghost ? pg_strdup(ropt->cparams.pghost) : NULL;
|
|
+ dopt->cparams.username = ropt->cparams.username ? pg_strdup(ropt->cparams.username) : NULL;
|
|
+ dopt->cparams.promptPassword = ropt->cparams.promptPassword;
|
|
dopt->outputClean = ropt->dropSchema;
|
|
dopt->dataOnly = ropt->dataOnly;
|
|
dopt->schemaOnly = ropt->schemaOnly;
|
|
@@ -401,9 +407,7 @@ RestoreArchive(Archive *AHX)
|
|
AHX->minRemoteVersion = 0;
|
|
AHX->maxRemoteVersion = 9999999;
|
|
|
|
- ConnectDatabase(AHX, ropt->dbname,
|
|
- ropt->pghost, ropt->pgport, ropt->username,
|
|
- ropt->promptPassword);
|
|
+ ConnectDatabase(AHX, &ropt->cparams, false);
|
|
|
|
/*
|
|
* If we're talking to the DB directly, don't send comments since they
|
|
@@ -823,16 +827,8 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
|
|
/* If we created a DB, connect to it... */
|
|
if (strcmp(te->desc, "DATABASE") == 0)
|
|
{
|
|
- PQExpBufferData connstr;
|
|
-
|
|
- initPQExpBuffer(&connstr);
|
|
- appendPQExpBufferStr(&connstr, "dbname=");
|
|
- appendConnStrVal(&connstr, te->tag);
|
|
- /* Abandon struct, but keep its buffer until process exit. */
|
|
-
|
|
ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag);
|
|
_reconnectToDB(AH, te->tag);
|
|
- ropt->dbname = connstr.data;
|
|
}
|
|
}
|
|
|
|
@@ -966,7 +962,7 @@ NewRestoreOptions(void)
|
|
|
|
/* set any fields that shouldn't default to zeroes */
|
|
opts->format = archUnknown;
|
|
- opts->promptPassword = TRI_DEFAULT;
|
|
+ opts->cparams.promptPassword = TRI_DEFAULT;
|
|
opts->dumpSections = DUMP_UNSECTIONED;
|
|
|
|
return opts;
|
|
@@ -2388,8 +2384,6 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
|
|
else
|
|
AH->format = fmt;
|
|
|
|
- AH->promptPassword = TRI_DEFAULT;
|
|
-
|
|
switch (AH->format)
|
|
{
|
|
case archCustom:
|
|
@@ -3157,27 +3151,20 @@ _doSetWithOids(ArchiveHandle *AH, const bool withOids)
|
|
* If we're currently restoring right into a database, this will
|
|
* actually establish a connection. Otherwise it puts a \connect into
|
|
* the script output.
|
|
- *
|
|
- * NULL dbname implies reconnecting to the current DB (pretty useless).
|
|
*/
|
|
static void
|
|
_reconnectToDB(ArchiveHandle *AH, const char *dbname)
|
|
{
|
|
if (RestoringToDB(AH))
|
|
- ReconnectToServer(AH, dbname, NULL);
|
|
+ ReconnectToServer(AH, dbname);
|
|
else
|
|
{
|
|
- if (dbname)
|
|
- {
|
|
- PQExpBufferData connectbuf;
|
|
+ PQExpBufferData connectbuf;
|
|
|
|
- initPQExpBuffer(&connectbuf);
|
|
- appendPsqlMetaConnect(&connectbuf, dbname);
|
|
- ahprintf(AH, "%s\n", connectbuf.data);
|
|
- termPQExpBuffer(&connectbuf);
|
|
- }
|
|
- else
|
|
- ahprintf(AH, "%s\n", "\\connect -\n");
|
|
+ initPQExpBuffer(&connectbuf);
|
|
+ appendPsqlMetaConnect(&connectbuf, dbname);
|
|
+ ahprintf(AH, "%s\n", connectbuf.data);
|
|
+ termPQExpBuffer(&connectbuf);
|
|
}
|
|
|
|
/*
|
|
@@ -4107,9 +4094,7 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
|
|
/*
|
|
* Now reconnect the single parent connection.
|
|
*/
|
|
- ConnectDatabase((Archive *) AH, ropt->dbname,
|
|
- ropt->pghost, ropt->pgport, ropt->username,
|
|
- ropt->promptPassword);
|
|
+ ConnectDatabase((Archive *) AH, &ropt->cparams, true);
|
|
|
|
/* re-establish fixed state */
|
|
_doSetFixedOutputState(AH);
|
|
@@ -4690,54 +4675,15 @@ CloneArchive(ArchiveHandle *AH)
|
|
clone->public.n_errors = 0;
|
|
|
|
/*
|
|
- * Connect our new clone object to the database: In parallel restore the
|
|
- * parent is already disconnected, because we can connect the worker
|
|
- * processes independently to the database (no snapshot sync required). In
|
|
- * parallel backup we clone the parent's existing connection.
|
|
+ * Connect our new clone object to the database, using the same connection
|
|
+ * parameters used for the original connection.
|
|
*/
|
|
- if (AH->mode == archModeRead)
|
|
- {
|
|
- RestoreOptions *ropt = AH->public.ropt;
|
|
-
|
|
- Assert(AH->connection == NULL);
|
|
-
|
|
- /* this also sets clone->connection */
|
|
- ConnectDatabase((Archive *) clone, ropt->dbname,
|
|
- ropt->pghost, ropt->pgport, ropt->username,
|
|
- ropt->promptPassword);
|
|
+ ConnectDatabase((Archive *) clone, &clone->public.ropt->cparams, true);
|
|
|
|
- /* re-establish fixed state */
|
|
+ /* re-establish fixed state */
|
|
+ if (AH->mode == archModeRead)
|
|
_doSetFixedOutputState(clone);
|
|
- }
|
|
- else
|
|
- {
|
|
- PQExpBufferData connstr;
|
|
- char *pghost;
|
|
- char *pgport;
|
|
- char *username;
|
|
-
|
|
- Assert(AH->connection != NULL);
|
|
-
|
|
- /*
|
|
- * Even though we are technically accessing the parent's database
|
|
- * object here, these functions are fine to be called like that
|
|
- * because all just return a pointer and do not actually send/receive
|
|
- * any data to/from the database.
|
|
- */
|
|
- initPQExpBuffer(&connstr);
|
|
- appendPQExpBuffer(&connstr, "dbname=");
|
|
- appendConnStrVal(&connstr, PQdb(AH->connection));
|
|
- pghost = PQhost(AH->connection);
|
|
- pgport = PQport(AH->connection);
|
|
- username = PQuser(AH->connection);
|
|
-
|
|
- /* this also sets clone->connection */
|
|
- ConnectDatabase((Archive *) clone, connstr.data,
|
|
- pghost, pgport, username, TRI_NO);
|
|
-
|
|
- termPQExpBuffer(&connstr);
|
|
- /* setupDumpWorker will fix up connection state */
|
|
- }
|
|
+ /* in write case, setupDumpWorker will fix up connection state */
|
|
|
|
/* Let the format-specific code have a chance too */
|
|
(clone->ClonePtr) (clone);
|
|
diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h
|
|
index 3b69868359..50829c4b2e 100644
|
|
--- a/src/bin/pg_dump/pg_backup_archiver.h
|
|
+++ b/src/bin/pg_dump/pg_backup_archiver.h
|
|
@@ -304,7 +304,6 @@ struct _archiveHandle
|
|
|
|
/* Stuff for direct DB connection */
|
|
char *archdbname; /* DB name *read* from archive */
|
|
- trivalue promptPassword;
|
|
char *savedPassword; /* password for ropt->username, if known */
|
|
char *use_role;
|
|
PGconn *connection;
|
|
@@ -450,7 +449,7 @@ extern void InitArchiveFmt_Tar(ArchiveHandle *AH);
|
|
|
|
extern bool isValidTarHeader(char *header);
|
|
|
|
-extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser);
|
|
+extern void ReconnectToServer(ArchiveHandle *AH, const char *dbname);
|
|
extern void DropBlobIfExists(ArchiveHandle *AH, Oid oid);
|
|
|
|
void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
|
|
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
|
|
index 43f5941f93..4eaea4af4f 100644
|
|
--- a/src/bin/pg_dump/pg_backup_db.c
|
|
+++ b/src/bin/pg_dump/pg_backup_db.c
|
|
@@ -30,7 +30,6 @@
|
|
static const char *modulename = gettext_noop("archiver (db)");
|
|
|
|
static void _check_database_version(ArchiveHandle *AH);
|
|
-static PGconn *_connectDB(ArchiveHandle *AH, const char *newdbname, const char *newUser);
|
|
static void notice_processor(void *arg, const char *message);
|
|
|
|
static void
|
|
@@ -76,186 +75,51 @@ _check_database_version(ArchiveHandle *AH)
|
|
|
|
/*
|
|
* Reconnect to the server. If dbname is not NULL, use that database,
|
|
- * else the one associated with the archive handle. If username is
|
|
- * not NULL, use that user name, else the one from the handle. If
|
|
- * both the database and the user match the existing connection already,
|
|
- * nothing will be done.
|
|
- *
|
|
- * Returns 1 in any case.
|
|
+ * else the one associated with the archive handle.
|
|
*/
|
|
-int
|
|
-ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username)
|
|
-{
|
|
- PGconn *newConn;
|
|
- const char *newdbname;
|
|
- const char *newusername;
|
|
-
|
|
- if (!dbname)
|
|
- newdbname = PQdb(AH->connection);
|
|
- else
|
|
- newdbname = dbname;
|
|
-
|
|
- if (!username)
|
|
- newusername = PQuser(AH->connection);
|
|
- else
|
|
- newusername = username;
|
|
-
|
|
- /* Let's see if the request is already satisfied */
|
|
- if (strcmp(newdbname, PQdb(AH->connection)) == 0 &&
|
|
- strcmp(newusername, PQuser(AH->connection)) == 0)
|
|
- return 1;
|
|
-
|
|
- newConn = _connectDB(AH, newdbname, newusername);
|
|
-
|
|
- /* Update ArchiveHandle's connCancel before closing old connection */
|
|
- set_archive_cancel_info(AH, newConn);
|
|
-
|
|
- PQfinish(AH->connection);
|
|
- AH->connection = newConn;
|
|
-
|
|
- /* Start strict; later phases may override this. */
|
|
- PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
|
|
- ALWAYS_SECURE_SEARCH_PATH_SQL));
|
|
-
|
|
- return 1;
|
|
-}
|
|
-
|
|
-/*
|
|
- * Connect to the db again.
|
|
- *
|
|
- * Note: it's not really all that sensible to use a single-entry password
|
|
- * cache if the username keeps changing. In current usage, however, the
|
|
- * username never does change, so one savedPassword is sufficient. We do
|
|
- * update the cache on the off chance that the password has changed since the
|
|
- * start of the run.
|
|
- */
|
|
-static PGconn *
|
|
-_connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
|
|
+void
|
|
+ReconnectToServer(ArchiveHandle *AH, const char *dbname)
|
|
{
|
|
- PQExpBufferData connstr;
|
|
- PGconn *newConn;
|
|
- const char *newdb;
|
|
- const char *newuser;
|
|
- char *password;
|
|
- char passbuf[100];
|
|
- bool new_pass;
|
|
-
|
|
- if (!reqdb)
|
|
- newdb = PQdb(AH->connection);
|
|
- else
|
|
- newdb = reqdb;
|
|
-
|
|
- if (!requser || strlen(requser) == 0)
|
|
- newuser = PQuser(AH->connection);
|
|
- else
|
|
- newuser = requser;
|
|
-
|
|
- ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n",
|
|
- newdb, newuser);
|
|
-
|
|
- password = AH->savedPassword;
|
|
-
|
|
- if (AH->promptPassword == TRI_YES && password == NULL)
|
|
- {
|
|
- simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
|
|
- password = passbuf;
|
|
- }
|
|
-
|
|
- initPQExpBuffer(&connstr);
|
|
- appendPQExpBuffer(&connstr, "dbname=");
|
|
- appendConnStrVal(&connstr, newdb);
|
|
-
|
|
- do
|
|
- {
|
|
- const char *keywords[7];
|
|
- const char *values[7];
|
|
-
|
|
- keywords[0] = "host";
|
|
- values[0] = PQhost(AH->connection);
|
|
- keywords[1] = "port";
|
|
- values[1] = PQport(AH->connection);
|
|
- keywords[2] = "user";
|
|
- values[2] = newuser;
|
|
- keywords[3] = "password";
|
|
- values[3] = password;
|
|
- keywords[4] = "dbname";
|
|
- values[4] = connstr.data;
|
|
- keywords[5] = "fallback_application_name";
|
|
- values[5] = progname;
|
|
- keywords[6] = NULL;
|
|
- values[6] = NULL;
|
|
-
|
|
- new_pass = false;
|
|
- newConn = PQconnectdbParams(keywords, values, true);
|
|
-
|
|
- if (!newConn)
|
|
- exit_horribly(modulename, "failed to reconnect to database\n");
|
|
-
|
|
- if (PQstatus(newConn) == CONNECTION_BAD)
|
|
- {
|
|
- if (!PQconnectionNeedsPassword(newConn))
|
|
- exit_horribly(modulename, "could not reconnect to database: %s",
|
|
- PQerrorMessage(newConn));
|
|
- PQfinish(newConn);
|
|
-
|
|
- if (password)
|
|
- fprintf(stderr, "Password incorrect\n");
|
|
-
|
|
- fprintf(stderr, "Connecting to %s as %s\n",
|
|
- newdb, newuser);
|
|
-
|
|
- if (AH->promptPassword != TRI_NO)
|
|
- {
|
|
- simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
|
|
- password = passbuf;
|
|
- }
|
|
- else
|
|
- exit_horribly(modulename, "connection needs password\n");
|
|
-
|
|
- new_pass = true;
|
|
- }
|
|
- } while (new_pass);
|
|
+ PGconn *oldConn = AH->connection;
|
|
+ RestoreOptions *ropt = AH->public.ropt;
|
|
|
|
/*
|
|
- * We want to remember connection's actual password, whether or not we got
|
|
- * it by prompting. So we don't just store the password variable.
|
|
+ * Save the dbname, if given, in override_dbname so that it will also
|
|
+ * affect any later reconnection attempt.
|
|
*/
|
|
- if (PQconnectionUsedPassword(newConn))
|
|
- {
|
|
- if (AH->savedPassword)
|
|
- free(AH->savedPassword);
|
|
- AH->savedPassword = pg_strdup(PQpass(newConn));
|
|
- }
|
|
+ if (dbname)
|
|
+ ropt->cparams.override_dbname = pg_strdup(dbname);
|
|
|
|
- termPQExpBuffer(&connstr);
|
|
-
|
|
- /* check for version mismatch */
|
|
- _check_database_version(AH);
|
|
+ /*
|
|
+ * Note: we want to establish the new connection, and in particular update
|
|
+ * ArchiveHandle's connCancel, before closing old connection. Otherwise
|
|
+ * an ill-timed SIGINT could try to access a dead connection.
|
|
+ */
|
|
+ AH->connection = NULL; /* dodge error check in ConnectDatabase */
|
|
|
|
- PQsetNoticeProcessor(newConn, notice_processor, NULL);
|
|
+ ConnectDatabase((Archive *) AH, &ropt->cparams, true);
|
|
|
|
- return newConn;
|
|
+ PQfinish(oldConn);
|
|
}
|
|
|
|
-
|
|
/*
|
|
- * Make a database connection with the given parameters. The
|
|
- * connection handle is returned, the parameters are stored in AHX.
|
|
- * An interactive password prompt is automatically issued if required.
|
|
+ * Make, or remake, a database connection with the given parameters.
|
|
+ *
|
|
+ * The resulting connection handle is stored in AHX->connection.
|
|
*
|
|
+ * An interactive password prompt is automatically issued if required.
|
|
+ * We store the results of that in AHX->savedPassword.
|
|
* Note: it's not really all that sensible to use a single-entry password
|
|
* cache if the username keeps changing. In current usage, however, the
|
|
* username never does change, so one savedPassword is sufficient.
|
|
*/
|
|
void
|
|
ConnectDatabase(Archive *AHX,
|
|
- const char *dbname,
|
|
- const char *pghost,
|
|
- const char *pgport,
|
|
- const char *username,
|
|
- trivalue prompt_password)
|
|
+ const ConnParams *cparams,
|
|
+ bool isReconnect)
|
|
{
|
|
ArchiveHandle *AH = (ArchiveHandle *) AHX;
|
|
+ trivalue prompt_password;
|
|
char *password;
|
|
char passbuf[100];
|
|
bool new_pass;
|
|
@@ -263,6 +127,9 @@ ConnectDatabase(Archive *AHX,
|
|
if (AH->connection)
|
|
exit_horribly(modulename, "already connected to a database\n");
|
|
|
|
+ /* Never prompt for a password during a reconnection */
|
|
+ prompt_password = isReconnect ? TRI_NO : cparams->promptPassword;
|
|
+
|
|
password = AH->savedPassword;
|
|
|
|
if (prompt_password == TRI_YES && password == NULL)
|
|
@@ -270,7 +137,6 @@ ConnectDatabase(Archive *AHX,
|
|
simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
|
|
password = passbuf;
|
|
}
|
|
- AH->promptPassword = prompt_password;
|
|
|
|
/*
|
|
* Start the connection. Loop until we have a password if requested by
|
|
@@ -278,23 +144,35 @@ ConnectDatabase(Archive *AHX,
|
|
*/
|
|
do
|
|
{
|
|
- const char *keywords[7];
|
|
- const char *values[7];
|
|
-
|
|
- keywords[0] = "host";
|
|
- values[0] = pghost;
|
|
- keywords[1] = "port";
|
|
- values[1] = pgport;
|
|
- keywords[2] = "user";
|
|
- values[2] = username;
|
|
- keywords[3] = "password";
|
|
- values[3] = password;
|
|
- keywords[4] = "dbname";
|
|
- values[4] = dbname;
|
|
- keywords[5] = "fallback_application_name";
|
|
- values[5] = progname;
|
|
- keywords[6] = NULL;
|
|
- values[6] = NULL;
|
|
+ const char *keywords[8];
|
|
+ const char *values[8];
|
|
+ int i = 0;
|
|
+
|
|
+ /*
|
|
+ * If dbname is a connstring, its entries can override the other
|
|
+ * values obtained from cparams; but in turn, override_dbname can
|
|
+ * override the dbname component of it.
|
|
+ */
|
|
+ keywords[i] = "host";
|
|
+ values[i++] = cparams->pghost;
|
|
+ keywords[i] = "port";
|
|
+ values[i++] = cparams->pgport;
|
|
+ keywords[i] = "user";
|
|
+ values[i++] = cparams->username;
|
|
+ keywords[i] = "password";
|
|
+ values[i++] = password;
|
|
+ keywords[i] = "dbname";
|
|
+ values[i++] = cparams->dbname;
|
|
+ if (cparams->override_dbname)
|
|
+ {
|
|
+ keywords[i] = "dbname";
|
|
+ values[i++] = cparams->override_dbname;
|
|
+ }
|
|
+ keywords[i] = "fallback_application_name";
|
|
+ values[i++] = progname;
|
|
+ keywords[i] = NULL;
|
|
+ values[i++] = NULL;
|
|
+ Assert(i <= lengthof(keywords));
|
|
|
|
new_pass = false;
|
|
AH->connection = PQconnectdbParams(keywords, values, true);
|
|
@@ -316,9 +194,16 @@ ConnectDatabase(Archive *AHX,
|
|
|
|
/* check to see that the backend connection was successfully made */
|
|
if (PQstatus(AH->connection) == CONNECTION_BAD)
|
|
- exit_horribly(modulename, "connection to database \"%s\" failed: %s",
|
|
- PQdb(AH->connection) ? PQdb(AH->connection) : "",
|
|
- PQerrorMessage(AH->connection));
|
|
+ {
|
|
+ if (isReconnect)
|
|
+ exit_horribly(modulename, "reconnection to database \"%s\" failed: %s",
|
|
+ PQdb(AH->connection) ? PQdb(AH->connection) : "",
|
|
+ PQerrorMessage(AH->connection));
|
|
+ else
|
|
+ exit_horribly(modulename, "connection to database \"%s\" failed: %s",
|
|
+ PQdb(AH->connection) ? PQdb(AH->connection) : "",
|
|
+ PQerrorMessage(AH->connection));
|
|
+ }
|
|
|
|
/* Start strict; later phases may override this. */
|
|
PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
|
|
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
|
|
index 8080155a95..abcee89d10 100644
|
|
--- a/src/bin/pg_dump/pg_dump.c
|
|
+++ b/src/bin/pg_dump/pg_dump.c
|
|
@@ -302,7 +302,6 @@ main(int argc, char **argv)
|
|
const char *dumpsnapshot = NULL;
|
|
char *use_role = NULL;
|
|
int numWorkers = 1;
|
|
- trivalue prompt_password = TRI_DEFAULT;
|
|
int compressLevel = -1;
|
|
int plainText = 0;
|
|
ArchiveFormat archiveFormat = archUnknown;
|
|
@@ -431,7 +430,7 @@ main(int argc, char **argv)
|
|
break;
|
|
|
|
case 'd': /* database name */
|
|
- dopt.dbname = pg_strdup(optarg);
|
|
+ dopt.cparams.dbname = pg_strdup(optarg);
|
|
break;
|
|
|
|
case 'E': /* Dump encoding */
|
|
@@ -447,7 +446,7 @@ main(int argc, char **argv)
|
|
break;
|
|
|
|
case 'h': /* server host */
|
|
- dopt.pghost = pg_strdup(optarg);
|
|
+ dopt.cparams.pghost = pg_strdup(optarg);
|
|
break;
|
|
|
|
case 'j': /* number of dump jobs */
|
|
@@ -472,7 +471,7 @@ main(int argc, char **argv)
|
|
break;
|
|
|
|
case 'p': /* server port */
|
|
- dopt.pgport = pg_strdup(optarg);
|
|
+ dopt.cparams.pgport = pg_strdup(optarg);
|
|
break;
|
|
|
|
case 'R':
|
|
@@ -497,7 +496,7 @@ main(int argc, char **argv)
|
|
break;
|
|
|
|
case 'U':
|
|
- dopt.username = pg_strdup(optarg);
|
|
+ dopt.cparams.username = pg_strdup(optarg);
|
|
break;
|
|
|
|
case 'v': /* verbose */
|
|
@@ -505,11 +504,11 @@ main(int argc, char **argv)
|
|
break;
|
|
|
|
case 'w':
|
|
- prompt_password = TRI_NO;
|
|
+ dopt.cparams.promptPassword = TRI_NO;
|
|
break;
|
|
|
|
case 'W':
|
|
- prompt_password = TRI_YES;
|
|
+ dopt.cparams.promptPassword = TRI_YES;
|
|
break;
|
|
|
|
case 'x': /* skip ACL dump */
|
|
@@ -563,8 +562,8 @@ main(int argc, char **argv)
|
|
* Non-option argument specifies database name as long as it wasn't
|
|
* already specified with -d / --dbname
|
|
*/
|
|
- if (optind < argc && dopt.dbname == NULL)
|
|
- dopt.dbname = argv[optind++];
|
|
+ if (optind < argc && dopt.cparams.dbname == NULL)
|
|
+ dopt.cparams.dbname = argv[optind++];
|
|
|
|
/* Complain if any arguments remain */
|
|
if (optind < argc)
|
|
@@ -677,7 +676,7 @@ main(int argc, char **argv)
|
|
* Open the database using the Archiver, so it knows about it. Errors mean
|
|
* death.
|
|
*/
|
|
- ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
|
|
+ ConnectDatabase(fout, &dopt.cparams, false);
|
|
setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
|
|
|
|
/*
|
|
@@ -860,6 +859,11 @@ main(int argc, char **argv)
|
|
ropt->filename = filename;
|
|
|
|
/* if you change this list, see dumpOptionsFromRestoreOptions */
|
|
+ ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
|
|
+ ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
|
|
+ ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
|
|
+ ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
|
|
+ ropt->cparams.promptPassword = dopt.cparams.promptPassword;
|
|
ropt->dropSchema = dopt.outputClean;
|
|
ropt->dataOnly = dopt.dataOnly;
|
|
ropt->schemaOnly = dopt.schemaOnly;
|
|
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
|
|
index 860a211a3c..ce03ded8ec 100644
|
|
--- a/src/bin/pg_dump/pg_restore.c
|
|
+++ b/src/bin/pg_dump/pg_restore.c
|
|
@@ -163,7 +163,7 @@ main(int argc, char **argv)
|
|
opts->createDB = 1;
|
|
break;
|
|
case 'd':
|
|
- opts->dbname = pg_strdup(optarg);
|
|
+ opts->cparams.dbname = pg_strdup(optarg);
|
|
break;
|
|
case 'e':
|
|
opts->exit_on_error = true;
|
|
@@ -177,7 +177,7 @@ main(int argc, char **argv)
|
|
break;
|
|
case 'h':
|
|
if (strlen(optarg) != 0)
|
|
- opts->pghost = pg_strdup(optarg);
|
|
+ opts->cparams.pghost = pg_strdup(optarg);
|
|
break;
|
|
|
|
case 'j': /* number of restore jobs */
|
|
@@ -206,7 +206,7 @@ main(int argc, char **argv)
|
|
|
|
case 'p':
|
|
if (strlen(optarg) != 0)
|
|
- opts->pgport = pg_strdup(optarg);
|
|
+ opts->cparams.pgport = pg_strdup(optarg);
|
|
break;
|
|
case 'R':
|
|
/* no-op, still accepted for backwards compatibility */
|
|
@@ -240,7 +240,7 @@ main(int argc, char **argv)
|
|
break;
|
|
|
|
case 'U':
|
|
- opts->username = pg_strdup(optarg);
|
|
+ opts->cparams.username = pg_strdup(optarg);
|
|
break;
|
|
|
|
case 'v': /* verbose */
|
|
@@ -248,11 +248,11 @@ main(int argc, char **argv)
|
|
break;
|
|
|
|
case 'w':
|
|
- opts->promptPassword = TRI_NO;
|
|
+ opts->cparams.promptPassword = TRI_NO;
|
|
break;
|
|
|
|
case 'W':
|
|
- opts->promptPassword = TRI_YES;
|
|
+ opts->cparams.promptPassword = TRI_YES;
|
|
break;
|
|
|
|
case 'x': /* skip ACL dump */
|
|
@@ -302,7 +302,7 @@ main(int argc, char **argv)
|
|
}
|
|
|
|
/* Should get at most one of -d and -f, else user is confused */
|
|
- if (opts->dbname)
|
|
+ if (opts->cparams.dbname)
|
|
{
|
|
if (opts->filename)
|
|
{
|
|
--
|
|
2.23.0
|
|
|