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