doc: clarify that pg_global can _only_ be used for system tabs.
[pgsql.git] / src / fe_utils / connect_utils.c
blob7d45f5c6090494ecdd1c4eeba0c82d5eba255fe3
1 /*-------------------------------------------------------------------------
3 * Facilities for frontend code to connect to and disconnect from databases.
5 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
8 * src/fe_utils/connect_utils.c
10 *-------------------------------------------------------------------------
12 #include "postgres_fe.h"
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"
21 * Make a database connection with the given parameters.
23 * An interactive password prompt is automatically issued if needed and
24 * allowed by cparams->prompt_password.
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.)
31 PGconn *
32 connectDatabase(const ConnParams *cparams, const char *progname,
33 bool echo, bool fail_ok, bool allow_password_reuse)
35 PGconn *conn;
36 bool new_pass;
37 static char *password = NULL;
39 /* Callers must supply at least dbname; other params can be NULL */
40 Assert(cparams->dbname);
42 if (!allow_password_reuse && password)
44 free(password);
45 password = NULL;
48 if (cparams->prompt_password == TRI_YES && password == NULL)
49 password = simple_prompt("Password: ", false);
52 * Start the connection. Loop until we have a password if requested by
53 * backend.
57 const char *keywords[8];
58 const char *values[8];
59 int i = 0;
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.
66 keywords[i] = "host";
67 values[i++] = cparams->pghost;
68 keywords[i] = "port";
69 values[i++] = cparams->pgport;
70 keywords[i] = "user";
71 values[i++] = cparams->pguser;
72 keywords[i] = "password";
73 values[i++] = password;
74 keywords[i] = "dbname";
75 values[i++] = cparams->dbname;
76 if (cparams->override_dbname)
78 keywords[i] = "dbname";
79 values[i++] = cparams->override_dbname;
81 keywords[i] = "fallback_application_name";
82 values[i++] = progname;
83 keywords[i] = NULL;
84 values[i++] = NULL;
85 Assert(i <= lengthof(keywords));
87 new_pass = false;
88 conn = PQconnectdbParams(keywords, values, true);
90 if (!conn)
91 pg_fatal("could not connect to database %s: out of memory",
92 cparams->dbname);
95 * No luck? Trying asking (again) for a password.
97 if (PQstatus(conn) == CONNECTION_BAD &&
98 PQconnectionNeedsPassword(conn) &&
99 cparams->prompt_password != TRI_NO)
101 PQfinish(conn);
102 free(password);
103 password = simple_prompt("Password: ", false);
104 new_pass = true;
106 } while (new_pass);
108 /* check to see that the backend connection was successfully made */
109 if (PQstatus(conn) == CONNECTION_BAD)
111 if (fail_ok)
113 PQfinish(conn);
114 return NULL;
116 pg_fatal("%s", PQerrorMessage(conn));
119 /* Start strict; callers may override this. */
120 PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
122 return conn;
126 * Try to connect to the appropriate maintenance database.
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.
133 PGconn *
134 connectMaintenanceDatabase(ConnParams *cparams,
135 const char *progname, bool echo)
137 PGconn *conn;
139 /* If a maintenance database name was specified, just connect to it. */
140 if (cparams->dbname)
141 return connectDatabase(cparams, progname, echo, false, false);
143 /* Otherwise, try postgres first and then template1. */
144 cparams->dbname = "postgres";
145 conn = connectDatabase(cparams, progname, echo, true, false);
146 if (!conn)
148 cparams->dbname = "template1";
149 conn = connectDatabase(cparams, progname, echo, false, false);
151 return conn;
155 * Disconnect the given connection, canceling any statement if one is active.
157 void
158 disconnectDatabase(PGconn *conn)
160 char errbuf[256];
162 Assert(conn != NULL);
164 if (PQtransactionStatus(conn) == PQTRANS_ACTIVE)
166 PGcancel *cancel;
168 if ((cancel = PQgetCancel(conn)))
170 (void) PQcancel(cancel, errbuf, sizeof(errbuf));
171 PQfreeCancel(cancel);
175 PQfinish(conn);