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
This commit is contained in:
Tom Lane 2020-09-24 18:19:38 -04:00
parent 55b7e2f4d7
commit a45bc8a4f6
6 changed files with 129 additions and 280 deletions

View File

@ -58,6 +58,20 @@ typedef enum _teSection
SECTION_POST_DATA /* stuff to be processed after data */ SECTION_POST_DATA /* stuff to be processed after data */
} teSection; } 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 typedef struct _restoreOptions
{ {
int createDB; /* Issue commands to create the database */ int createDB; /* Issue commands to create the database */
@ -107,12 +121,9 @@ typedef struct _restoreOptions
SimpleStringList tableNames; SimpleStringList tableNames;
int useDB; int useDB;
char *dbname; /* subject to expand_dbname */ ConnParams cparams; /* parameters to use if useDB */
char *pgport;
char *pghost;
char *username;
int noDataForFailedTables; int noDataForFailedTables;
trivalue promptPassword;
int exit_on_error; int exit_on_error;
int compression; int compression;
int suppressDumpWarnings; /* Suppress output of WARNING entries int suppressDumpWarnings; /* Suppress output of WARNING entries
@ -127,10 +138,7 @@ typedef struct _restoreOptions
typedef struct _dumpOptions typedef struct _dumpOptions
{ {
const char *dbname; /* subject to expand_dbname */ ConnParams cparams;
const char *pghost;
const char *pgport;
const char *username;
int binary_upgrade; int binary_upgrade;
@ -247,12 +255,9 @@ typedef void (*SetupWorkerPtrType) (Archive *AH);
* Main archiver interface. * Main archiver interface.
*/ */
extern void ConnectDatabase(Archive *AH, extern void ConnectDatabase(Archive *AHX,
const char *dbname, const ConnParams *cparams,
const char *pghost, bool isReconnect);
const char *pgport,
const char *username,
trivalue prompt_password);
extern void DisconnectDatabase(Archive *AHX); extern void DisconnectDatabase(Archive *AHX);
extern PGconn *GetConnection(Archive *AHX); extern PGconn *GetConnection(Archive *AHX);

View File

@ -165,6 +165,7 @@ InitDumpOptions(DumpOptions *opts)
memset(opts, 0, sizeof(DumpOptions)); memset(opts, 0, sizeof(DumpOptions));
/* set any fields that shouldn't default to zeroes */ /* set any fields that shouldn't default to zeroes */
opts->include_everything = true; opts->include_everything = true;
opts->cparams.promptPassword = TRI_DEFAULT;
opts->dumpSections = DUMP_UNSECTIONED; opts->dumpSections = DUMP_UNSECTIONED;
} }
@ -178,6 +179,11 @@ dumpOptionsFromRestoreOptions(RestoreOptions *ropt)
DumpOptions *dopt = NewDumpOptions(); DumpOptions *dopt = NewDumpOptions();
/* this is the inverse of what's at the end of pg_dump.c's main() */ /* 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->outputClean = ropt->dropSchema;
dopt->dataOnly = ropt->dataOnly; dopt->dataOnly = ropt->dataOnly;
dopt->schemaOnly = ropt->schemaOnly; dopt->schemaOnly = ropt->schemaOnly;
@ -410,9 +416,7 @@ RestoreArchive(Archive *AHX)
AHX->minRemoteVersion = 0; AHX->minRemoteVersion = 0;
AHX->maxRemoteVersion = 9999999; AHX->maxRemoteVersion = 9999999;
ConnectDatabase(AHX, ropt->dbname, ConnectDatabase(AHX, &ropt->cparams, false);
ropt->pghost, ropt->pgport, ropt->username,
ropt->promptPassword);
/* /*
* If we're talking to the DB directly, don't send comments since they * If we're talking to the DB directly, don't send comments since they
@ -832,16 +836,8 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
if (strcmp(te->desc, "DATABASE") == 0 || if (strcmp(te->desc, "DATABASE") == 0 ||
strcmp(te->desc, "DATABASE PROPERTIES") == 0) strcmp(te->desc, "DATABASE PROPERTIES") == 0)
{ {
PQExpBufferData connstr;
initPQExpBuffer(&connstr);
appendPQExpBufferStr(&connstr, "dbname=");
appendConnStrVal(&connstr, te->tag);
/* Abandon struct, but keep its buffer until process exit. */
pg_log_info("connecting to new database \"%s\"", te->tag); pg_log_info("connecting to new database \"%s\"", te->tag);
_reconnectToDB(AH, te->tag); _reconnectToDB(AH, te->tag);
ropt->dbname = connstr.data;
} }
} }
@ -973,7 +969,7 @@ NewRestoreOptions(void)
/* set any fields that shouldn't default to zeroes */ /* set any fields that shouldn't default to zeroes */
opts->format = archUnknown; opts->format = archUnknown;
opts->promptPassword = TRI_DEFAULT; opts->cparams.promptPassword = TRI_DEFAULT;
opts->dumpSections = DUMP_UNSECTIONED; opts->dumpSections = DUMP_UNSECTIONED;
return opts; return opts;
@ -2345,8 +2341,6 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
else else
AH->format = fmt; AH->format = fmt;
AH->promptPassword = TRI_DEFAULT;
switch (AH->format) switch (AH->format)
{ {
case archCustom: case archCustom:
@ -3207,27 +3201,20 @@ _doSetSessionAuth(ArchiveHandle *AH, const char *user)
* If we're currently restoring right into a database, this will * If we're currently restoring right into a database, this will
* actually establish a connection. Otherwise it puts a \connect into * actually establish a connection. Otherwise it puts a \connect into
* the script output. * the script output.
*
* NULL dbname implies reconnecting to the current DB (pretty useless).
*/ */
static void static void
_reconnectToDB(ArchiveHandle *AH, const char *dbname) _reconnectToDB(ArchiveHandle *AH, const char *dbname)
{ {
if (RestoringToDB(AH)) if (RestoringToDB(AH))
ReconnectToServer(AH, dbname, NULL); ReconnectToServer(AH, dbname);
else else
{ {
if (dbname) PQExpBufferData connectbuf;
{
PQExpBufferData connectbuf;
initPQExpBuffer(&connectbuf); initPQExpBuffer(&connectbuf);
appendPsqlMetaConnect(&connectbuf, dbname); appendPsqlMetaConnect(&connectbuf, dbname);
ahprintf(AH, "%s\n", connectbuf.data); ahprintf(AH, "%s\n", connectbuf.data);
termPQExpBuffer(&connectbuf); termPQExpBuffer(&connectbuf);
}
else
ahprintf(AH, "%s\n", "\\connect -\n");
} }
/* /*
@ -4159,9 +4146,7 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
/* /*
* Now reconnect the single parent connection. * Now reconnect the single parent connection.
*/ */
ConnectDatabase((Archive *) AH, ropt->dbname, ConnectDatabase((Archive *) AH, &ropt->cparams, true);
ropt->pghost, ropt->pgport, ropt->username,
ropt->promptPassword);
/* re-establish fixed state */ /* re-establish fixed state */
_doSetFixedOutputState(AH); _doSetFixedOutputState(AH);
@ -4823,54 +4808,15 @@ CloneArchive(ArchiveHandle *AH)
clone->public.n_errors = 0; clone->public.n_errors = 0;
/* /*
* Connect our new clone object to the database: In parallel restore the * Connect our new clone object to the database, using the same connection
* parent is already disconnected, because we can connect the worker * parameters used for the original connection.
* processes independently to the database (no snapshot sync required). In
* parallel backup we clone the parent's existing connection.
*/ */
ConnectDatabase((Archive *) clone, &clone->public.ropt->cparams, true);
/* re-establish fixed state */
if (AH->mode == archModeRead) 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);
/* re-establish fixed state */
_doSetFixedOutputState(clone); _doSetFixedOutputState(clone);
} /* in write case, setupDumpWorker will fix up connection state */
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);
appendPQExpBufferStr(&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 */
}
/* Let the format-specific code have a chance too */ /* Let the format-specific code have a chance too */
clone->ClonePtr(clone); clone->ClonePtr(clone);

View File

@ -303,7 +303,6 @@ struct _archiveHandle
/* Stuff for direct DB connection */ /* Stuff for direct DB connection */
char *archdbname; /* DB name *read* from archive */ char *archdbname; /* DB name *read* from archive */
trivalue promptPassword;
char *savedPassword; /* password for ropt->username, if known */ char *savedPassword; /* password for ropt->username, if known */
char *use_role; char *use_role;
PGconn *connection; PGconn *connection;
@ -471,7 +470,7 @@ extern void InitArchiveFmt_Tar(ArchiveHandle *AH);
extern bool isValidTarHeader(char *header); extern bool isValidTarHeader(char *header);
extern void ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser); extern void ReconnectToServer(ArchiveHandle *AH, const char *dbname);
extern void DropBlobIfExists(ArchiveHandle *AH, Oid oid); extern void DropBlobIfExists(ArchiveHandle *AH, Oid oid);
void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH); void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);

View File

@ -27,7 +27,6 @@
#include "pg_backup_utils.h" #include "pg_backup_utils.h"
static void _check_database_version(ArchiveHandle *AH); 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 notice_processor(void *arg, const char *message);
static void static void
@ -73,211 +72,100 @@ _check_database_version(ArchiveHandle *AH)
/* /*
* Reconnect to the server. If dbname is not NULL, use that database, * Reconnect to the server. If dbname is not NULL, use that database,
* else the one associated with the archive handle. If username is * else the one associated with the archive handle.
* not NULL, use that user name, else the one from the handle.
*/ */
void void
ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username) ReconnectToServer(ArchiveHandle *AH, const char *dbname)
{ {
PGconn *newConn; PGconn *oldConn = AH->connection;
const char *newdbname; RestoreOptions *ropt = AH->public.ropt;
const char *newusername;
if (!dbname)
newdbname = PQdb(AH->connection);
else
newdbname = dbname;
if (!username)
newusername = PQuser(AH->connection);
else
newusername = username;
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));
}
/*
* 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)
{
PQExpBufferData connstr;
PGconn *newConn;
const char *newdb;
const char *newuser;
char *password;
bool new_pass;
if (!reqdb)
newdb = PQdb(AH->connection);
else
newdb = reqdb;
if (!requser || strlen(requser) == 0)
newuser = PQuser(AH->connection);
else
newuser = requser;
pg_log_info("connecting to database \"%s\" as user \"%s\"",
newdb, newuser);
password = AH->savedPassword;
if (AH->promptPassword == TRI_YES && password == NULL)
password = simple_prompt("Password: ", false);
initPQExpBuffer(&connstr);
appendPQExpBufferStr(&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)
fatal("could not reconnect to database");
if (PQstatus(newConn) == CONNECTION_BAD)
{
if (!PQconnectionNeedsPassword(newConn))
fatal("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)
{
if (password && password != AH->savedPassword)
free(password);
password = simple_prompt("Password: ", false);
}
else
fatal("connection needs password");
new_pass = true;
}
} while (new_pass);
if (password && password != AH->savedPassword)
free(password);
/* /*
* We want to remember connection's actual password, whether or not we got * Save the dbname, if given, in override_dbname so that it will also
* it by prompting. So we don't just store the password variable. * affect any later reconnection attempt.
*/ */
if (PQconnectionUsedPassword(newConn)) if (dbname)
{ ropt->cparams.override_dbname = pg_strdup(dbname);
if (AH->savedPassword)
free(AH->savedPassword);
AH->savedPassword = pg_strdup(PQpass(newConn));
}
termPQExpBuffer(&connstr); /*
* 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 */
/* check for version mismatch */ ConnectDatabase((Archive *) AH, &ropt->cparams, true);
_check_database_version(AH);
PQsetNoticeProcessor(newConn, notice_processor, NULL); PQfinish(oldConn);
return newConn;
} }
/* /*
* Make a database connection with the given parameters. The * Make, or remake, a database connection with the given parameters.
* connection handle is returned, the parameters are stored in AHX.
* An interactive password prompt is automatically issued if required.
* *
* 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 * 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 * cache if the username keeps changing. In current usage, however, the
* username never does change, so one savedPassword is sufficient. * username never does change, so one savedPassword is sufficient.
*/ */
void void
ConnectDatabase(Archive *AHX, ConnectDatabase(Archive *AHX,
const char *dbname, const ConnParams *cparams,
const char *pghost, bool isReconnect)
const char *pgport,
const char *username,
trivalue prompt_password)
{ {
ArchiveHandle *AH = (ArchiveHandle *) AHX; ArchiveHandle *AH = (ArchiveHandle *) AHX;
trivalue prompt_password;
char *password; char *password;
bool new_pass; bool new_pass;
if (AH->connection) if (AH->connection)
fatal("already connected to a database"); fatal("already connected to a database");
/* Never prompt for a password during a reconnection */
prompt_password = isReconnect ? TRI_NO : cparams->promptPassword;
password = AH->savedPassword; password = AH->savedPassword;
if (prompt_password == TRI_YES && password == NULL) if (prompt_password == TRI_YES && password == NULL)
password = simple_prompt("Password: ", false); password = simple_prompt("Password: ", false);
AH->promptPassword = prompt_password;
/* /*
* Start the connection. Loop until we have a password if requested by * Start the connection. Loop until we have a password if requested by
* backend. * backend.
*/ */
do do
{ {
const char *keywords[7]; const char *keywords[8];
const char *values[7]; const char *values[8];
int i = 0;
keywords[0] = "host"; /*
values[0] = pghost; * If dbname is a connstring, its entries can override the other
keywords[1] = "port"; * values obtained from cparams; but in turn, override_dbname can
values[1] = pgport; * override the dbname component of it.
keywords[2] = "user"; */
values[2] = username; keywords[i] = "host";
keywords[3] = "password"; values[i++] = cparams->pghost;
values[3] = password; keywords[i] = "port";
keywords[4] = "dbname"; values[i++] = cparams->pgport;
values[4] = dbname; keywords[i] = "user";
keywords[5] = "fallback_application_name"; values[i++] = cparams->username;
values[5] = progname; keywords[i] = "password";
keywords[6] = NULL; values[i++] = password;
values[6] = NULL; 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; new_pass = false;
AH->connection = PQconnectdbParams(keywords, values, true); AH->connection = PQconnectdbParams(keywords, values, true);
@ -298,9 +186,16 @@ ConnectDatabase(Archive *AHX,
/* check to see that the backend connection was successfully made */ /* check to see that the backend connection was successfully made */
if (PQstatus(AH->connection) == CONNECTION_BAD) if (PQstatus(AH->connection) == CONNECTION_BAD)
fatal("connection to database \"%s\" failed: %s", {
PQdb(AH->connection) ? PQdb(AH->connection) : "", if (isReconnect)
PQerrorMessage(AH->connection)); fatal("reconnection to database \"%s\" failed: %s",
PQdb(AH->connection) ? PQdb(AH->connection) : "",
PQerrorMessage(AH->connection));
else
fatal("connection to database \"%s\" failed: %s",
PQdb(AH->connection) ? PQdb(AH->connection) : "",
PQerrorMessage(AH->connection));
}
/* Start strict; later phases may override this. */ /* Start strict; later phases may override this. */
PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH, PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,

View File

@ -314,7 +314,6 @@ main(int argc, char **argv)
char *use_role = NULL; char *use_role = NULL;
long rowsPerInsert; long rowsPerInsert;
int numWorkers = 1; int numWorkers = 1;
trivalue prompt_password = TRI_DEFAULT;
int compressLevel = -1; int compressLevel = -1;
int plainText = 0; int plainText = 0;
ArchiveFormat archiveFormat = archUnknown; ArchiveFormat archiveFormat = archUnknown;
@ -444,7 +443,7 @@ main(int argc, char **argv)
break; break;
case 'd': /* database name */ case 'd': /* database name */
dopt.dbname = pg_strdup(optarg); dopt.cparams.dbname = pg_strdup(optarg);
break; break;
case 'E': /* Dump encoding */ case 'E': /* Dump encoding */
@ -460,7 +459,7 @@ main(int argc, char **argv)
break; break;
case 'h': /* server host */ case 'h': /* server host */
dopt.pghost = pg_strdup(optarg); dopt.cparams.pghost = pg_strdup(optarg);
break; break;
case 'j': /* number of dump jobs */ case 'j': /* number of dump jobs */
@ -481,7 +480,7 @@ main(int argc, char **argv)
break; break;
case 'p': /* server port */ case 'p': /* server port */
dopt.pgport = pg_strdup(optarg); dopt.cparams.pgport = pg_strdup(optarg);
break; break;
case 'R': case 'R':
@ -506,7 +505,7 @@ main(int argc, char **argv)
break; break;
case 'U': case 'U':
dopt.username = pg_strdup(optarg); dopt.cparams.username = pg_strdup(optarg);
break; break;
case 'v': /* verbose */ case 'v': /* verbose */
@ -515,11 +514,11 @@ main(int argc, char **argv)
break; break;
case 'w': case 'w':
prompt_password = TRI_NO; dopt.cparams.promptPassword = TRI_NO;
break; break;
case 'W': case 'W':
prompt_password = TRI_YES; dopt.cparams.promptPassword = TRI_YES;
break; break;
case 'x': /* skip ACL dump */ case 'x': /* skip ACL dump */
@ -613,8 +612,8 @@ main(int argc, char **argv)
* Non-option argument specifies database name as long as it wasn't * Non-option argument specifies database name as long as it wasn't
* already specified with -d / --dbname * already specified with -d / --dbname
*/ */
if (optind < argc && dopt.dbname == NULL) if (optind < argc && dopt.cparams.dbname == NULL)
dopt.dbname = argv[optind++]; dopt.cparams.dbname = argv[optind++];
/* Complain if any arguments remain */ /* Complain if any arguments remain */
if (optind < argc) if (optind < argc)
@ -740,7 +739,7 @@ main(int argc, char **argv)
* Open the database using the Archiver, so it knows about it. Errors mean * Open the database using the Archiver, so it knows about it. Errors mean
* death. * 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); setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
/* /*
@ -918,6 +917,11 @@ main(int argc, char **argv)
ropt->filename = filename; ropt->filename = filename;
/* if you change this list, see dumpOptionsFromRestoreOptions */ /* 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->dropSchema = dopt.outputClean;
ropt->dataOnly = dopt.dataOnly; ropt->dataOnly = dopt.dataOnly;
ropt->schemaOnly = dopt.schemaOnly; ropt->schemaOnly = dopt.schemaOnly;

View File

@ -163,7 +163,7 @@ main(int argc, char **argv)
opts->createDB = 1; opts->createDB = 1;
break; break;
case 'd': case 'd':
opts->dbname = pg_strdup(optarg); opts->cparams.dbname = pg_strdup(optarg);
break; break;
case 'e': case 'e':
opts->exit_on_error = true; opts->exit_on_error = true;
@ -177,7 +177,7 @@ main(int argc, char **argv)
break; break;
case 'h': case 'h':
if (strlen(optarg) != 0) if (strlen(optarg) != 0)
opts->pghost = pg_strdup(optarg); opts->cparams.pghost = pg_strdup(optarg);
break; break;
case 'j': /* number of restore jobs */ case 'j': /* number of restore jobs */
@ -206,7 +206,7 @@ main(int argc, char **argv)
case 'p': case 'p':
if (strlen(optarg) != 0) if (strlen(optarg) != 0)
opts->pgport = pg_strdup(optarg); opts->cparams.pgport = pg_strdup(optarg);
break; break;
case 'R': case 'R':
/* no-op, still accepted for backwards compatibility */ /* no-op, still accepted for backwards compatibility */
@ -240,7 +240,7 @@ main(int argc, char **argv)
break; break;
case 'U': case 'U':
opts->username = pg_strdup(optarg); opts->cparams.username = pg_strdup(optarg);
break; break;
case 'v': /* verbose */ case 'v': /* verbose */
@ -249,11 +249,11 @@ main(int argc, char **argv)
break; break;
case 'w': case 'w':
opts->promptPassword = TRI_NO; opts->cparams.promptPassword = TRI_NO;
break; break;
case 'W': case 'W':
opts->promptPassword = TRI_YES; opts->cparams.promptPassword = TRI_YES;
break; break;
case 'x': /* skip ACL dump */ case 'x': /* skip ACL dump */
@ -303,14 +303,14 @@ main(int argc, char **argv)
} }
/* Complain if neither -f nor -d was specified (except if dumping TOC) */ /* Complain if neither -f nor -d was specified (except if dumping TOC) */
if (!opts->dbname && !opts->filename && !opts->tocSummary) if (!opts->cparams.dbname && !opts->filename && !opts->tocSummary)
{ {
pg_log_error("one of -d/--dbname and -f/--file must be specified"); pg_log_error("one of -d/--dbname and -f/--file must be specified");
exit_nicely(1); exit_nicely(1);
} }
/* Should get at most one of -d and -f, else user is confused */ /* Should get at most one of -d and -f, else user is confused */
if (opts->dbname) if (opts->cparams.dbname)
{ {
if (opts->filename) if (opts->filename)
{ {