Skip to content

Commit d939462

Browse files
MahendraThalorCommitfest Bot
authored and
Commitfest Bot
committed
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 <[email protected]>
1 parent dbd437e commit d939462

File tree

9 files changed

+352
-345
lines changed

9 files changed

+352
-345
lines changed

src/bin/pg_dump/Makefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ OBJS = \
3131
compress_lz4.o \
3232
compress_none.o \
3333
compress_zstd.o \
34+
connectdb.o \
3435
dumputils.o \
3536
filter.o \
3637
parallel.o \
@@ -50,8 +51,8 @@ pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) | submake-libpq submake-libpg
5051
pg_restore: pg_restore.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
5152
$(CC) $(CFLAGS) pg_restore.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
5253

53-
pg_dumpall: pg_dumpall.o dumputils.o filter.o $(WIN32RES) | submake-libpq submake-libpgport submake-libpgfeutils
54-
$(CC) $(CFLAGS) pg_dumpall.o dumputils.o filter.o $(WIN32RES) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
54+
pg_dumpall: pg_dumpall.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
55+
$(CC) $(CFLAGS) pg_dumpall.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
5556

5657
install: all installdirs
5758
$(INSTALL_PROGRAM) pg_dump$(X) '$(DESTDIR)$(bindir)'/pg_dump$(X)

src/bin/pg_dump/connectdb.c

+294
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* connectdb.c
4+
* This is a common file connection to the database.
5+
*
6+
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
* IDENTIFICATION
10+
* src/bin/pg_dump/connectdb.c
11+
*
12+
*-------------------------------------------------------------------------
13+
*/
14+
15+
#include "postgres_fe.h"
16+
17+
#include "common/connect.h"
18+
#include "common/logging.h"
19+
#include "common/string.h"
20+
#include "connectdb.h"
21+
#include "dumputils.h"
22+
#include "fe_utils/string_utils.h"
23+
24+
static char *constructConnStr(const char **keywords, const char **values);
25+
26+
/*
27+
* ConnectDatabase
28+
*
29+
* Make a database connection with the given parameters. An
30+
* interactive password prompt is automatically issued if required.
31+
*
32+
* If fail_on_error is false, we return NULL without printing any message
33+
* on failure, but preserve any prompted password for the next try.
34+
*
35+
* On success, the 'connstr' is set to a connection string containing
36+
* the options used and 'server_version' is set to version so that caller
37+
* can use them.
38+
*/
39+
PGconn *
40+
ConnectDatabase(const char *dbname, const char *connection_string,
41+
const char *pghost, const char *pgport, const char *pguser,
42+
trivalue prompt_password, bool fail_on_error, const char *progname,
43+
const char **connstr, int *server_version, char *password,
44+
char *override_dbname)
45+
{
46+
PGconn *conn;
47+
bool new_pass;
48+
const char *remoteversion_str;
49+
int my_version;
50+
const char **keywords = NULL;
51+
const char **values = NULL;
52+
PQconninfoOption *conn_opts = NULL;
53+
int server_version_temp;
54+
55+
if (prompt_password == TRI_YES && !password)
56+
password = simple_prompt("Password: ", false);
57+
58+
/*
59+
* Start the connection. Loop until we have a password if requested by
60+
* backend.
61+
*/
62+
do
63+
{
64+
int argcount = 8;
65+
PQconninfoOption *conn_opt;
66+
char *err_msg = NULL;
67+
int i = 0;
68+
69+
free(keywords);
70+
free(values);
71+
PQconninfoFree(conn_opts);
72+
73+
/*
74+
* Merge the connection info inputs given in form of connection string
75+
* and other options. Explicitly discard any dbname value in the
76+
* connection string; otherwise, PQconnectdbParams() would interpret
77+
* that value as being itself a connection string.
78+
*/
79+
if (connection_string)
80+
{
81+
conn_opts = PQconninfoParse(connection_string, &err_msg);
82+
if (conn_opts == NULL)
83+
pg_fatal("%s", err_msg);
84+
85+
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
86+
{
87+
if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
88+
strcmp(conn_opt->keyword, "dbname") != 0)
89+
argcount++;
90+
}
91+
92+
keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
93+
values = pg_malloc0((argcount + 1) * sizeof(*values));
94+
95+
for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
96+
{
97+
if (conn_opt->val != NULL && conn_opt->val[0] != '\0' &&
98+
strcmp(conn_opt->keyword, "dbname") != 0)
99+
{
100+
keywords[i] = conn_opt->keyword;
101+
values[i] = conn_opt->val;
102+
i++;
103+
}
104+
}
105+
}
106+
else
107+
{
108+
keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
109+
values = pg_malloc0((argcount + 1) * sizeof(*values));
110+
}
111+
112+
if (pghost)
113+
{
114+
keywords[i] = "host";
115+
values[i] = pghost;
116+
i++;
117+
}
118+
if (pgport)
119+
{
120+
keywords[i] = "port";
121+
values[i] = pgport;
122+
i++;
123+
}
124+
if (pguser)
125+
{
126+
keywords[i] = "user";
127+
values[i] = pguser;
128+
i++;
129+
}
130+
if (password)
131+
{
132+
keywords[i] = "password";
133+
values[i] = password;
134+
i++;
135+
}
136+
if (dbname)
137+
{
138+
keywords[i] = "dbname";
139+
values[i] = dbname;
140+
i++;
141+
}
142+
if (override_dbname)
143+
{
144+
keywords[i] = "dbname";
145+
values[i++] = override_dbname;
146+
}
147+
148+
keywords[i] = "fallback_application_name";
149+
values[i] = progname;
150+
i++;
151+
152+
new_pass = false;
153+
conn = PQconnectdbParams(keywords, values, true);
154+
155+
if (!conn)
156+
pg_fatal("could not connect to database \"%s\"", dbname);
157+
158+
if (PQstatus(conn) == CONNECTION_BAD &&
159+
PQconnectionNeedsPassword(conn) &&
160+
!password &&
161+
prompt_password != TRI_NO)
162+
{
163+
PQfinish(conn);
164+
password = simple_prompt("Password: ", false);
165+
new_pass = true;
166+
}
167+
} while (new_pass);
168+
169+
/* check to see that the backend connection was successfully made */
170+
if (PQstatus(conn) == CONNECTION_BAD)
171+
{
172+
if (fail_on_error)
173+
pg_fatal("%s", PQerrorMessage(conn));
174+
else
175+
{
176+
PQfinish(conn);
177+
178+
free(keywords);
179+
free(values);
180+
PQconninfoFree(conn_opts);
181+
182+
return NULL;
183+
}
184+
}
185+
186+
/*
187+
* Ok, connected successfully. If requested, remember the options used, in
188+
* the form of a connection string.
189+
*/
190+
if (connstr)
191+
*connstr = constructConnStr(keywords, values);
192+
193+
free(keywords);
194+
free(values);
195+
PQconninfoFree(conn_opts);
196+
197+
/* Check version */
198+
remoteversion_str = PQparameterStatus(conn, "server_version");
199+
if (!remoteversion_str)
200+
pg_fatal("could not get server version");
201+
202+
server_version_temp = PQserverVersion(conn);
203+
if (server_version_temp == 0)
204+
pg_fatal("could not parse server version \"%s\"",
205+
remoteversion_str);
206+
207+
/* If requested, then copy server version to out variable. */
208+
if (server_version)
209+
*server_version = server_version_temp;
210+
211+
my_version = PG_VERSION_NUM;
212+
213+
/*
214+
* We allow the server to be back to 9.2, and up to any minor release of
215+
* our own major version. (See also version check in pg_dump.c.)
216+
*/
217+
if (my_version != server_version_temp
218+
&& (server_version_temp < 90200 ||
219+
(server_version_temp / 100) > (my_version / 100)))
220+
{
221+
pg_log_error("aborting because of server version mismatch");
222+
pg_log_error_detail("server version: %s; %s version: %s",
223+
remoteversion_str, progname, PG_VERSION);
224+
exit_nicely(1);
225+
}
226+
227+
PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL));
228+
229+
return conn;
230+
}
231+
232+
/*
233+
* constructConnStr
234+
*
235+
* Construct a connection string from the given keyword/value pairs. It is
236+
* used to pass the connection options to the pg_dump subprocess.
237+
*
238+
* The following parameters are excluded:
239+
* dbname - varies in each pg_dump invocation
240+
* password - it's not secure to pass a password on the command line
241+
* fallback_application_name - we'll let pg_dump set it
242+
*/
243+
static char *
244+
constructConnStr(const char **keywords, const char **values)
245+
{
246+
PQExpBuffer buf = createPQExpBuffer();
247+
char *connstr;
248+
int i;
249+
bool firstkeyword = true;
250+
251+
/* Construct a new connection string in key='value' format. */
252+
for (i = 0; keywords[i] != NULL; i++)
253+
{
254+
if (strcmp(keywords[i], "dbname") == 0 ||
255+
strcmp(keywords[i], "password") == 0 ||
256+
strcmp(keywords[i], "fallback_application_name") == 0)
257+
continue;
258+
259+
if (!firstkeyword)
260+
appendPQExpBufferChar(buf, ' ');
261+
firstkeyword = false;
262+
appendPQExpBuffer(buf, "%s=", keywords[i]);
263+
appendConnStrVal(buf, values[i]);
264+
}
265+
266+
connstr = pg_strdup(buf->data);
267+
destroyPQExpBuffer(buf);
268+
return connstr;
269+
}
270+
271+
/*
272+
* executeQuery
273+
*
274+
* Run a query, return the results, exit program on failure.
275+
*/
276+
PGresult *
277+
executeQuery(PGconn *conn, const char *query)
278+
{
279+
PGresult *res;
280+
281+
pg_log_info("executing %s", query);
282+
283+
res = PQexec(conn, query);
284+
if (!res ||
285+
PQresultStatus(res) != PGRES_TUPLES_OK)
286+
{
287+
pg_log_error("query failed: %s", PQerrorMessage(conn));
288+
pg_log_error_detail("Query was: %s", query);
289+
PQfinish(conn);
290+
exit_nicely(1);
291+
}
292+
293+
return res;
294+
}

src/bin/pg_dump/connectdb.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* connectdb.h
4+
* Common header file for connection to the database.
5+
*
6+
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
* IDENTIFICATION
10+
* src/bin/pg_dump/connectdb.h
11+
*
12+
*-------------------------------------------------------------------------
13+
*/
14+
#ifndef CONNECTDB_H
15+
#define CONNECTDB_H
16+
17+
#include "pg_backup.h"
18+
#include "pg_backup_utils.h"
19+
20+
extern PGconn *ConnectDatabase(const char *dbname, const char *connection_string, const char *pghost,
21+
const char *pgport, const char *pguser,
22+
trivalue prompt_password, bool fail_on_error,
23+
const char *progname, const char **connstr, int *server_version,
24+
char *password, char *override_dbname);
25+
extern PGresult *executeQuery(PGconn *conn, const char *query);
26+
#endif /* CONNECTDB_H */

src/bin/pg_dump/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pg_dump_common_sources = files(
66
'compress_lz4.c',
77
'compress_none.c',
88
'compress_zstd.c',
9+
'connectdb.c',
910
'dumputils.c',
1011
'filter.c',
1112
'parallel.c',

src/bin/pg_dump/pg_backup.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,9 @@ typedef void (*SetupWorkerPtrType) (Archive *AH);
293293
* Main archiver interface.
294294
*/
295295

296-
extern void ConnectDatabase(Archive *AHX,
297-
const ConnParams *cparams,
298-
bool isReconnect);
296+
extern void ConnectDatabaseAhx(Archive *AHX,
297+
const ConnParams *cparams,
298+
bool isReconnect);
299299
extern void DisconnectDatabase(Archive *AHX);
300300
extern PGconn *GetConnection(Archive *AHX);
301301

src/bin/pg_dump/pg_backup_archiver.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ RestoreArchive(Archive *AHX)
415415
AHX->minRemoteVersion = 0;
416416
AHX->maxRemoteVersion = 9999999;
417417

418-
ConnectDatabase(AHX, &ropt->cparams, false);
418+
ConnectDatabaseAhx(AHX, &ropt->cparams, false);
419419

420420
/*
421421
* If we're talking to the DB directly, don't send comments since they
@@ -4458,7 +4458,7 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
44584458
/*
44594459
* Now reconnect the single parent connection.
44604460
*/
4461-
ConnectDatabase((Archive *) AH, &ropt->cparams, true);
4461+
ConnectDatabaseAhx((Archive *) AH, &ropt->cparams, true);
44624462

44634463
/* re-establish fixed state */
44644464
_doSetFixedOutputState(AH);
@@ -5076,7 +5076,7 @@ CloneArchive(ArchiveHandle *AH)
50765076
* Connect our new clone object to the database, using the same connection
50775077
* parameters used for the original connection.
50785078
*/
5079-
ConnectDatabase((Archive *) clone, &clone->public.ropt->cparams, true);
5079+
ConnectDatabaseAhx((Archive *) clone, &clone->public.ropt->cparams, true);
50805080

50815081
/* re-establish fixed state */
50825082
if (AH->mode == archModeRead)

0 commit comments

Comments
 (0)