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 230 : ecpg_actual_connection_init(void)
25 : {
26 230 : pthread_key_create(&actual_connection_key, NULL);
27 230 : }
28 :
29 : void
30 25512 : ecpg_pthreads_init(void)
31 : {
32 25512 : pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
33 25512 : }
34 :
35 : static struct connection *
36 2104 : ecpg_get_connection_nr(const char *connection_name)
37 : {
38 2104 : struct connection *ret = NULL;
39 :
40 2104 : if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
41 : {
42 178 : ecpg_pthreads_init(); /* ensure actual_connection_key is valid */
43 :
44 178 : 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 178 : if (ret == NULL)
52 : /* no TSD connection, going for global */
53 8 : ret = actual_connection;
54 : }
55 : else
56 : {
57 : struct connection *con;
58 :
59 7442 : for (con = all_connections; con != NULL; con = con->next)
60 : {
61 7082 : if (strcmp(connection_name, con->name) == 0)
62 1566 : break;
63 : }
64 1926 : ret = con;
65 : }
66 :
67 2104 : return ret;
68 : }
69 :
70 : struct connection *
71 15784 : ecpg_get_connection(const char *connection_name)
72 : {
73 15784 : struct connection *ret = NULL;
74 :
75 15784 : if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
76 : {
77 14146 : ecpg_pthreads_init(); /* ensure actual_connection_key is valid */
78 :
79 14146 : 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 : */
86 14146 : if (ret == NULL)
87 : /* no TSD connection here either, using global */
88 232 : ret = actual_connection;
89 : }
90 : else
91 : {
92 1638 : pthread_mutex_lock(&connections_mutex);
93 :
94 1638 : ret = ecpg_get_connection_nr(connection_name);
95 :
96 1638 : pthread_mutex_unlock(&connections_mutex);
97 : }
98 :
99 15784 : return ret;
100 : }
101 :
102 : static void
103 512 : ecpg_finish(struct connection *act)
104 : {
105 512 : if (act != NULL)
106 : {
107 : struct ECPGtype_information_cache *cache,
108 : *ptr;
109 :
110 512 : ecpg_deallocate_all_conn(0, ECPG_COMPAT_PGSQL, act);
111 512 : 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 512 : if (act == all_connections)
120 328 : all_connections = act->next;
121 : else
122 : {
123 : struct connection *con;
124 :
125 838 : for (con = all_connections; con->next && con->next != act; con = con->next);
126 184 : if (con->next)
127 184 : con->next = act->next;
128 : }
129 :
130 512 : if (pthread_getspecific(actual_connection_key) == act)
131 512 : pthread_setspecific(actual_connection_key, all_connections);
132 512 : if (actual_connection == act)
133 328 : actual_connection = all_connections;
134 :
135 512 : ecpg_log("ecpg_finish: connection %s closed\n", act->name ? act->name : "(null)");
136 :
137 10056 : for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ecpg_free(ptr));
138 512 : ecpg_free(act->name);
139 512 : ecpg_free(act);
140 : /* delete cursor variables when last connection gets closed */
141 512 : if (all_connections == NULL)
142 : {
143 : struct var_list *iv_ptr;
144 :
145 348 : for (; ivlist; iv_ptr = ivlist, ivlist = ivlist->next, ecpg_free(iv_ptr));
146 : }
147 : }
148 : else
149 0 : ecpg_log("ecpg_finish: called an extra time\n");
150 512 : }
151 :
152 : bool
153 172 : ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
154 : {
155 172 : struct connection *con = ecpg_get_connection(connection_name);
156 : PGresult *results;
157 :
158 172 : if (!ecpg_init(con, connection_name, lineno))
159 0 : return false;
160 :
161 172 : ecpg_log("ECPGsetcommit on line %d: action \"%s\"; connection \"%s\"\n", lineno, mode, con->name);
162 :
163 172 : if (con->autocommit && strncmp(mode, "off", strlen("off")) == 0)
164 : {
165 0 : if (PQtransactionStatus(con->connection) == PQTRANS_IDLE)
166 : {
167 0 : results = PQexec(con->connection, "begin transaction");
168 0 : if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
169 0 : return false;
170 0 : PQclear(results);
171 : }
172 0 : con->autocommit = false;
173 : }
174 172 : else if (!con->autocommit && strncmp(mode, "on", strlen("on")) == 0)
175 : {
176 160 : if (PQtransactionStatus(con->connection) != PQTRANS_IDLE)
177 : {
178 0 : results = PQexec(con->connection, "commit");
179 0 : if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
180 0 : return false;
181 0 : PQclear(results);
182 : }
183 160 : con->autocommit = true;
184 : }
185 :
186 172 : return true;
187 : }
188 :
189 : bool
190 8 : ECPGsetconn(int lineno, const char *connection_name)
191 : {
192 8 : struct connection *con = ecpg_get_connection(connection_name);
193 :
194 8 : if (!ecpg_init(con, connection_name, lineno))
195 0 : return false;
196 :
197 8 : pthread_setspecific(actual_connection_key, con);
198 8 : return true;
199 : }
200 :
201 :
202 : static void
203 8 : ECPGnoticeReceiver(void *arg, const PGresult *result)
204 : {
205 8 : char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
206 8 : char *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
207 8 : struct sqlca_t *sqlca = ECPGget_sqlca();
208 : int sqlcode;
209 :
210 8 : if (sqlca == NULL)
211 : {
212 0 : ecpg_log("out of memory");
213 0 : return;
214 : }
215 :
216 : (void) arg; /* keep the compiler quiet */
217 8 : if (sqlstate == NULL)
218 0 : sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR;
219 :
220 8 : if (message == NULL) /* Shouldn't happen, but need to be sure */
221 0 : message = ecpg_gettext("empty message text");
222 :
223 : /* these are not warnings */
224 8 : if (strncmp(sqlstate, "00", 2) == 0)
225 4 : return;
226 :
227 4 : ecpg_log("ECPGnoticeReceiver: %s\n", message);
228 :
229 : /* map to SQLCODE for backward compatibility */
230 4 : if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME) == 0)
231 0 : sqlcode = ECPG_WARNING_UNKNOWN_PORTAL;
232 4 : else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION) == 0)
233 0 : sqlcode = ECPG_WARNING_IN_TRANSACTION;
234 4 : else if (strcmp(sqlstate, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION) == 0)
235 0 : sqlcode = ECPG_WARNING_NO_TRANSACTION;
236 4 : else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR) == 0)
237 0 : sqlcode = ECPG_WARNING_PORTAL_EXISTS;
238 : else
239 4 : sqlcode = 0;
240 :
241 4 : strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
242 4 : sqlca->sqlcode = sqlcode;
243 4 : sqlca->sqlwarn[2] = 'W';
244 4 : sqlca->sqlwarn[0] = 'W';
245 :
246 4 : strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
247 4 : sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
248 4 : sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
249 :
250 4 : 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
255 546 : ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
256 : {
257 546 : struct sqlca_t *sqlca = ECPGget_sqlca();
258 546 : enum COMPAT_MODE compat = c;
259 : struct connection *this;
260 : int i,
261 546 : connect_params = 0;
262 546 : char *dbname = name ? ecpg_strdup(name, lineno) : NULL,
263 546 : *host = NULL,
264 : *tmp,
265 546 : *port = NULL,
266 546 : *realname = NULL,
267 546 : *options = NULL;
268 : const char **conn_keywords;
269 : const char **conn_values;
270 :
271 546 : if (sqlca == NULL)
272 : {
273 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 :
279 546 : ecpg_init_sqlca(sqlca);
280 :
281 : /*
282 : * clear auto_mem structure because some error handling functions might
283 : * access it
284 : */
285 546 : ecpg_clear_auto_mem();
286 :
287 546 : 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 : */
296 24 : envname = getenv("PG_DBPATH");
297 24 : if (envname)
298 : {
299 0 : ecpg_free(dbname);
300 0 : dbname = ecpg_strdup(envname, lineno);
301 : }
302 : }
303 :
304 546 : if (dbname == NULL && connection_name == NULL)
305 0 : connection_name = "DEFAULT";
306 :
307 546 : ecpg_pthreads_init();
308 :
309 : /* check if the identifier is unique */
310 546 : if (ecpg_get_connection(connection_name))
311 : {
312 8 : ecpg_free(dbname);
313 8 : ecpg_log("ECPGconnect: connection identifier %s is already in use\n",
314 : connection_name);
315 8 : return false;
316 : }
317 :
318 538 : if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL)
319 : {
320 0 : ecpg_free(dbname);
321 0 : return false;
322 : }
323 :
324 538 : if (dbname != NULL)
325 : {
326 : /* get the detail information from dbname */
327 538 : if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
328 36 : {
329 40 : int offset = 0;
330 :
331 : /*
332 : * only allow protocols tcp and unix
333 : */
334 40 : if (strncmp(dbname, "tcp:", 4) == 0)
335 10 : offset = 4;
336 30 : else if (strncmp(dbname, "unix:", 5) == 0)
337 30 : offset = 5;
338 :
339 40 : 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 40 : offset += strlen("postgresql://");
348 :
349 40 : tmp = strrchr(dbname + offset, '?');
350 40 : if (tmp != NULL) /* options given */
351 : {
352 10 : options = ecpg_strdup(tmp + 1, lineno);
353 10 : *tmp = '\0';
354 : }
355 :
356 40 : tmp = last_dir_separator(dbname + offset);
357 40 : if (tmp != NULL) /* database name given */
358 : {
359 40 : if (tmp[1] != '\0') /* non-empty database name */
360 : {
361 34 : realname = ecpg_strdup(tmp + 1, lineno);
362 34 : connect_params++;
363 : }
364 40 : *tmp = '\0';
365 : }
366 :
367 40 : tmp = strrchr(dbname + offset, ':');
368 40 : if (tmp != NULL) /* port number given */
369 : {
370 2 : *tmp = '\0';
371 2 : port = ecpg_strdup(tmp + 1, lineno);
372 2 : connect_params++;
373 : }
374 :
375 40 : 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 : */
382 30 : if (strcmp(dbname + offset, "localhost") != 0 &&
383 4 : strcmp(dbname + offset, "127.0.0.1") != 0)
384 : {
385 4 : ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno);
386 4 : ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
387 4 : if (host)
388 0 : ecpg_free(host);
389 4 : if (port)
390 0 : ecpg_free(port);
391 4 : if (options)
392 0 : ecpg_free(options);
393 4 : if (realname)
394 4 : ecpg_free(realname);
395 4 : if (dbname)
396 4 : ecpg_free(dbname);
397 4 : free(this);
398 4 : return false;
399 : }
400 : }
401 : else
402 : {
403 10 : if (*(dbname + offset) != '\0')
404 : {
405 10 : host = ecpg_strdup(dbname + offset, lineno);
406 10 : connect_params++;
407 : }
408 : }
409 : }
410 : }
411 : else
412 : {
413 : /* old style: dbname[@server][:port] */
414 498 : tmp = strrchr(dbname, ':');
415 498 : if (tmp != NULL) /* port number given */
416 : {
417 0 : port = ecpg_strdup(tmp + 1, lineno);
418 0 : connect_params++;
419 0 : *tmp = '\0';
420 : }
421 :
422 498 : tmp = strrchr(dbname, '@');
423 498 : if (tmp != NULL) /* host name given */
424 : {
425 4 : host = ecpg_strdup(tmp + 1, lineno);
426 4 : connect_params++;
427 4 : *tmp = '\0';
428 : }
429 :
430 498 : if (strlen(dbname) > 0)
431 : {
432 496 : realname = ecpg_strdup(dbname, lineno);
433 496 : connect_params++;
434 : }
435 : else
436 2 : realname = NULL;
437 : }
438 : }
439 : else
440 0 : realname = NULL;
441 :
442 : /*
443 : * Count options for the allocation done below (this may produce an
444 : * overestimate, it's ok).
445 : */
446 534 : if (options)
447 300 : for (i = 0; options[i]; i++)
448 290 : if (options[i] == '=')
449 14 : connect_params++;
450 :
451 534 : if (user && strlen(user) > 0)
452 42 : connect_params++;
453 534 : if (passwd && strlen(passwd) > 0)
454 36 : 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 : */
461 534 : conn_keywords = (const char **) ecpg_alloc((connect_params + 1) * sizeof(char *), lineno);
462 534 : conn_values = (const char **) ecpg_alloc(connect_params * sizeof(char *), lineno);
463 534 : if (conn_keywords == NULL || conn_values == NULL)
464 : {
465 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);
475 0 : if (conn_keywords)
476 0 : ecpg_free(conn_keywords);
477 0 : if (conn_values)
478 0 : ecpg_free(conn_values);
479 0 : free(this);
480 0 : return false;
481 : }
482 :
483 : /* add connection to our list */
484 534 : 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
491 534 : if (!ecpg_clocale)
492 : {
493 226 : ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
494 226 : if (!ecpg_clocale)
495 : {
496 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 :
519 534 : if (connection_name != NULL)
520 326 : this->name = ecpg_strdup(connection_name, lineno);
521 : else
522 208 : this->name = ecpg_strdup(realname, lineno);
523 :
524 534 : this->cache_head = NULL;
525 534 : this->prep_stmts = NULL;
526 :
527 534 : if (all_connections == NULL)
528 314 : this->next = NULL;
529 : else
530 220 : this->next = all_connections;
531 :
532 534 : all_connections = this;
533 534 : pthread_setspecific(actual_connection_key, all_connections);
534 534 : actual_connection = all_connections;
535 :
536 578 : ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n",
537 : realname ? realname : "<DEFAULT>",
538 : host ? host : "<DEFAULT>",
539 2 : port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>",
540 : options ? "with options " : "", options ? options : "",
541 42 : (user && strlen(user) > 0) ? "for user " : "", user ? user : "");
542 :
543 534 : i = 0;
544 534 : if (realname)
545 : {
546 526 : conn_keywords[i] = "dbname";
547 526 : conn_values[i] = realname;
548 526 : i++;
549 : }
550 534 : if (host)
551 : {
552 14 : conn_keywords[i] = "host";
553 14 : conn_values[i] = host;
554 14 : i++;
555 : }
556 534 : if (port)
557 : {
558 2 : conn_keywords[i] = "port";
559 2 : conn_values[i] = port;
560 2 : i++;
561 : }
562 534 : if (user && strlen(user) > 0)
563 : {
564 42 : conn_keywords[i] = "user";
565 42 : conn_values[i] = user;
566 42 : i++;
567 : }
568 534 : if (passwd && strlen(passwd) > 0)
569 : {
570 36 : conn_keywords[i] = "password";
571 36 : conn_values[i] = passwd;
572 36 : i++;
573 : }
574 534 : 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. (The preprocessor used
583 : * to add spaces around '&'s, making it necessary to ignore spaces
584 : * before keywords here. While it no longer does that, we still must
585 : * skip spaces to support code compiled with older preprocessors.)
586 : */
587 24 : for (str = options; *str;)
588 : {
589 : int e,
590 : a;
591 : char *token1,
592 : *token2;
593 :
594 : /* Skip spaces before keyword */
595 14 : for (token1 = str; *token1 == ' '; token1++)
596 : /* skip */ ;
597 : /* Find end of keyword */
598 204 : for (e = 0; token1[e] && token1[e] != '='; e++)
599 : /* skip */ ;
600 14 : if (token1[e]) /* found "=" */
601 : {
602 14 : token1[e] = '\0';
603 : /* Skip spaces before value */
604 14 : for (token2 = token1 + e + 1; *token2 == ' '; token2++)
605 : /* skip */ ;
606 : /* Find end of value */
607 96 : for (a = 0; token2[a] && token2[a] != '&'; a++)
608 : /* skip */ ;
609 14 : if (token2[a]) /* found "&" => another option follows */
610 : {
611 4 : token2[a] = '\0';
612 4 : str = token2 + a + 1;
613 : }
614 : else
615 10 : str = token2 + a;
616 :
617 14 : conn_keywords[i] = token1;
618 14 : conn_values[i] = token2;
619 14 : i++;
620 : }
621 : else
622 : {
623 : /* Bogus options syntax ... ignore trailing garbage */
624 0 : str = token1 + e;
625 : }
626 : }
627 : }
628 :
629 : Assert(i <= connect_params);
630 534 : conn_keywords[i] = NULL; /* terminator */
631 :
632 534 : this->connection = PQconnectdbParams(conn_keywords, conn_values, 0);
633 :
634 534 : if (host)
635 14 : ecpg_free(host);
636 534 : if (port)
637 2 : ecpg_free(port);
638 534 : if (options)
639 10 : ecpg_free(options);
640 534 : if (dbname)
641 534 : ecpg_free(dbname);
642 534 : ecpg_free(conn_values);
643 534 : ecpg_free(conn_keywords);
644 :
645 534 : if (PQstatus(this->connection) == CONNECTION_BAD)
646 : {
647 12 : const char *errmsg = PQerrorMessage(this->connection);
648 12 : const char *db = realname ? realname : ecpg_gettext("<DEFAULT>");
649 :
650 : /* PQerrorMessage's result already has a trailing newline */
651 12 : ecpg_log("ECPGconnect: %s", errmsg);
652 :
653 12 : ecpg_finish(this);
654 12 : pthread_mutex_unlock(&connections_mutex);
655 :
656 12 : ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
657 12 : if (realname)
658 4 : ecpg_free(realname);
659 :
660 12 : return false;
661 : }
662 :
663 522 : if (realname)
664 522 : ecpg_free(realname);
665 :
666 522 : pthread_mutex_unlock(&connections_mutex);
667 :
668 522 : this->autocommit = autocommit;
669 :
670 522 : PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, (void *) this);
671 :
672 522 : return true;
673 : }
674 :
675 : bool
676 530 : ECPGdisconnect(int lineno, const char *connection_name)
677 : {
678 530 : struct sqlca_t *sqlca = ECPGget_sqlca();
679 : struct connection *con;
680 :
681 530 : if (sqlca == NULL)
682 : {
683 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
684 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
685 0 : return false;
686 : }
687 :
688 530 : pthread_mutex_lock(&connections_mutex);
689 :
690 530 : if (strcmp(connection_name, "ALL") == 0)
691 : {
692 64 : ecpg_init_sqlca(sqlca);
693 136 : for (con = all_connections; con;)
694 : {
695 72 : struct connection *f = con;
696 :
697 72 : con = con->next;
698 72 : ecpg_finish(f);
699 : }
700 : }
701 : else
702 : {
703 466 : con = ecpg_get_connection_nr(connection_name);
704 :
705 466 : if (!ecpg_init(con, connection_name, lineno))
706 : {
707 38 : pthread_mutex_unlock(&connections_mutex);
708 38 : return false;
709 : }
710 : else
711 428 : ecpg_finish(con);
712 : }
713 :
714 492 : pthread_mutex_unlock(&connections_mutex);
715 :
716 492 : return true;
717 : }
718 :
719 : PGconn *
720 0 : ECPGget_PGconn(const char *connection_name)
721 : {
722 : struct connection *con;
723 :
724 0 : con = ecpg_get_connection(connection_name);
725 0 : if (con == NULL)
726 0 : return NULL;
727 :
728 0 : return con->connection;
729 : }
|