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