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