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:
parent
ff3a7f0b68
commit
c1da728106
@ -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
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_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',
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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).
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user