PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 }
147
148 keywords[i] = "fallback_application_name";
149 values[i] = progname;
150 i++;
151
152 new_pass = false;
154
155 if (!conn)
156 pg_fatal("could not connect to database \"%s\"", dbname);
157
158 if (PQstatus(conn) == CONNECTION_BAD &&
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 */
171 {
172 if (fail_on_error)
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)
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
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 */
243static char *
244constructConnStr(const char **keywords, const char **values)
245{
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)
261 firstkeyword = false;
264 }
265
266 connstr = pg_strdup(buf->data);
268 return connstr;
269}
270
271/*
272 * executeQuery
273 *
274 * Run a query, return the results, exit program on failure.
275 */
276PGresult *
277executeQuery(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 ||
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}
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:244
PGresult * executeQuery(PGconn *conn, const char *query)
Definition: connectdb.c:277
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