1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-21 12:05:57 +03:00

Move common pg_dump code related to connections to a new file

ConnectDatabase is used by pg_dumpall, pg_restore and pg_dump so move
common code to new file.

new file name: connectdb.c

Author:    Mahendra Singh Thalor <mahi6run@gmail.com>
This commit is contained in:
Andrew Dunstan 2025-04-04 10:04:35 -04:00
parent ff3a7f0b68
commit c1da728106
9 changed files with 352 additions and 345 deletions

View File

@ -31,6 +31,7 @@ OBJS = \
compress_lz4.o \ compress_lz4.o \
compress_none.o \ compress_none.o \
compress_zstd.o \ compress_zstd.o \
connectdb.o \
dumputils.o \ dumputils.o \
filter.o \ filter.o \
parallel.o \ parallel.o \
@ -50,8 +51,8 @@ pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) | submake-libpq submake-libpg
pg_restore: pg_restore.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils pg_restore: pg_restore.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
$(CC) $(CFLAGS) pg_restore.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) $(CC) $(CFLAGS) pg_restore.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
pg_dumpall: pg_dumpall.o dumputils.o filter.o $(WIN32RES) | submake-libpq submake-libpgport submake-libpgfeutils pg_dumpall: pg_dumpall.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
$(CC) $(CFLAGS) pg_dumpall.o dumputils.o filter.o $(WIN32RES) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) $(CC) $(CFLAGS) pg_dumpall.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
install: all installdirs install: all installdirs
$(INSTALL_PROGRAM) pg_dump$(X) '$(DESTDIR)$(bindir)'/pg_dump$(X) $(INSTALL_PROGRAM) pg_dump$(X) '$(DESTDIR)$(bindir)'/pg_dump$(X)

294
src/bin/pg_dump/connectdb.c Normal file
View File

@ -0,0 +1,294 @@
/*-------------------------------------------------------------------------
*
* connectdb.c
* This is a common file connection to the database.
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/bin/pg_dump/connectdb.c
*
*-------------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include "common/connect.h"
#include "common/logging.h"
#include "common/string.h"
#include "connectdb.h"
#include "dumputils.h"
#include "fe_utils/string_utils.h"
static char *constructConnStr(const char **keywords, const char **values);
/*
* ConnectDatabase
*
* Make a database connection with the given parameters. An
* interactive password prompt is automatically issued if required.
*
* If fail_on_error is false, we return NULL without printing any message
* on failure, but preserve any prompted password for the next try.
*
* On success, the 'connstr' is set to a connection string containing
* the options used and 'server_version' is set to version so that caller
* can use them.
*/
PGconn *
ConnectDatabase(const char *dbname, const char *connection_string,
const char *pghost, const char *pgport, const char *pguser,
trivalue prompt_password, bool fail_on_error, const char *progname,
const char **connstr, int *server_version, char *password,
char *override_dbname)
{
PGconn *conn;
bool new_pass;
const char *remoteversion_str;
int my_version;
const char **keywords = NULL;
const char **values = NULL;
PQconninfoOption *conn_opts = NULL;
int server_version_temp;
if (prompt_password == TRI_YES && !password)
password = simple_prompt("Password: ", false);
/*
* Start the connection. Loop until we have a password if requested by
* backend.
*/
do
{
int argcount = 8;
PQconninfoOption *conn_opt;
char *err_msg = NULL;
int i = 0;
free(keywords);
free(values);
PQconninfoFree(conn_opts);
/*
* Merge the connection info inputs given in form of connection string
* and other options. Explicitly discard any dbname value in the
* connection string; otherwise, PQconnectdbParams() would interpret
* that value as being itself a connection string.
*/
if (connection_string)
{
conn_opts = PQconninfoParse(connection_string, &err_msg);
if (conn_opts == NULL)
pg_fatal("%s", err_msg);
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
{
if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
strcmp(conn_opt->keyword, "dbname") != 0)
argcount++;
}
keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
values = pg_malloc0((argcount + 1) * sizeof(*values));
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
{
if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
strcmp(conn_opt->keyword, "dbname") != 0)
{
keywords[i] = conn_opt->keyword;
values[i] = conn_opt->val;
i++;
}
}
}
else
{
keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
values = pg_malloc0((argcount + 1) * sizeof(*values));
}
if (pghost)
{
keywords[i] = "host";
values[i] = pghost;
i++;
}
if (pgport)
{
keywords[i] = "port";
values[i] = pgport;
i++;
}
if (pguser)
{
keywords[i] = "user";
values[i] = pguser;
i++;
}
if (password)
{
keywords[i] = "password";
values[i] = password;
i++;
}
if (dbname)
{
keywords[i] = "dbname";
values[i] = dbname;
i++;
}
if (override_dbname)
{
keywords[i] = "dbname";
values[i++] = override_dbname;
}
keywords[i] = "fallback_application_name";
values[i] = progname;
i++;
new_pass = false;
conn = PQconnectdbParams(keywords, values, true);
if (!conn)
pg_fatal("could not connect to database \"%s\"", dbname);
if (PQstatus(conn) == CONNECTION_BAD &&
PQconnectionNeedsPassword(conn) &&
!password &&
prompt_password != TRI_NO)
{
PQfinish(conn);
password = simple_prompt("Password: ", false);
new_pass = true;
}
} while (new_pass);
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) == CONNECTION_BAD)
{
if (fail_on_error)
pg_fatal("%s", PQerrorMessage(conn));
else
{
PQfinish(conn);
free(keywords);
free(values);
PQconninfoFree(conn_opts);
return NULL;
}
}
/*
* Ok, connected successfully. If requested, remember the options used, in
* the form of a connection string.
*/
if (connstr)
*connstr = constructConnStr(keywords, values);
free(keywords);
free(values);
PQconninfoFree(conn_opts);
/* Check version */
remoteversion_str = PQparameterStatus(conn, "server_version");
if (!remoteversion_str)
pg_fatal("could not get server version");
server_version_temp = PQserverVersion(conn);
if (server_version_temp == 0)
pg_fatal("could not parse server version \"%s\"",
remoteversion_str);
/* If requested, then copy server version to out variable. */
if (server_version)
*server_version = server_version_temp;
my_version = PG_VERSION_NUM;
/*
* We allow the server to be back to 9.2, and up to any minor release of
* our own major version. (See also version check in pg_dump.c.)
*/
if (my_version != server_version_temp
&& (server_version_temp < 90200 ||
(server_version_temp / 100) > (my_version / 100)))
{
pg_log_error("aborting because of server version mismatch");
pg_log_error_detail("server version: %s; %s version: %s",
remoteversion_str, progname, PG_VERSION);
exit_nicely(1);
}
PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL));
return conn;
}
/*
* constructConnStr
*
* Construct a connection string from the given keyword/value pairs. It is
* used to pass the connection options to the pg_dump subprocess.
*
* The following parameters are excluded:
* dbname - varies in each pg_dump invocation
* password - it's not secure to pass a password on the command line
* fallback_application_name - we'll let pg_dump set it
*/
static char *
constructConnStr(const char **keywords, const char **values)
{
PQExpBuffer buf = createPQExpBuffer();
char *connstr;
int i;
bool firstkeyword = true;
/* Construct a new connection string in key='value' format. */
for (i = 0; keywords[i] != NULL; i++)
{
if (strcmp(keywords[i], "dbname") == 0 ||
strcmp(keywords[i], "password") == 0 ||
strcmp(keywords[i], "fallback_application_name") == 0)
continue;
if (!firstkeyword)
appendPQExpBufferChar(buf, ' ');
firstkeyword = false;
appendPQExpBuffer(buf, "%s=", keywords[i]);
appendConnStrVal(buf, values[i]);
}
connstr = pg_strdup(buf->data);
destroyPQExpBuffer(buf);
return connstr;
}
/*
* executeQuery
*
* Run a query, return the results, exit program on failure.
*/
PGresult *
executeQuery(PGconn *conn, const char *query)
{
PGresult *res;
pg_log_info("executing %s", query);
res = PQexec(conn, query);
if (!res ||
PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("query failed: %s", PQerrorMessage(conn));
pg_log_error_detail("Query was: %s", query);
PQfinish(conn);
exit_nicely(1);
}
return res;
}

View File

@ -0,0 +1,26 @@
/*-------------------------------------------------------------------------
*
* connectdb.h
* Common header file for connection to the database.
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/bin/pg_dump/connectdb.h
*
*-------------------------------------------------------------------------
*/
#ifndef CONNECTDB_H
#define CONNECTDB_H
#include "pg_backup.h"
#include "pg_backup_utils.h"
extern PGconn *ConnectDatabase(const char *dbname, const char *connection_string, const char *pghost,
const char *pgport, const char *pguser,
trivalue prompt_password, bool fail_on_error,
const char *progname, const char **connstr, int *server_version,
char *password, char *override_dbname);
extern PGresult *executeQuery(PGconn *conn, const char *query);
#endif /* CONNECTDB_H */

View File

@ -6,6 +6,7 @@ pg_dump_common_sources = files(
'compress_lz4.c', 'compress_lz4.c',
'compress_none.c', 'compress_none.c',
'compress_zstd.c', 'compress_zstd.c',
'connectdb.c',
'dumputils.c', 'dumputils.c',
'filter.c', 'filter.c',
'parallel.c', 'parallel.c',

View File

@ -297,7 +297,7 @@ typedef void (*SetupWorkerPtrType) (Archive *AH);
* Main archiver interface. * Main archiver interface.
*/ */
extern void ConnectDatabase(Archive *AHX, extern void ConnectDatabaseAhx(Archive *AHX,
const ConnParams *cparams, const ConnParams *cparams,
bool isReconnect); bool isReconnect);
extern void DisconnectDatabase(Archive *AHX); extern void DisconnectDatabase(Archive *AHX);

View File

@ -414,7 +414,7 @@ RestoreArchive(Archive *AHX)
AHX->minRemoteVersion = 0; AHX->minRemoteVersion = 0;
AHX->maxRemoteVersion = 9999999; AHX->maxRemoteVersion = 9999999;
ConnectDatabase(AHX, &ropt->cparams, false); ConnectDatabaseAhx(AHX, &ropt->cparams, false);
/* /*
* 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
@ -4529,7 +4529,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->cparams, true); ConnectDatabaseAhx((Archive *) AH, &ropt->cparams, true);
/* re-establish fixed state */ /* re-establish fixed state */
_doSetFixedOutputState(AH); _doSetFixedOutputState(AH);
@ -5146,7 +5146,7 @@ CloneArchive(ArchiveHandle *AH)
* Connect our new clone object to the database, using the same connection * Connect our new clone object to the database, using the same connection
* parameters used for the original connection. * parameters used for the original connection.
*/ */
ConnectDatabase((Archive *) clone, &clone->public.ropt->cparams, true); ConnectDatabaseAhx((Archive *) clone, &clone->public.ropt->cparams, true);
/* re-establish fixed state */ /* re-establish fixed state */
if (AH->mode == archModeRead) if (AH->mode == archModeRead)

View File

@ -19,6 +19,7 @@
#include "common/connect.h" #include "common/connect.h"
#include "common/string.h" #include "common/string.h"
#include "connectdb.h"
#include "parallel.h" #include "parallel.h"
#include "pg_backup_archiver.h" #include "pg_backup_archiver.h"
#include "pg_backup_db.h" #include "pg_backup_db.h"
@ -86,9 +87,9 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname)
* ArchiveHandle's connCancel, before closing old connection. Otherwise * ArchiveHandle's connCancel, before closing old connection. Otherwise
* an ill-timed SIGINT could try to access a dead connection. * an ill-timed SIGINT could try to access a dead connection.
*/ */
AH->connection = NULL; /* dodge error check in ConnectDatabase */ AH->connection = NULL; /* dodge error check in ConnectDatabaseAhx */
ConnectDatabase((Archive *) AH, &ropt->cparams, true); ConnectDatabaseAhx((Archive *) AH, &ropt->cparams, true);
PQfinish(oldConn); PQfinish(oldConn);
} }
@ -105,14 +106,13 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname)
* username never does change, so one savedPassword is sufficient. * username never does change, so one savedPassword is sufficient.
*/ */
void void
ConnectDatabase(Archive *AHX, ConnectDatabaseAhx(Archive *AHX,
const ConnParams *cparams, const ConnParams *cparams,
bool isReconnect) bool isReconnect)
{ {
ArchiveHandle *AH = (ArchiveHandle *) AHX; ArchiveHandle *AH = (ArchiveHandle *) AHX;
trivalue prompt_password; trivalue prompt_password;
char *password; char *password;
bool new_pass;
if (AH->connection) if (AH->connection)
pg_fatal("already connected to a database"); pg_fatal("already connected to a database");
@ -125,69 +125,10 @@ ConnectDatabase(Archive *AHX,
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->connection = ConnectDatabase(cparams->dbname, NULL, cparams->pghost,
* Start the connection. Loop until we have a password if requested by cparams->pgport, cparams->username,
* backend. prompt_password, true,
*/ progname, NULL, NULL, password, cparams->override_dbname);
do
{
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);
if (!AH->connection)
pg_fatal("could not connect to database");
if (PQstatus(AH->connection) == CONNECTION_BAD &&
PQconnectionNeedsPassword(AH->connection) &&
password == NULL &&
prompt_password != TRI_NO)
{
PQfinish(AH->connection);
password = simple_prompt("Password: ", false);
new_pass = true;
}
} while (new_pass);
/* check to see that the backend connection was successfully made */
if (PQstatus(AH->connection) == CONNECTION_BAD)
{
if (isReconnect)
pg_fatal("reconnection failed: %s",
PQerrorMessage(AH->connection));
else
pg_fatal("%s",
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

@ -969,7 +969,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.cparams, false); ConnectDatabaseAhx(fout, &dopt.cparams, false);
setup_connection(fout, dumpencoding, dumpsnapshot, use_role); setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
/* /*

View File

@ -24,11 +24,11 @@
#include "common/hashfn_unstable.h" #include "common/hashfn_unstable.h"
#include "common/logging.h" #include "common/logging.h"
#include "common/string.h" #include "common/string.h"
#include "connectdb.h"
#include "dumputils.h" #include "dumputils.h"
#include "fe_utils/string_utils.h" #include "fe_utils/string_utils.h"
#include "filter.h" #include "filter.h"
#include "getopt_long.h" #include "getopt_long.h"
#include "pg_backup.h"
/* version string we expect back from pg_dump */ /* version string we expect back from pg_dump */
#define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n" #define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
@ -71,21 +71,14 @@ static void buildShSecLabels(PGconn *conn,
const char *catalog_name, Oid objectId, const char *catalog_name, Oid objectId,
const char *objtype, const char *objname, const char *objtype, const char *objname,
PQExpBuffer buffer); PQExpBuffer buffer);
static PGconn *connectDatabase(const char *dbname,
const char *connection_string, const char *pghost,
const char *pgport, const char *pguser,
trivalue prompt_password, bool fail_on_error);
static char *constructConnStr(const char **keywords, const char **values);
static PGresult *executeQuery(PGconn *conn, const char *query);
static void executeCommand(PGconn *conn, const char *query); static void executeCommand(PGconn *conn, const char *query);
static void expand_dbname_patterns(PGconn *conn, SimpleStringList *patterns, static void expand_dbname_patterns(PGconn *conn, SimpleStringList *patterns,
SimpleStringList *names); SimpleStringList *names);
static void read_dumpall_filters(const char *filename, SimpleStringList *pattern); static void read_dumpall_filters(const char *filename, SimpleStringList *pattern);
static char pg_dump_bin[MAXPGPATH]; static char pg_dump_bin[MAXPGPATH];
static const char *progname;
static PQExpBuffer pgdumpopts; static PQExpBuffer pgdumpopts;
static char *connstr = ""; static const char *connstr = "";
static bool output_clean = false; static bool output_clean = false;
static bool skip_acls = false; static bool skip_acls = false;
static bool verbose = false; static bool verbose = false;
@ -129,8 +122,6 @@ static char *filename = NULL;
static SimpleStringList database_exclude_patterns = {NULL, NULL}; static SimpleStringList database_exclude_patterns = {NULL, NULL};
static SimpleStringList database_exclude_names = {NULL, NULL}; static SimpleStringList database_exclude_names = {NULL, NULL};
#define exit_nicely(code) exit(code)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -499,19 +490,22 @@ main(int argc, char *argv[])
*/ */
if (pgdb) if (pgdb)
{ {
conn = connectDatabase(pgdb, connstr, pghost, pgport, pguser, conn = ConnectDatabase(pgdb, connstr, pghost, pgport, pguser,
prompt_password, false); prompt_password, false,
progname, &connstr, &server_version, NULL, NULL);
if (!conn) if (!conn)
pg_fatal("could not connect to database \"%s\"", pgdb); pg_fatal("could not connect to database \"%s\"", pgdb);
} }
else else
{ {
conn = connectDatabase("postgres", connstr, pghost, pgport, pguser, conn = ConnectDatabase("postgres", connstr, pghost, pgport, pguser,
prompt_password, false); prompt_password, false,
progname, &connstr, &server_version, NULL, NULL);
if (!conn) if (!conn)
conn = connectDatabase("template1", connstr, pghost, pgport, pguser, conn = ConnectDatabase("template1", connstr, pghost, pgport, pguser,
prompt_password, true); prompt_password, true,
progname, &connstr, &server_version, NULL, NULL);
if (!conn) if (!conn)
{ {
@ -1738,256 +1732,6 @@ buildShSecLabels(PGconn *conn, const char *catalog_name, Oid objectId,
destroyPQExpBuffer(sql); destroyPQExpBuffer(sql);
} }
/*
* Make a database connection with the given parameters. An
* interactive password prompt is automatically issued if required.
*
* If fail_on_error is false, we return NULL without printing any message
* on failure, but preserve any prompted password for the next try.
*
* On success, the global variable 'connstr' is set to a connection string
* containing the options used.
*/
static PGconn *
connectDatabase(const char *dbname, const char *connection_string,
const char *pghost, const char *pgport, const char *pguser,
trivalue prompt_password, bool fail_on_error)
{
PGconn *conn;
bool new_pass;
const char *remoteversion_str;
int my_version;
const char **keywords = NULL;
const char **values = NULL;
PQconninfoOption *conn_opts = NULL;
static char *password = NULL;
if (prompt_password == TRI_YES && !password)
password = simple_prompt("Password: ", false);
/*
* Start the connection. Loop until we have a password if requested by
* backend.
*/
do
{
int argcount = 6;
PQconninfoOption *conn_opt;
char *err_msg = NULL;
int i = 0;
free(keywords);
free(values);
PQconninfoFree(conn_opts);
/*
* Merge the connection info inputs given in form of connection string
* and other options. Explicitly discard any dbname value in the
* connection string; otherwise, PQconnectdbParams() would interpret
* that value as being itself a connection string.
*/
if (connection_string)
{
conn_opts = PQconninfoParse(connection_string, &err_msg);
if (conn_opts == NULL)
pg_fatal("%s", err_msg);
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
{
if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
strcmp(conn_opt->keyword, "dbname") != 0)
argcount++;
}
keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
values = pg_malloc0((argcount + 1) * sizeof(*values));
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
{
if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
strcmp(conn_opt->keyword, "dbname") != 0)
{
keywords[i] = conn_opt->keyword;
values[i] = conn_opt->val;
i++;
}
}
}
else
{
keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
values = pg_malloc0((argcount + 1) * sizeof(*values));
}
if (pghost)
{
keywords[i] = "host";
values[i] = pghost;
i++;
}
if (pgport)
{
keywords[i] = "port";
values[i] = pgport;
i++;
}
if (pguser)
{
keywords[i] = "user";
values[i] = pguser;
i++;
}
if (password)
{
keywords[i] = "password";
values[i] = password;
i++;
}
if (dbname)
{
keywords[i] = "dbname";
values[i] = dbname;
i++;
}
keywords[i] = "fallback_application_name";
values[i] = progname;
i++;
new_pass = false;
conn = PQconnectdbParams(keywords, values, true);
if (!conn)
pg_fatal("could not connect to database \"%s\"", dbname);
if (PQstatus(conn) == CONNECTION_BAD &&
PQconnectionNeedsPassword(conn) &&
!password &&
prompt_password != TRI_NO)
{
PQfinish(conn);
password = simple_prompt("Password: ", false);
new_pass = true;
}
} while (new_pass);
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) == CONNECTION_BAD)
{
if (fail_on_error)
pg_fatal("%s", PQerrorMessage(conn));
else
{
PQfinish(conn);
free(keywords);
free(values);
PQconninfoFree(conn_opts);
return NULL;
}
}
/*
* Ok, connected successfully. Remember the options used, in the form of a
* connection string.
*/
connstr = constructConnStr(keywords, values);
free(keywords);
free(values);
PQconninfoFree(conn_opts);
/* Check version */
remoteversion_str = PQparameterStatus(conn, "server_version");
if (!remoteversion_str)
pg_fatal("could not get server version");
server_version = PQserverVersion(conn);
if (server_version == 0)
pg_fatal("could not parse server version \"%s\"",
remoteversion_str);
my_version = PG_VERSION_NUM;
/*
* We allow the server to be back to 9.2, and up to any minor release of
* our own major version. (See also version check in pg_dump.c.)
*/
if (my_version != server_version
&& (server_version < 90200 ||
(server_version / 100) > (my_version / 100)))
{
pg_log_error("aborting because of server version mismatch");
pg_log_error_detail("server version: %s; %s version: %s",
remoteversion_str, progname, PG_VERSION);
exit_nicely(1);
}
PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL));
return conn;
}
/* ----------
* Construct a connection string from the given keyword/value pairs. It is
* used to pass the connection options to the pg_dump subprocess.
*
* The following parameters are excluded:
* dbname - varies in each pg_dump invocation
* password - it's not secure to pass a password on the command line
* fallback_application_name - we'll let pg_dump set it
* ----------
*/
static char *
constructConnStr(const char **keywords, const char **values)
{
PQExpBuffer buf = createPQExpBuffer();
char *connstr;
int i;
bool firstkeyword = true;
/* Construct a new connection string in key='value' format. */
for (i = 0; keywords[i] != NULL; i++)
{
if (strcmp(keywords[i], "dbname") == 0 ||
strcmp(keywords[i], "password") == 0 ||
strcmp(keywords[i], "fallback_application_name") == 0)
continue;
if (!firstkeyword)
appendPQExpBufferChar(buf, ' ');
firstkeyword = false;
appendPQExpBuffer(buf, "%s=", keywords[i]);
appendConnStrVal(buf, values[i]);
}
connstr = pg_strdup(buf->data);
destroyPQExpBuffer(buf);
return connstr;
}
/*
* Run a query, return the results, exit program on failure.
*/
static PGresult *
executeQuery(PGconn *conn, const char *query)
{
PGresult *res;
pg_log_info("executing %s", query);
res = PQexec(conn, query);
if (!res ||
PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("query failed: %s", PQerrorMessage(conn));
pg_log_error_detail("Query was: %s", query);
PQfinish(conn);
exit_nicely(1);
}
return res;
}
/* /*
* As above for a SQL command (which returns nothing). * As above for a SQL command (which returns nothing).
*/ */