Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * Facilities for frontend code to connect to and disconnect from databases.
4 : : *
5 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
6 : : * Portions Copyright (c) 1994, Regents of the University of California
7 : : *
8 : : * src/fe_utils/connect_utils.c
9 : : *
10 : : *-------------------------------------------------------------------------
11 : : */
12 : : #include "postgres_fe.h"
13 : :
14 : : #include "common/connect.h"
15 : : #include "common/logging.h"
16 : : #include "common/string.h"
17 : : #include "fe_utils/connect_utils.h"
18 : : #include "fe_utils/query_utils.h"
19 : :
20 : : /*
21 : : * Make a database connection with the given parameters.
22 : : *
23 : : * An interactive password prompt is automatically issued if needed and
24 : : * allowed by cparams->prompt_password.
25 : : *
26 : : * If allow_password_reuse is true, we will try to re-use any password
27 : : * given during previous calls to this routine. (Callers should not pass
28 : : * allow_password_reuse=true unless reconnecting to the same host+port+user
29 : : * as before, else we might create password exposure hazards.)
30 : : */
31 : : PGconn *
1164 rhaas@postgresql.org 32 :CBC 331 : connectDatabase(const ConnParams *cparams, const char *progname,
33 : : bool echo, bool fail_ok, bool allow_password_reuse)
34 : : {
35 : : PGconn *conn;
36 : : bool new_pass;
37 : : static char *password = NULL;
38 : :
39 : : /* Callers must supply at least dbname; other params can be NULL */
40 [ - + ]: 331 : Assert(cparams->dbname);
41 : :
42 [ + + - + ]: 331 : if (!allow_password_reuse && password)
43 : : {
1164 rhaas@postgresql.org 44 :UBC 0 : free(password);
45 : 0 : password = NULL;
46 : : }
47 : :
1164 rhaas@postgresql.org 48 [ - + - - ]:CBC 331 : if (cparams->prompt_password == TRI_YES && password == NULL)
1164 rhaas@postgresql.org 49 :UBC 0 : password = simple_prompt("Password: ", false);
50 : :
51 : : /*
52 : : * Start the connection. Loop until we have a password if requested by
53 : : * backend.
54 : : */
55 : : do
56 : : {
57 : : const char *keywords[8];
58 : : const char *values[8];
1164 rhaas@postgresql.org 59 :CBC 331 : int i = 0;
60 : :
61 : : /*
62 : : * If dbname is a connstring, its entries can override the other
63 : : * values obtained from cparams; but in turn, override_dbname can
64 : : * override the dbname component of it.
65 : : */
66 : 331 : keywords[i] = "host";
67 : 331 : values[i++] = cparams->pghost;
68 : 331 : keywords[i] = "port";
69 : 331 : values[i++] = cparams->pgport;
70 : 331 : keywords[i] = "user";
71 : 331 : values[i++] = cparams->pguser;
72 : 331 : keywords[i] = "password";
73 : 331 : values[i++] = password;
74 : 331 : keywords[i] = "dbname";
75 : 331 : values[i++] = cparams->dbname;
76 [ + + ]: 331 : if (cparams->override_dbname)
77 : : {
78 : 113 : keywords[i] = "dbname";
79 : 113 : values[i++] = cparams->override_dbname;
80 : : }
81 : 331 : keywords[i] = "fallback_application_name";
82 : 331 : values[i++] = progname;
83 : 331 : keywords[i] = NULL;
84 : 331 : values[i++] = NULL;
85 [ - + ]: 331 : Assert(i <= lengthof(keywords));
86 : :
87 : 331 : new_pass = false;
88 : 331 : conn = PQconnectdbParams(keywords, values, true);
89 : :
90 [ - + ]: 331 : if (!conn)
737 tgl@sss.pgh.pa.us 91 :UBC 0 : pg_fatal("could not connect to database %s: out of memory",
92 : : cparams->dbname);
93 : :
94 : : /*
95 : : * No luck? Trying asking (again) for a password.
96 : : */
1164 rhaas@postgresql.org 97 [ + + - + ]:CBC 336 : if (PQstatus(conn) == CONNECTION_BAD &&
1164 rhaas@postgresql.org 98 :UBC 0 : PQconnectionNeedsPassword(conn) &&
99 [ # # ]: 0 : cparams->prompt_password != TRI_NO)
100 : : {
101 : 0 : PQfinish(conn);
668 peter@eisentraut.org 102 : 0 : free(password);
1164 rhaas@postgresql.org 103 : 0 : password = simple_prompt("Password: ", false);
104 : 0 : new_pass = true;
105 : : }
1164 rhaas@postgresql.org 106 [ - + ]:CBC 331 : } while (new_pass);
107 : :
108 : : /* check to see that the backend connection was successfully made */
109 [ + + ]: 331 : if (PQstatus(conn) == CONNECTION_BAD)
110 : : {
111 [ - + ]: 5 : if (fail_ok)
112 : : {
1164 rhaas@postgresql.org 113 :UBC 0 : PQfinish(conn);
114 : 0 : return NULL;
115 : : }
737 tgl@sss.pgh.pa.us 116 :CBC 5 : pg_fatal("%s", PQerrorMessage(conn));
117 : : }
118 : :
119 : : /* Start strict; callers may override this. */
1164 rhaas@postgresql.org 120 : 326 : PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
121 : :
122 : 326 : return conn;
123 : : }
124 : :
125 : : /*
126 : : * Try to connect to the appropriate maintenance database.
127 : : *
128 : : * This differs from connectDatabase only in that it has a rule for
129 : : * inserting a default "dbname" if none was given (which is why cparams
130 : : * is not const). Note that cparams->dbname should typically come from
131 : : * a --maintenance-db command line parameter.
132 : : */
133 : : PGconn *
134 : 119 : connectMaintenanceDatabase(ConnParams *cparams,
135 : : const char *progname, bool echo)
136 : : {
137 : : PGconn *conn;
138 : :
139 : : /* If a maintenance database name was specified, just connect to it. */
140 [ - + ]: 119 : if (cparams->dbname)
1164 rhaas@postgresql.org 141 :UBC 0 : return connectDatabase(cparams, progname, echo, false, false);
142 : :
143 : : /* Otherwise, try postgres first and then template1. */
1164 rhaas@postgresql.org 144 :CBC 119 : cparams->dbname = "postgres";
145 : 119 : conn = connectDatabase(cparams, progname, echo, true, false);
146 [ - + ]: 119 : if (!conn)
147 : : {
1164 rhaas@postgresql.org 148 :UBC 0 : cparams->dbname = "template1";
149 : 0 : conn = connectDatabase(cparams, progname, echo, false, false);
150 : : }
1164 rhaas@postgresql.org 151 :CBC 119 : return conn;
152 : : }
153 : :
154 : : /*
155 : : * Disconnect the given connection, canceling any statement if one is active.
156 : : */
157 : : void
158 : 207 : disconnectDatabase(PGconn *conn)
159 : : {
160 [ - + ]: 207 : Assert(conn != NULL);
161 : :
162 [ - + ]: 207 : if (PQtransactionStatus(conn) == PQTRANS_ACTIVE)
163 : : {
27 alvherre@alvh.no-ip. 164 :UNC 0 : PGcancelConn *cancelConn = PQcancelCreate(conn);
165 : :
166 : 0 : (void) PQcancelBlocking(cancelConn);
167 : 0 : PQcancelFinish(cancelConn);
168 : : }
169 : :
1164 rhaas@postgresql.org 170 :CBC 207 : PQfinish(conn);
171 : 207 : }
|