mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +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:
parent
ff3a7f0b68
commit
c1da728106
@ -31,6 +31,7 @@ OBJS = \
|
||||
compress_lz4.o \
|
||||
compress_none.o \
|
||||
compress_zstd.o \
|
||||
connectdb.o \
|
||||
dumputils.o \
|
||||
filter.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
|
||||
$(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
|
||||
$(CC) $(CFLAGS) pg_dumpall.o dumputils.o filter.o $(WIN32RES) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
|
||||
pg_dumpall: pg_dumpall.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
|
||||
$(CC) $(CFLAGS) pg_dumpall.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
|
||||
|
||||
install: all installdirs
|
||||
$(INSTALL_PROGRAM) pg_dump$(X) '$(DESTDIR)$(bindir)'/pg_dump$(X)
|
||||
|
294
src/bin/pg_dump/connectdb.c
Normal file
294
src/bin/pg_dump/connectdb.c
Normal 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;
|
||||
}
|
26
src/bin/pg_dump/connectdb.h
Normal file
26
src/bin/pg_dump/connectdb.h
Normal 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 */
|
@ -6,6 +6,7 @@ pg_dump_common_sources = files(
|
||||
'compress_lz4.c',
|
||||
'compress_none.c',
|
||||
'compress_zstd.c',
|
||||
'connectdb.c',
|
||||
'dumputils.c',
|
||||
'filter.c',
|
||||
'parallel.c',
|
||||
|
@ -297,7 +297,7 @@ typedef void (*SetupWorkerPtrType) (Archive *AH);
|
||||
* Main archiver interface.
|
||||
*/
|
||||
|
||||
extern void ConnectDatabase(Archive *AHX,
|
||||
extern void ConnectDatabaseAhx(Archive *AHX,
|
||||
const ConnParams *cparams,
|
||||
bool isReconnect);
|
||||
extern void DisconnectDatabase(Archive *AHX);
|
||||
|
@ -414,7 +414,7 @@ RestoreArchive(Archive *AHX)
|
||||
AHX->minRemoteVersion = 0;
|
||||
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
|
||||
@ -4529,7 +4529,7 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
|
||||
/*
|
||||
* Now reconnect the single parent connection.
|
||||
*/
|
||||
ConnectDatabase((Archive *) AH, &ropt->cparams, true);
|
||||
ConnectDatabaseAhx((Archive *) AH, &ropt->cparams, true);
|
||||
|
||||
/* re-establish fixed state */
|
||||
_doSetFixedOutputState(AH);
|
||||
@ -5146,7 +5146,7 @@ CloneArchive(ArchiveHandle *AH)
|
||||
* Connect our new clone object to the database, using the same 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 */
|
||||
if (AH->mode == archModeRead)
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "common/connect.h"
|
||||
#include "common/string.h"
|
||||
#include "connectdb.h"
|
||||
#include "parallel.h"
|
||||
#include "pg_backup_archiver.h"
|
||||
#include "pg_backup_db.h"
|
||||
@ -86,9 +87,9 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname)
|
||||
* 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 */
|
||||
AH->connection = NULL; /* dodge error check in ConnectDatabaseAhx */
|
||||
|
||||
ConnectDatabase((Archive *) AH, &ropt->cparams, true);
|
||||
ConnectDatabaseAhx((Archive *) AH, &ropt->cparams, true);
|
||||
|
||||
PQfinish(oldConn);
|
||||
}
|
||||
@ -105,14 +106,13 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname)
|
||||
* username never does change, so one savedPassword is sufficient.
|
||||
*/
|
||||
void
|
||||
ConnectDatabase(Archive *AHX,
|
||||
ConnectDatabaseAhx(Archive *AHX,
|
||||
const ConnParams *cparams,
|
||||
bool isReconnect)
|
||||
{
|
||||
ArchiveHandle *AH = (ArchiveHandle *) AHX;
|
||||
trivalue prompt_password;
|
||||
char *password;
|
||||
bool new_pass;
|
||||
|
||||
if (AH->connection)
|
||||
pg_fatal("already connected to a database");
|
||||
@ -125,69 +125,10 @@ ConnectDatabase(Archive *AHX,
|
||||
if (prompt_password == TRI_YES && password == NULL)
|
||||
password = simple_prompt("Password: ", false);
|
||||
|
||||
/*
|
||||
* Start the connection. Loop until we have a password if requested by
|
||||
* backend.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
AH->connection = ConnectDatabase(cparams->dbname, NULL, cparams->pghost,
|
||||
cparams->pgport, cparams->username,
|
||||
prompt_password, true,
|
||||
progname, NULL, NULL, password, cparams->override_dbname);
|
||||
|
||||
/* Start strict; later phases may override this. */
|
||||
PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
|
||||
|
@ -969,7 +969,7 @@ main(int argc, char **argv)
|
||||
* Open the database using the Archiver, so it knows about it. Errors mean
|
||||
* death.
|
||||
*/
|
||||
ConnectDatabase(fout, &dopt.cparams, false);
|
||||
ConnectDatabaseAhx(fout, &dopt.cparams, false);
|
||||
setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
|
||||
|
||||
/*
|
||||
|
@ -24,11 +24,11 @@
|
||||
#include "common/hashfn_unstable.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/string.h"
|
||||
#include "connectdb.h"
|
||||
#include "dumputils.h"
|
||||
#include "fe_utils/string_utils.h"
|
||||
#include "filter.h"
|
||||
#include "getopt_long.h"
|
||||
#include "pg_backup.h"
|
||||
|
||||
/* version string we expect back from pg_dump */
|
||||
#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 *objtype, const char *objname,
|
||||
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 expand_dbname_patterns(PGconn *conn, SimpleStringList *patterns,
|
||||
SimpleStringList *names);
|
||||
static void read_dumpall_filters(const char *filename, SimpleStringList *pattern);
|
||||
|
||||
static char pg_dump_bin[MAXPGPATH];
|
||||
static const char *progname;
|
||||
static PQExpBuffer pgdumpopts;
|
||||
static char *connstr = "";
|
||||
static const char *connstr = "";
|
||||
static bool output_clean = false;
|
||||
static bool skip_acls = false;
|
||||
static bool verbose = false;
|
||||
@ -129,8 +122,6 @@ static char *filename = NULL;
|
||||
static SimpleStringList database_exclude_patterns = {NULL, NULL};
|
||||
static SimpleStringList database_exclude_names = {NULL, NULL};
|
||||
|
||||
#define exit_nicely(code) exit(code)
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@ -499,19 +490,22 @@ main(int argc, char *argv[])
|
||||
*/
|
||||
if (pgdb)
|
||||
{
|
||||
conn = connectDatabase(pgdb, connstr, pghost, pgport, pguser,
|
||||
prompt_password, false);
|
||||
conn = ConnectDatabase(pgdb, connstr, pghost, pgport, pguser,
|
||||
prompt_password, false,
|
||||
progname, &connstr, &server_version, NULL, NULL);
|
||||
|
||||
if (!conn)
|
||||
pg_fatal("could not connect to database \"%s\"", pgdb);
|
||||
}
|
||||
else
|
||||
{
|
||||
conn = connectDatabase("postgres", connstr, pghost, pgport, pguser,
|
||||
prompt_password, false);
|
||||
conn = ConnectDatabase("postgres", connstr, pghost, pgport, pguser,
|
||||
prompt_password, false,
|
||||
progname, &connstr, &server_version, NULL, NULL);
|
||||
if (!conn)
|
||||
conn = connectDatabase("template1", connstr, pghost, pgport, pguser,
|
||||
prompt_password, true);
|
||||
conn = ConnectDatabase("template1", connstr, pghost, pgport, pguser,
|
||||
prompt_password, true,
|
||||
progname, &connstr, &server_version, NULL, NULL);
|
||||
|
||||
if (!conn)
|
||||
{
|
||||
@ -1738,256 +1732,6 @@ buildShSecLabels(PGconn *conn, const char *catalog_name, Oid objectId,
|
||||
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).
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user