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
14static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
15static pthread_key_t actual_connection_key;
16static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT;
17#endif
18static struct connection *actual_connection = NULL;
19static struct connection *all_connections = NULL;
20
21#ifdef ENABLE_THREAD_SAFETY
22static void
23ecpg_actual_connection_init(void)
24{
25 pthread_key_create(&actual_connection_key, NULL);
26}
27
28void
29ecpg_pthreads_init(void)
30{
31 pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
32}
33#endif
34
35static struct connection *
36ecpg_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
73struct connection *
74ecpg_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
112static void
113ecpg_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
164bool
165ECPGsetcommit(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
201bool
202ECPGsetconn(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
218static void
219ECPGnoticeReceiver(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 */
270bool
271ECPGconnect(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
668bool
669ECPGdisconnect(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
718PGconn *
719ECPGget_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