PostgreSQL Source Code git master
connectdb.c
Go to the documentation of this file.
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"
23
24static 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 */
39PGconn *
40ConnectDatabase(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
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 */
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 i++;
147 }
148
149 keywords[i] = "fallback_application_name";
150 values[i] = progname;
151 i++;
152
153 new_pass = false;
155
156 if (!conn)
157 pg_fatal("could not connect to database \"%s\"", dbname);
158
159 if (PQstatus(conn) == CONNECTION_BAD &&
161 !password &&
162 prompt_password != TRI_NO)
163 {
164 PQfinish(conn);
165 password = simple_prompt("Password: ", false);
166 new_pass = true;
167 }
168 } while (new_pass);
169
170 /* check to see that the backend connection was successfully made */
172 {
173 if (fail_on_error)
175 else
176 {
177 PQfinish(conn);
178
179 free(keywords);
180 free(values);
181 PQconninfoFree(conn_opts);
182
183 return NULL;
184 }
185 }
186
187 /*
188 * Ok, connected successfully. If requested, remember the options used, in
189 * the form of a connection string.
190 */
191 if (connstr)
193
194 free(keywords);
195 free(values);
196 PQconninfoFree(conn_opts);
197
198 /* Check version */
199 remoteversion_str = PQparameterStatus(conn, "server_version");
200 if (!remoteversion_str)
201 pg_fatal("could not get server version");
202
203 server_version_temp = PQserverVersion(conn);
204 if (server_version_temp == 0)
205 pg_fatal("could not parse server version \"%s\"",
206 remoteversion_str);
207
208 /* If requested, then copy server version to out variable. */
209 if (server_version)
210 *server_version = server_version_temp;
211
212 my_version = PG_VERSION_NUM;
213
214 /*
215 * We allow the server to be back to 9.2, and up to any minor release of
216 * our own major version. (See also version check in pg_dump.c.)
217 */
218 if (my_version != server_version_temp
219 && (server_version_temp < 90200 ||
220 (server_version_temp / 100) > (my_version / 100)))
221 {
222 pg_log_error("aborting because of server version mismatch");
223 pg_log_error_detail("server version: %s; %s version: %s",
224 remoteversion_str, progname, PG_VERSION);
225 exit_nicely(1);
226 }
227
229
230 return conn;
231}
232
233/*
234 * constructConnStr
235 *
236 * Construct a connection string from the given keyword/value pairs. It is
237 * used to pass the connection options to the pg_dump subprocess.
238 *
239 * The following parameters are excluded:
240 * dbname - varies in each pg_dump invocation
241 * password - it's not secure to pass a password on the command line
242 * fallback_application_name - we'll let pg_dump set it
243 */
244static char *
245constructConnStr(const char **keywords, const char **values)
246{
248 char *connstr;
249 int i;
250 bool firstkeyword = true;
251
252 /* Construct a new connection string in key='value' format. */
253 for (i = 0; keywords[i] != NULL; i++)
254 {
255 if (strcmp(keywords[i], "dbname") == 0 ||
256 strcmp(keywords[i], "password") == 0 ||
257 strcmp(keywords[i], "fallback_application_name") == 0)
258 continue;
259
260 if (!firstkeyword)
262 firstkeyword = false;
265 }
266
267 connstr = pg_strdup(buf->data);
269 return connstr;
270}
271
272/*
273 * executeQuery
274 *
275 * Run a query, return the results, exit program on failure.
276 */
277PGresult *
278executeQuery(PGconn *conn, const char *query)
279{
280 PGresult *res;
281
282 pg_log_info("executing %s", query);
283
284 res = PQexec(conn, query);
285 if (!res ||
287 {
288 pg_log_error("query failed: %s", PQerrorMessage(conn));
289 pg_log_error_detail("Query was: %s", query);
290 PQfinish(conn);
291 exit_nicely(1);
292 }
293
294 return res;
295}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define ALWAYS_SECURE_SEARCH_PATH_SQL
Definition: connect.h:25
static char * constructConnStr(const char **keywords, const char **values)
Definition: connectdb.c:245
PGresult * executeQuery(PGconn *conn, const char *query)
Definition: connectdb.c:278
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)
Definition: connectdb.c:40
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:7609
void PQconninfoFree(PQconninfoOption *connOptions)
Definition: fe-connect.c:7434
PQconninfoOption * PQconninfoParse(const char *conninfo, char **errmsg)
Definition: fe-connect.c:6150
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
Definition: fe-connect.c:7574
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:7672
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7556
void PQfinish(PGconn *conn)
Definition: fe-connect.c:5290
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7619
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:758
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3411
void PQclear(PGresult *res)
Definition: fe-exec.c:721
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2262
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
#define free(a)
Definition: header.h:65
int i
Definition: isn.c:77
static const JsonPathKeyword keywords[]
@ CONNECTION_BAD
Definition: libpq-fe.h:85
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:128
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_info(...)
Definition: logging.h:124
#define pg_log_error_detail(...)
Definition: logging.h:109
const char * progname
Definition: main.c:44
void exit_nicely(int code)
#define pg_fatal(...)
static const char * connstr
Definition: pg_dumpall.c:84
static int server_version
Definition: pg_dumpall.c:113
static char * buf
Definition: pg_test_fsync.c:72
static const char * pghost
Definition: pgbench.c:295
static const char * pgport
Definition: pgbench.c:296
PQExpBuffer createPQExpBuffer(void)
Definition: pqexpbuffer.c:72
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void destroyPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:114
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
static char * password
Definition: streamutil.c:51
char * connection_string
Definition: streamutil.c:45
char * dbname
Definition: streamutil.c:49
PGconn * conn
Definition: streamutil.c:52
void appendConnStrVal(PQExpBuffer buf, const char *str)
Definition: string_utils.c:698
trivalue
Definition: vacuumlo.c:35
@ TRI_YES
Definition: vacuumlo.c:38
@ TRI_NO
Definition: vacuumlo.c:37