PostgreSQL Source Code  git master
connect_utils.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * Facilities for frontend code to connect to and disconnect from databases.
4  *
5  * Portions Copyright (c) 1996-2022, 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 *
32 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  Assert(cparams->dbname);
41 
42  if (!allow_password_reuse && password)
43  {
44  free(password);
45  password = NULL;
46  }
47 
48  if (cparams->prompt_password == TRI_YES && password == NULL)
49  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];
59  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  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)
77  {
78  keywords[i] = "dbname";
79  values[i++] = cparams->override_dbname;
80  }
81  keywords[i] = "fallback_application_name";
82  values[i++] = progname;
83  keywords[i] = NULL;
84  values[i++] = NULL;
85  Assert(i <= lengthof(keywords));
86 
87  new_pass = false;
88  conn = PQconnectdbParams(keywords, values, true);
89 
90  if (!conn)
91  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  */
97  if (PQstatus(conn) == CONNECTION_BAD &&
99  cparams->prompt_password != TRI_NO)
100  {
101  PQfinish(conn);
102  free(password);
103  password = simple_prompt("Password: ", false);
104  new_pass = true;
105  }
106  } while (new_pass);
107 
108  /* check to see that the backend connection was successfully made */
109  if (PQstatus(conn) == CONNECTION_BAD)
110  {
111  if (fail_ok)
112  {
113  PQfinish(conn);
114  return NULL;
115  }
116  pg_fatal("%s", PQerrorMessage(conn));
117  }
118 
119  /* Start strict; callers may override this. */
121 
122  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 *
135  const char *progname, bool echo)
136 {
137  PGconn *conn;
138 
139  /* If a maintenance database name was specified, just connect to it. */
140  if (cparams->dbname)
141  return connectDatabase(cparams, progname, echo, false, false);
142 
143  /* Otherwise, try postgres first and then template1. */
144  cparams->dbname = "postgres";
145  conn = connectDatabase(cparams, progname, echo, true, false);
146  if (!conn)
147  {
148  cparams->dbname = "template1";
149  conn = connectDatabase(cparams, progname, echo, false, false);
150  }
151  return conn;
152 }
153 
154 /*
155  * Disconnect the given connection, canceling any statement if one is active.
156  */
157 void
159 {
160  char errbuf[256];
161 
162  Assert(conn != NULL);
163 
165  {
166  PGcancel *cancel;
167 
168  if ((cancel = PQgetCancel(conn)))
169  {
170  (void) PQcancel(cancel, errbuf, sizeof(errbuf));
171  PQfreeCancel(cancel);
172  }
173  }
174 
175  PQfinish(conn);
176 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define lengthof(array)
Definition: c.h:745
#define ALWAYS_SECURE_SEARCH_PATH_SQL
Definition: connect.h:25
void disconnectDatabase(PGconn *conn)
PGconn * connectDatabase(const ConnParams *cparams, const char *progname, bool echo, bool fail_ok, bool allow_password_reuse)
Definition: connect_utils.c:32
PGconn * connectMaintenanceDatabase(ConnParams *cparams, const char *progname, bool echo)
PGcancel * PQgetCancel(PGconn *conn)
Definition: fe-connect.c:4303
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:655
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:6790
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6886
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6835
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize)
Definition: fe-connect.c:4417
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6782
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4198
void PQfreeCancel(PGcancel *cancel)
Definition: fe-connect.c:4371
#define free(a)
Definition: header.h:65
int i
Definition: isn.c:73
@ CONNECTION_BAD
Definition: libpq-fe.h:61
@ PQTRANS_ACTIVE
Definition: libpq-fe.h:119
Assert(fmt[strlen(fmt) - 1] !='\n')
const char * progname
Definition: main.c:50
#define pg_fatal(...)
static PGresult * executeQuery(PGconn *conn, const char *query)
Definition: pg_dumpall.c:1696
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
static char * password
Definition: streamutil.c:53
PGconn * conn
Definition: streamutil.c:54
const char * pguser
Definition: connect_utils.h:31
char * override_dbname
Definition: pg_backup.h:89
char * pgport
Definition: pg_backup.h:83
char * pghost
Definition: pg_backup.h:84
char * dbname
Definition: pg_backup.h:82
enum trivalue prompt_password
Definition: connect_utils.h:32
@ TRI_YES
Definition: vacuumlo.c:38
@ TRI_NO
Definition: vacuumlo.c:37