Age Owner Branch data TLA Line data Source code
1 : : /* src/interfaces/ecpg/ecpglib/connect.c */
2 : :
3 : : #define POSTGRES_ECPG_INTERNAL
4 : : #include "postgres_fe.h"
5 : :
6 : : #include "ecpg-pthread-win32.h"
7 : : #include "ecpgerrno.h"
8 : : #include "ecpglib.h"
9 : : #include "ecpglib_extern.h"
10 : : #include "ecpgtype.h"
11 : : #include "sqlca.h"
12 : :
13 : : #ifdef HAVE_USELOCALE
14 : : locale_t ecpg_clocale = (locale_t) 0;
15 : : #endif
16 : :
17 : : static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
18 : : static pthread_key_t actual_connection_key;
19 : : static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT;
20 : : static struct connection *actual_connection = NULL;
21 : : static struct connection *all_connections = NULL;
22 : :
23 : : static void
7336 meskes@postgresql.or 24 :CBC 57 : ecpg_actual_connection_init(void)
25 : : {
7168 bruce@momjian.us 26 : 57 : pthread_key_create(&actual_connection_key, NULL);
7336 meskes@postgresql.or 27 : 57 : }
28 : :
29 : : void
6402 bruce@momjian.us 30 : 6358 : ecpg_pthreads_init(void)
31 : : {
6465 meskes@postgresql.or 32 : 6358 : pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
33 : 6358 : }
34 : :
35 : : static struct connection *
7593 36 : 520 : ecpg_get_connection_nr(const char *connection_name)
37 : : {
7559 bruce@momjian.us 38 : 520 : struct connection *ret = NULL;
39 : :
40 [ + - + + ]: 520 : if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
41 : : {
670 tgl@sss.pgh.pa.us 42 : 41 : ecpg_pthreads_init(); /* ensure actual_connection_key is valid */
43 : :
7336 meskes@postgresql.or 44 : 41 : ret = pthread_getspecific(actual_connection_key);
45 : :
46 : : /*
47 : : * if no connection in TSD for this thread, get the global default
48 : : * connection and hope the user knows what they're doing (i.e. using
49 : : * their own mutex to protect that connection from concurrent accesses
50 : : */
670 tgl@sss.pgh.pa.us 51 [ + + ]: 41 : if (ret == NULL)
52 : : /* no TSD connection, going for global */
6940 meskes@postgresql.or 53 : 1 : ret = actual_connection;
54 : : }
55 : : else
56 : : {
57 : : struct connection *con;
58 : :
7559 bruce@momjian.us 59 [ + + ]: 1920 : for (con = all_connections; con != NULL; con = con->next)
60 : : {
61 [ + + ]: 1832 : if (strcmp(connection_name, con->name) == 0)
62 : 391 : break;
63 : : }
64 : 479 : ret = con;
65 : : }
66 : :
2432 peter_e@gmx.net 67 : 520 : return ret;
68 : : }
69 : :
70 : : struct connection *
6038 meskes@postgresql.or 71 : 3937 : ecpg_get_connection(const char *connection_name)
72 : : {
7559 bruce@momjian.us 73 : 3937 : struct connection *ret = NULL;
74 : :
7335 75 [ + + - + ]: 3937 : if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
76 : : {
670 tgl@sss.pgh.pa.us 77 : 3529 : ecpg_pthreads_init(); /* ensure actual_connection_key is valid */
78 : :
7335 bruce@momjian.us 79 : 3529 : ret = pthread_getspecific(actual_connection_key);
80 : :
81 : : /*
82 : : * if no connection in TSD for this thread, get the global default
83 : : * connection and hope the user knows what they're doing (i.e. using
84 : : * their own mutex to protect that connection from concurrent accesses
85 : : */
670 tgl@sss.pgh.pa.us 86 [ + + ]: 3529 : if (ret == NULL)
87 : : /* no TSD connection here either, using global */
6756 bruce@momjian.us 88 : 54 : ret = actual_connection;
89 : : }
90 : : else
91 : : {
7335 92 : 408 : pthread_mutex_lock(&connections_mutex);
93 : :
94 : 408 : ret = ecpg_get_connection_nr(connection_name);
95 : :
96 : 408 : pthread_mutex_unlock(&connections_mutex);
97 : : }
98 : :
2432 peter_e@gmx.net 99 : 3937 : return ret;
100 : : }
101 : :
102 : : static void
2489 tgl@sss.pgh.pa.us 103 : 123 : ecpg_finish(struct connection *act)
104 : : {
7700 meskes@postgresql.or 105 [ + - ]: 123 : if (act != NULL)
106 : : {
107 : : struct ECPGtype_information_cache *cache,
108 : : *ptr;
109 : :
6038 110 : 123 : ecpg_deallocate_all_conn(0, ECPG_COMPAT_PGSQL, act);
7700 111 : 123 : PQfinish(act->connection);
112 : :
113 : : /*
114 : : * no need to lock connections_mutex - we're always called by
115 : : * ECPGdisconnect or ECPGconnect, which are holding the lock
116 : : */
117 : :
118 : : /* remove act from the list */
119 [ + + ]: 123 : if (act == all_connections)
120 : 75 : all_connections = act->next;
121 : : else
122 : : {
123 : : struct connection *con;
124 : :
125 [ + - + + ]: 239 : for (con = all_connections; con->next && con->next != act; con = con->next);
126 [ + - ]: 48 : if (con->next)
127 : 48 : con->next = act->next;
128 : : }
129 : :
7168 bruce@momjian.us 130 [ + - ]: 123 : if (pthread_getspecific(actual_connection_key) == act)
131 : 123 : pthread_setspecific(actual_connection_key, all_connections);
7700 meskes@postgresql.or 132 [ + + ]: 123 : if (actual_connection == act)
133 : 75 : actual_connection = all_connections;
134 : :
5597 135 [ + - ]: 123 : ecpg_log("ecpg_finish: connection %s closed\n", act->name ? act->name : "(null)");
136 : :
6038 137 [ + + ]: 2509 : for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ecpg_free(ptr));
138 : 123 : ecpg_free(act->name);
139 : 123 : ecpg_free(act);
140 : : /* delete cursor variables when last connection gets closed */
4483 141 [ + + ]: 123 : if (all_connections == NULL)
142 : : {
143 : : struct var_list *iv_ptr;
144 : :
145 [ + + ]: 82 : for (; ivlist; iv_ptr = ivlist, ivlist = ivlist->next, ecpg_free(iv_ptr));
146 : : }
147 : : }
148 : : else
5812 peter_e@gmx.net 149 :UBC 0 : ecpg_log("ecpg_finish: called an extra time\n");
7700 meskes@postgresql.or 150 :CBC 123 : }
151 : :
152 : : bool
153 : 43 : ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
154 : : {
6038 155 : 43 : struct connection *con = ecpg_get_connection(connection_name);
156 : : PGresult *results;
157 : :
158 [ - + ]: 43 : if (!ecpg_init(con, connection_name, lineno))
2432 peter_e@gmx.net 159 :UBC 0 : return false;
160 : :
5812 peter_e@gmx.net 161 :CBC 43 : ecpg_log("ECPGsetcommit on line %d: action \"%s\"; connection \"%s\"\n", lineno, mode, con->name);
162 : :
4900 rhaas@postgresql.org 163 [ - + - - ]: 43 : if (con->autocommit && strncmp(mode, "off", strlen("off")) == 0)
164 : : {
4931 meskes@postgresql.or 165 [ # # ]:UBC 0 : if (PQtransactionStatus(con->connection) == PQTRANS_IDLE)
166 : : {
6088 167 : 0 : results = PQexec(con->connection, "begin transaction");
6038 168 [ # # ]: 0 : if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
7700 169 : 0 : return false;
170 : 0 : PQclear(results);
171 : : }
172 : 0 : con->autocommit = false;
173 : : }
4900 rhaas@postgresql.org 174 [ + - + + ]:CBC 43 : else if (!con->autocommit && strncmp(mode, "on", strlen("on")) == 0)
175 : : {
4931 meskes@postgresql.or 176 [ - + ]: 40 : if (PQtransactionStatus(con->connection) != PQTRANS_IDLE)
177 : : {
6088 meskes@postgresql.or 178 :UBC 0 : results = PQexec(con->connection, "commit");
6038 179 [ # # ]: 0 : if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
7700 180 : 0 : return false;
181 : 0 : PQclear(results);
182 : : }
7700 meskes@postgresql.or 183 :CBC 40 : con->autocommit = true;
184 : : }
185 : :
186 : 43 : return true;
187 : : }
188 : :
189 : : bool
190 : 2 : ECPGsetconn(int lineno, const char *connection_name)
191 : : {
6038 192 : 2 : struct connection *con = ecpg_get_connection(connection_name);
193 : :
194 [ - + ]: 2 : if (!ecpg_init(con, connection_name, lineno))
2432 peter_e@gmx.net 195 :UBC 0 : return false;
196 : :
7336 meskes@postgresql.or 197 :CBC 2 : pthread_setspecific(actual_connection_key, con);
7700 198 : 2 : return true;
199 : : }
200 : :
201 : :
202 : : static void
7562 peter_e@gmx.net 203 : 2 : ECPGnoticeReceiver(void *arg, const PGresult *result)
204 : : {
7539 205 : 2 : char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
206 : 2 : char *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
7609 bruce@momjian.us 207 : 2 : struct sqlca_t *sqlca = ECPGget_sqlca();
208 : : int sqlcode;
209 : :
3226 meskes@postgresql.or 210 [ - + ]: 2 : if (sqlca == NULL)
211 : : {
3226 meskes@postgresql.or 212 :UBC 0 : ecpg_log("out of memory");
213 : 0 : return;
214 : : }
215 : :
216 : : (void) arg; /* keep the compiler quiet */
7555 peter_e@gmx.net 217 [ - + ]:CBC 2 : if (sqlstate == NULL)
7555 peter_e@gmx.net 218 :UBC 0 : sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR;
219 : :
6402 bruce@momjian.us 220 [ - + ]:CBC 2 : if (message == NULL) /* Shouldn't happen, but need to be sure */
5568 peter_e@gmx.net 221 :UBC 0 : message = ecpg_gettext("empty message text");
222 : :
223 : : /* these are not warnings */
7559 bruce@momjian.us 224 [ + + ]:CBC 2 : if (strncmp(sqlstate, "00", 2) == 0)
7700 meskes@postgresql.or 225 : 1 : return;
226 : :
5812 peter_e@gmx.net 227 : 1 : ecpg_log("ECPGnoticeReceiver: %s\n", message);
228 : :
229 : : /* map to SQLCODE for backward compatibility */
7559 bruce@momjian.us 230 [ - + ]: 1 : if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME) == 0)
7562 peter_e@gmx.net 231 :UBC 0 : sqlcode = ECPG_WARNING_UNKNOWN_PORTAL;
7559 bruce@momjian.us 232 [ - + ]:CBC 1 : else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION) == 0)
7562 peter_e@gmx.net 233 :UBC 0 : sqlcode = ECPG_WARNING_IN_TRANSACTION;
7559 bruce@momjian.us 234 [ - + ]:CBC 1 : else if (strcmp(sqlstate, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION) == 0)
7562 peter_e@gmx.net 235 :UBC 0 : sqlcode = ECPG_WARNING_NO_TRANSACTION;
7559 bruce@momjian.us 236 [ - + ]:CBC 1 : else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR) == 0)
7562 peter_e@gmx.net 237 :UBC 0 : sqlcode = ECPG_WARNING_PORTAL_EXISTS;
238 : : else
7562 peter_e@gmx.net 239 :CBC 1 : sqlcode = 0;
240 : :
241 : 1 : strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
242 : 1 : sqlca->sqlcode = sqlcode;
7609 bruce@momjian.us 243 : 1 : sqlca->sqlwarn[2] = 'W';
244 : 1 : sqlca->sqlwarn[0] = 'W';
245 : :
7562 peter_e@gmx.net 246 : 1 : strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
247 : 1 : sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
248 : 1 : sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
249 : :
6038 meskes@postgresql.or 250 : 1 : ecpg_log("raising sqlcode %d\n", sqlcode);
251 : : }
252 : :
253 : : /* this contains some quick hacks, needs to be cleaned up, but it works */
254 : : bool
7599 255 : 131 : ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
256 : : {
7609 bruce@momjian.us 257 : 131 : struct sqlca_t *sqlca = ECPGget_sqlca();
7599 meskes@postgresql.or 258 : 131 : enum COMPAT_MODE compat = c;
259 : : struct connection *this;
260 : : int i,
4326 bruce@momjian.us 261 : 131 : connect_params = 0;
6038 meskes@postgresql.or 262 [ + - ]: 131 : char *dbname = name ? ecpg_strdup(name, lineno) : NULL,
7700 263 : 131 : *host = NULL,
264 : : *tmp,
265 : 131 : *port = NULL,
266 : 131 : *realname = NULL,
4454 267 : 131 : *options = NULL;
268 : : const char **conn_keywords;
269 : : const char **conn_values;
270 : :
3226 271 [ - + ]: 131 : if (sqlca == NULL)
272 : : {
3226 meskes@postgresql.or 273 :UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
274 : : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
275 : 0 : ecpg_free(dbname);
276 : 0 : return false;
277 : : }
278 : :
6038 meskes@postgresql.or 279 :CBC 131 : ecpg_init_sqlca(sqlca);
280 : :
281 : : /*
282 : : * clear auto_mem structure because some error handling functions might
283 : : * access it
284 : : */
285 : 131 : ecpg_clear_auto_mem();
286 : :
7598 287 [ + + - + ]: 131 : if (INFORMIX_MODE(compat))
288 : : {
289 : : char *envname;
290 : :
291 : : /*
292 : : * Informix uses an environment variable DBPATH that overrides the
293 : : * connection parameters given here. We do the same with PG_DBPATH as
294 : : * the syntax is different.
295 : : */
7599 296 : 6 : envname = getenv("PG_DBPATH");
297 [ - + ]: 6 : if (envname)
298 : : {
6038 meskes@postgresql.or 299 :UBC 0 : ecpg_free(dbname);
300 : 0 : dbname = ecpg_strdup(envname, lineno);
301 : : }
302 : : }
303 : :
7700 meskes@postgresql.or 304 [ - + - - ]:CBC 131 : if (dbname == NULL && connection_name == NULL)
7700 meskes@postgresql.or 305 :UBC 0 : connection_name = "DEFAULT";
306 : :
6465 meskes@postgresql.or 307 :CBC 131 : ecpg_pthreads_init();
308 : :
309 : : /* check if the identifier is unique */
6038 310 [ + + ]: 131 : if (ecpg_get_connection(connection_name))
311 : : {
312 : 2 : ecpg_free(dbname);
313 : 2 : ecpg_log("ECPGconnect: connection identifier %s is already in use\n",
314 : : connection_name);
6470 315 : 2 : return false;
316 : : }
317 : :
6038 318 [ - + ]: 129 : if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL)
319 : : {
3226 meskes@postgresql.or 320 :UBC 0 : ecpg_free(dbname);
6470 321 : 0 : return false;
322 : : }
323 : :
7045 meskes@postgresql.or 324 [ + - ]:CBC 129 : if (dbname != NULL)
325 : : {
326 : : /* get the detail information from dbname */
6440 327 [ + - + + ]: 129 : if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
7045 328 : 5 : {
329 : 6 : int offset = 0;
330 : :
331 : : /*
332 : : * only allow protocols tcp and unix
333 : : */
334 [ - + ]: 6 : if (strncmp(dbname, "tcp:", 4) == 0)
7045 meskes@postgresql.or 335 :UBC 0 : offset = 4;
7045 meskes@postgresql.or 336 [ + - ]:CBC 6 : else if (strncmp(dbname, "unix:", 5) == 0)
337 : 6 : offset = 5;
338 : :
339 [ + - ]: 6 : if (strncmp(dbname + offset, "postgresql://", strlen("postgresql://")) == 0)
340 : : {
341 : :
342 : : /*------
343 : : * new style:
344 : : * <tcp|unix>:postgresql://server[:port][/db-name][?options]
345 : : *------
346 : : */
347 : 6 : offset += strlen("postgresql://");
348 : :
349 : 6 : tmp = strrchr(dbname + offset, '?');
350 [ + + ]: 6 : if (tmp != NULL) /* options given */
351 : : {
6038 352 : 2 : options = ecpg_strdup(tmp + 1, lineno);
7045 353 : 2 : *tmp = '\0';
354 : : }
355 : :
356 : 6 : tmp = last_dir_separator(dbname + offset);
357 [ + - ]: 6 : if (tmp != NULL) /* database name given */
358 : : {
5862 359 [ + + ]: 6 : if (tmp[1] != '\0') /* non-empty database name */
360 : : {
361 : 5 : realname = ecpg_strdup(tmp + 1, lineno);
4440 362 : 5 : connect_params++;
363 : : }
7045 364 : 6 : *tmp = '\0';
365 : : }
366 : :
367 : 6 : tmp = strrchr(dbname + offset, ':');
1158 tgl@sss.pgh.pa.us 368 [ - + ]: 6 : if (tmp != NULL) /* port number given */
369 : : {
7045 meskes@postgresql.or 370 :UBC 0 : *tmp = '\0';
1158 tgl@sss.pgh.pa.us 371 : 0 : port = ecpg_strdup(tmp + 1, lineno);
372 : 0 : connect_params++;
373 : : }
374 : :
7045 meskes@postgresql.or 375 [ + - ]:CBC 6 : if (strncmp(dbname, "unix:", 5) == 0)
376 : : {
377 : : /*
378 : : * The alternative of using "127.0.0.1" here is deprecated
379 : : * and undocumented; we'll keep it for backward
380 : : * compatibility's sake, but not extend it to allow IPv6.
381 : : */
1158 tgl@sss.pgh.pa.us 382 [ + + ]: 6 : if (strcmp(dbname + offset, "localhost") != 0 &&
383 [ + - ]: 1 : strcmp(dbname + offset, "127.0.0.1") != 0)
384 : : {
5812 peter_e@gmx.net 385 : 1 : ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno);
5568 386 [ - + ]: 1 : ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
7700 meskes@postgresql.or 387 [ - + ]: 1 : if (host)
6038 meskes@postgresql.or 388 :UBC 0 : ecpg_free(host);
7700 meskes@postgresql.or 389 [ - + ]:CBC 1 : if (port)
6038 meskes@postgresql.or 390 :UBC 0 : ecpg_free(port);
7700 meskes@postgresql.or 391 [ - + ]:CBC 1 : if (options)
6038 meskes@postgresql.or 392 :UBC 0 : ecpg_free(options);
7700 meskes@postgresql.or 393 [ + - ]:CBC 1 : if (realname)
6038 394 : 1 : ecpg_free(realname);
7700 395 [ + - ]: 1 : if (dbname)
6038 396 : 1 : ecpg_free(dbname);
6440 397 : 1 : free(this);
7700 398 : 1 : return false;
399 : : }
400 : : }
401 : : else
402 : : {
3756 meskes@postgresql.or 403 [ # # ]:UBC 0 : if (*(dbname + offset) != '\0')
404 : : {
405 : 0 : host = ecpg_strdup(dbname + offset, lineno);
406 : 0 : connect_params++;
407 : : }
408 : : }
409 : : }
410 : : }
411 : : else
412 : : {
413 : : /* old style: dbname[@server][:port] */
6440 meskes@postgresql.or 414 :CBC 123 : tmp = strrchr(dbname, ':');
415 [ - + ]: 123 : if (tmp != NULL) /* port number given */
416 : : {
6038 meskes@postgresql.or 417 :UBC 0 : port = ecpg_strdup(tmp + 1, lineno);
4440 418 : 0 : connect_params++;
6440 419 : 0 : *tmp = '\0';
420 : : }
421 : :
6440 meskes@postgresql.or 422 :CBC 123 : tmp = strrchr(dbname, '@');
423 [ - + ]: 123 : if (tmp != NULL) /* host name given */
424 : : {
6038 meskes@postgresql.or 425 :UBC 0 : host = ecpg_strdup(tmp + 1, lineno);
4440 426 : 0 : connect_params++;
6440 427 : 0 : *tmp = '\0';
428 : : }
429 : :
4440 meskes@postgresql.or 430 [ + - ]:CBC 123 : if (strlen(dbname) > 0)
431 : : {
432 : 123 : realname = ecpg_strdup(dbname, lineno);
433 : 123 : connect_params++;
434 : : }
435 : : else
4440 meskes@postgresql.or 436 :UBC 0 : realname = NULL;
437 : : }
438 : : }
439 : : else
7045 440 : 0 : realname = NULL;
441 : :
442 : : /*
443 : : * Count options for the allocation done below (this may produce an
444 : : * overestimate, it's ok).
445 : : */
4440 meskes@postgresql.or 446 [ + + ]:CBC 128 : if (options)
5862 447 [ + + ]: 67 : for (i = 0; options[i]; i++)
4440 448 [ + + ]: 65 : if (options[i] == '=')
449 : 3 : connect_params++;
450 : :
451 [ + + + - ]: 128 : if (user && strlen(user) > 0)
452 : 6 : connect_params++;
453 [ + + + - ]: 128 : if (passwd && strlen(passwd) > 0)
454 : 6 : connect_params++;
455 : :
456 : : /*
457 : : * Allocate enough space for all connection parameters. These allocations
458 : : * are done before manipulating the list of connections to ease the error
459 : : * handling on failure.
460 : : */
4326 bruce@momjian.us 461 : 128 : conn_keywords = (const char **) ecpg_alloc((connect_params + 1) * sizeof(char *), lineno);
462 : 128 : conn_values = (const char **) ecpg_alloc(connect_params * sizeof(char *), lineno);
4440 meskes@postgresql.or 463 [ + - - + ]: 128 : if (conn_keywords == NULL || conn_values == NULL)
464 : : {
4440 meskes@postgresql.or 465 [ # # ]:UBC 0 : if (host)
466 : 0 : ecpg_free(host);
467 [ # # ]: 0 : if (port)
468 : 0 : ecpg_free(port);
469 [ # # ]: 0 : if (options)
470 : 0 : ecpg_free(options);
471 [ # # ]: 0 : if (realname)
472 : 0 : ecpg_free(realname);
473 [ # # ]: 0 : if (dbname)
474 : 0 : ecpg_free(dbname);
4420 peter_e@gmx.net 475 [ # # ]: 0 : if (conn_keywords)
476 : 0 : ecpg_free(conn_keywords);
477 [ # # ]: 0 : if (conn_values)
478 : 0 : ecpg_free(conn_values);
4440 meskes@postgresql.or 479 : 0 : free(this);
480 : 0 : return false;
481 : : }
482 : :
483 : : /* add connection to our list */
944 michael@paquier.xyz 484 :CBC 128 : pthread_mutex_lock(&connections_mutex);
485 : :
486 : : /*
487 : : * ... but first, make certain we have created ecpg_clocale. Rely on
488 : : * holding connections_mutex to ensure this is done by only one thread.
489 : : */
490 : : #ifdef HAVE_USELOCALE
652 noah@leadboat.com 491 [ + + ]: 128 : if (!ecpg_clocale)
492 : : {
493 : 56 : ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
494 [ - + ]: 56 : if (!ecpg_clocale)
495 : : {
652 noah@leadboat.com 496 :UBC 0 : pthread_mutex_unlock(&connections_mutex);
497 : 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
498 : : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
499 [ # # ]: 0 : if (host)
500 : 0 : ecpg_free(host);
501 [ # # ]: 0 : if (port)
502 : 0 : ecpg_free(port);
503 [ # # ]: 0 : if (options)
504 : 0 : ecpg_free(options);
505 [ # # ]: 0 : if (realname)
506 : 0 : ecpg_free(realname);
507 [ # # ]: 0 : if (dbname)
508 : 0 : ecpg_free(dbname);
509 [ # # ]: 0 : if (conn_keywords)
510 : 0 : ecpg_free(conn_keywords);
511 [ # # ]: 0 : if (conn_values)
512 : 0 : ecpg_free(conn_values);
513 : 0 : free(this);
514 : 0 : return false;
515 : : }
516 : : }
517 : : #endif
518 : :
944 michael@paquier.xyz 519 [ + + ]:CBC 128 : if (connection_name != NULL)
520 : 80 : this->name = ecpg_strdup(connection_name, lineno);
521 : : else
522 : 48 : this->name = ecpg_strdup(realname, lineno);
523 : :
524 : 128 : this->cache_head = NULL;
525 : 128 : this->prep_stmts = NULL;
526 : :
527 [ + + ]: 128 : if (all_connections == NULL)
528 : 73 : this->next = NULL;
529 : : else
530 : 55 : this->next = all_connections;
531 : :
532 : 128 : all_connections = this;
533 : 128 : pthread_setspecific(actual_connection_key, all_connections);
534 : 128 : actual_connection = all_connections;
535 : :
536 [ + + + + : 134 : ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n",
+ + + + -
+ - + +
+ ]
537 : : realname ? realname : "<DEFAULT>",
538 : : host ? host : "<DEFAULT>",
944 michael@paquier.xyz 539 [ # # ]:UBC 0 : port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>",
540 : : options ? "with options " : "", options ? options : "",
944 michael@paquier.xyz 541 [ + - ]:CBC 6 : (user && strlen(user) > 0) ? "for user " : "", user ? user : "");
542 : :
4454 meskes@postgresql.or 543 : 128 : i = 0;
544 [ + + ]: 128 : if (realname)
545 : : {
546 : 127 : conn_keywords[i] = "dbname";
547 : 127 : conn_values[i] = realname;
548 : 127 : i++;
549 : : }
550 [ - + ]: 128 : if (host)
551 : : {
4454 meskes@postgresql.or 552 :UBC 0 : conn_keywords[i] = "host";
553 : 0 : conn_values[i] = host;
554 : 0 : i++;
555 : : }
4454 meskes@postgresql.or 556 [ - + ]:CBC 128 : if (port)
557 : : {
4454 meskes@postgresql.or 558 :UBC 0 : conn_keywords[i] = "port";
559 : 0 : conn_values[i] = port;
560 : 0 : i++;
561 : : }
4454 meskes@postgresql.or 562 [ + + + - ]:CBC 128 : if (user && strlen(user) > 0)
563 : : {
564 : 6 : conn_keywords[i] = "user";
565 : 6 : conn_values[i] = user;
566 : 6 : i++;
567 : : }
568 [ + + + - ]: 128 : if (passwd && strlen(passwd) > 0)
569 : : {
570 : 6 : conn_keywords[i] = "password";
571 : 6 : conn_values[i] = passwd;
572 : 6 : i++;
573 : : }
574 [ + + ]: 128 : if (options)
575 : : {
576 : : char *str;
577 : :
578 : : /*
579 : : * The options string contains "keyword=value" pairs separated by
580 : : * '&'s. We must break this up into keywords and values to pass to
581 : : * libpq (it's okay to scribble on the options string). We ignore
582 : : * spaces just before each keyword or value.
583 : : */
4438 584 [ + + ]: 5 : for (str = options; *str;)
585 : : {
586 : : int e,
587 : : a;
588 : : char *token1,
589 : : *token2;
590 : :
591 : : /* Skip spaces before keyword */
1688 tgl@sss.pgh.pa.us 592 [ + + ]: 4 : for (token1 = str; *token1 == ' '; token1++)
593 : : /* skip */ ;
594 : : /* Find end of keyword */
595 [ + - + + ]: 43 : for (e = 0; token1[e] && token1[e] != '='; e++)
596 : : /* skip */ ;
4326 bruce@momjian.us 597 [ + - ]: 3 : if (token1[e]) /* found "=" */
598 : : {
4438 meskes@postgresql.or 599 : 3 : token1[e] = '\0';
600 : : /* Skip spaces before value */
1688 tgl@sss.pgh.pa.us 601 [ - + ]: 3 : for (token2 = token1 + e + 1; *token2 == ' '; token2++)
602 : : /* skip */ ;
603 : : /* Find end of value */
604 [ + + + + ]: 23 : for (a = 0; token2[a] && token2[a] != '&'; a++)
605 : : /* skip */ ;
4326 bruce@momjian.us 606 [ + + ]: 3 : if (token2[a]) /* found "&" => another option follows */
607 : : {
4438 meskes@postgresql.or 608 : 1 : token2[a] = '\0';
609 : 1 : str = token2 + a + 1;
610 : : }
611 : : else
612 : 2 : str = token2 + a;
613 : :
614 : 3 : conn_keywords[i] = token1;
615 : 3 : conn_values[i] = token2;
616 : 3 : i++;
617 : : }
618 : : else
619 : : {
620 : : /* Bogus options syntax ... ignore trailing garbage */
4326 bruce@momjian.us 621 :UBC 0 : str = token1 + e;
622 : : }
623 : : }
624 : : }
625 : :
1688 tgl@sss.pgh.pa.us 626 [ - + ]:CBC 128 : Assert(i <= connect_params);
4454 meskes@postgresql.or 627 : 128 : conn_keywords[i] = NULL; /* terminator */
628 : :
629 : 128 : this->connection = PQconnectdbParams(conn_keywords, conn_values, 0);
630 : :
5862 631 [ - + ]: 128 : if (host)
5862 meskes@postgresql.or 632 :UBC 0 : ecpg_free(host);
5862 meskes@postgresql.or 633 [ - + ]:CBC 128 : if (port)
5862 meskes@postgresql.or 634 :UBC 0 : ecpg_free(port);
5862 meskes@postgresql.or 635 [ + + ]:CBC 128 : if (options)
636 : 2 : ecpg_free(options);
637 [ + - ]: 128 : if (dbname)
638 : 128 : ecpg_free(dbname);
4440 639 : 128 : ecpg_free(conn_values);
640 : 128 : ecpg_free(conn_keywords);
641 : :
7700 642 [ + + ]: 128 : if (PQstatus(this->connection) == CONNECTION_BAD)
643 : : {
7559 bruce@momjian.us 644 : 1 : const char *errmsg = PQerrorMessage(this->connection);
5568 peter_e@gmx.net 645 [ + - ]: 1 : const char *db = realname ? realname : ecpg_gettext("<DEFAULT>");
646 : :
647 : : /* PQerrorMessage's result already has a trailing newline */
1178 tgl@sss.pgh.pa.us 648 : 1 : ecpg_log("ECPGconnect: %s", errmsg);
649 : :
6509 meskes@postgresql.or 650 : 1 : ecpg_finish(this);
651 : 1 : pthread_mutex_unlock(&connections_mutex);
652 : :
6038 653 : 1 : ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
7700 654 [ - + ]: 1 : if (realname)
6038 meskes@postgresql.or 655 :UBC 0 : ecpg_free(realname);
656 : :
7700 meskes@postgresql.or 657 :CBC 1 : return false;
658 : : }
659 : :
660 [ + - ]: 127 : if (realname)
6038 661 : 127 : ecpg_free(realname);
662 : :
5862 663 : 127 : pthread_mutex_unlock(&connections_mutex);
664 : :
7700 665 : 127 : this->autocommit = autocommit;
666 : :
7562 peter_e@gmx.net 667 : 127 : PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, (void *) this);
668 : :
7700 meskes@postgresql.or 669 : 127 : return true;
670 : : }
671 : :
672 : : bool
673 : 128 : ECPGdisconnect(int lineno, const char *connection_name)
674 : : {
7609 bruce@momjian.us 675 : 128 : struct sqlca_t *sqlca = ECPGget_sqlca();
676 : : struct connection *con;
677 : :
3226 meskes@postgresql.or 678 [ - + ]: 128 : if (sqlca == NULL)
679 : : {
3226 meskes@postgresql.or 680 :UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
681 : : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
2432 peter_e@gmx.net 682 : 0 : return false;
683 : : }
684 : :
7609 bruce@momjian.us 685 :CBC 128 : pthread_mutex_lock(&connections_mutex);
686 : :
7700 meskes@postgresql.or 687 [ + + ]: 128 : if (strcmp(connection_name, "ALL") == 0)
688 : : {
6038 689 : 16 : ecpg_init_sqlca(sqlca);
7700 690 [ + + ]: 34 : for (con = all_connections; con;)
691 : : {
692 : 18 : struct connection *f = con;
693 : :
694 : 18 : con = con->next;
695 : 18 : ecpg_finish(f);
696 : : }
697 : : }
698 : : else
699 : : {
7593 700 : 112 : con = ecpg_get_connection_nr(connection_name);
701 : :
6038 702 [ + + ]: 112 : if (!ecpg_init(con, connection_name, lineno))
703 : : {
7559 bruce@momjian.us 704 : 8 : pthread_mutex_unlock(&connections_mutex);
2432 peter_e@gmx.net 705 : 8 : return false;
706 : : }
707 : : else
7559 bruce@momjian.us 708 : 104 : ecpg_finish(con);
709 : : }
710 : :
7609 711 : 120 : pthread_mutex_unlock(&connections_mutex);
712 : :
7700 meskes@postgresql.or 713 : 120 : return true;
714 : : }
715 : :
716 : : PGconn *
5421 bruce@momjian.us 717 :UBC 0 : ECPGget_PGconn(const char *connection_name)
718 : : {
719 : : struct connection *con;
720 : :
721 : 0 : con = ecpg_get_connection(connection_name);
722 [ # # ]: 0 : if (con == NULL)
723 : 0 : return NULL;
724 : :
5869 meskes@postgresql.or 725 : 0 : return con->connection;
726 : : }
|