Age Owner 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-2023, 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 database+user
29 : * as before, else we might create password exposure hazards.)
30 : */
31 : PGconn *
793 rhaas 32 CBC 245 : 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 245 : Assert(cparams->dbname);
41 :
42 245 : if (!allow_password_reuse && password)
43 : {
793 rhaas 44 UBC 0 : free(password);
45 0 : password = NULL;
46 : }
47 :
793 rhaas 48 CBC 245 : if (cparams->prompt_password == TRI_YES && password == NULL)
793 rhaas 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];
793 rhaas 59 CBC 245 : 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 245 : keywords[i] = "host";
67 245 : values[i++] = cparams->pghost;
68 245 : keywords[i] = "port";
69 245 : values[i++] = cparams->pgport;
70 245 : keywords[i] = "user";
71 245 : values[i++] = cparams->pguser;
72 245 : keywords[i] = "password";
73 245 : values[i++] = password;
74 245 : keywords[i] = "dbname";
75 245 : values[i++] = cparams->dbname;
76 245 : if (cparams->override_dbname)
77 : {
78 77 : keywords[i] = "dbname";
79 77 : values[i++] = cparams->override_dbname;
80 : }
81 245 : keywords[i] = "fallback_application_name";
82 245 : values[i++] = progname;
83 245 : keywords[i] = NULL;
84 245 : values[i++] = NULL;
85 245 : Assert(i <= lengthof(keywords));
86 :
87 245 : new_pass = false;
88 245 : conn = PQconnectdbParams(keywords, values, true);
89 :
90 245 : if (!conn)
366 tgl 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 : */
793 rhaas 97 CBC 247 : if (PQstatus(conn) == CONNECTION_BAD &&
98 2 : PQconnectionNeedsPassword(conn) &&
793 rhaas 99 UBC 0 : cparams->prompt_password != TRI_NO)
100 : {
101 0 : PQfinish(conn);
297 peter 102 UNC 0 : free(password);
793 rhaas 103 UBC 0 : password = simple_prompt("Password: ", false);
793 rhaas 104 UIC 0 : new_pass = true;
793 rhaas 105 ECB : }
793 rhaas 106 GIC 245 : } while (new_pass);
107 :
793 rhaas 108 ECB : /* check to see that the backend connection was successfully made */
793 rhaas 109 GIC 245 : if (PQstatus(conn) == CONNECTION_BAD)
793 rhaas 110 ECB : {
793 rhaas 111 GIC 2 : if (fail_ok)
793 rhaas 112 EUB : {
793 rhaas 113 UBC 0 : PQfinish(conn);
793 rhaas 114 UIC 0 : return NULL;
793 rhaas 115 ECB : }
366 tgl 116 GIC 2 : pg_fatal("%s", PQerrorMessage(conn));
117 : }
118 :
793 rhaas 119 ECB : /* Start strict; callers may override this. */
793 rhaas 120 GIC 243 : PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
793 rhaas 121 ECB :
793 rhaas 122 GIC 243 : 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 : */
793 rhaas 133 ECB : PGconn *
793 rhaas 134 GIC 86 : connectMaintenanceDatabase(ConnParams *cparams,
135 : const char *progname, bool echo)
136 : {
137 : PGconn *conn;
138 :
793 rhaas 139 ECB : /* If a maintenance database name was specified, just connect to it. */
793 rhaas 140 GBC 86 : if (cparams->dbname)
793 rhaas 141 UIC 0 : return connectDatabase(cparams, progname, echo, false, false);
142 :
793 rhaas 143 ECB : /* Otherwise, try postgres first and then template1. */
793 rhaas 144 CBC 86 : cparams->dbname = "postgres";
145 86 : conn = connectDatabase(cparams, progname, echo, true, false);
793 rhaas 146 GIC 86 : if (!conn)
793 rhaas 147 EUB : {
793 rhaas 148 UBC 0 : cparams->dbname = "template1";
793 rhaas 149 UIC 0 : conn = connectDatabase(cparams, progname, echo, false, false);
793 rhaas 150 ECB : }
793 rhaas 151 GIC 86 : return conn;
152 : }
153 :
154 : /*
155 : * Disconnect the given connection, canceling any statement if one is active.
156 : */
793 rhaas 157 ECB : void
793 rhaas 158 GIC 158 : disconnectDatabase(PGconn *conn)
159 : {
160 : char errbuf[256];
793 rhaas 161 ECB :
793 rhaas 162 GIC 158 : Assert(conn != NULL);
793 rhaas 163 ECB :
793 rhaas 164 GIC 158 : if (PQtransactionStatus(conn) == PQTRANS_ACTIVE)
165 : {
166 : PGcancel *cancel;
793 rhaas 167 EUB :
793 rhaas 168 UIC 0 : if ((cancel = PQgetCancel(conn)))
793 rhaas 169 EUB : {
793 rhaas 170 UBC 0 : (void) PQcancel(cancel, errbuf, sizeof(errbuf));
793 rhaas 171 UIC 0 : PQfreeCancel(cancel);
172 : }
173 : }
793 rhaas 174 ECB :
793 rhaas 175 CBC 158 : PQfinish(conn);
793 rhaas 176 GIC 158 : }
|