1 /* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.44 2007/09/30 11:38:48 meskes Exp $ */
3 #define POSTGRES_ECPG_INTERNAL
4 #include "postgres_fe.h"
6 #include "ecpg-pthread-win32.h"
13 #ifdef ENABLE_THREAD_SAFETY
14 NON_EXEC_STATIC pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
15 static pthread_key_t actual_connection_key;
17 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;
23 #ifdef ENABLE_THREAD_SAFETY
25 ecpg_actual_connection_init(void)
27 pthread_key_create(&actual_connection_key, NULL);
31 ecpg_pthreads_init(void)
33 pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
37 static struct connection *
38 ecpg_get_connection_nr(const char *connection_name)
40 struct connection *ret = NULL;
42 if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
44 #ifdef ENABLE_THREAD_SAFETY
45 ret = pthread_getspecific(actual_connection_key);
48 * if no connection in TSD for this thread, get the global default
49 * connection and hope the user knows what they're doing (i.e. using
50 * their own mutex to protect that connection from concurrent accesses
52 /* if !ret then we got the connection from TSD */
54 /* no TSD connection, going for global */
55 ret = actual_connection;
57 ret = actual_connection;
62 struct connection *con;
64 for (con = all_connections; con != NULL; con = con->next)
66 if (strcmp(connection_name, con->name) == 0)
76 ECPGget_connection(const char *connection_name)
78 struct connection *ret = NULL;
80 if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
82 #ifdef ENABLE_THREAD_SAFETY
83 ret = pthread_getspecific(actual_connection_key);
86 * if no connection in TSD for this thread, get the global default
87 * connection and hope the user knows what they're doing (i.e. using
88 * their own mutex to protect that connection from concurrent accesses
90 /* if !ret then we got the connection from TSD */
92 /* no TSD connection here either, using global */
93 ret = actual_connection;
95 ret = actual_connection;
100 #ifdef ENABLE_THREAD_SAFETY
101 pthread_mutex_lock(&connections_mutex);
104 ret = ecpg_get_connection_nr(connection_name);
106 #ifdef ENABLE_THREAD_SAFETY
107 pthread_mutex_unlock(&connections_mutex);
115 ecpg_finish(struct connection * act)
119 struct ECPGtype_information_cache *cache,
122 ECPGdeallocate_all_conn(0, ECPG_COMPAT_PGSQL, act);
123 PQfinish(act->connection);
126 * no need to lock connections_mutex - we're always called by
127 * ECPGdisconnect or ECPGconnect, which are holding the lock
130 /* remove act from the list */
131 if (act == all_connections)
132 all_connections = act->next;
135 struct connection *con;
137 for (con = all_connections; con->next && con->next != act; con = con->next);
139 con->next = act->next;
142 #ifdef ENABLE_THREAD_SAFETY
143 if (pthread_getspecific(actual_connection_key) == act)
144 pthread_setspecific(actual_connection_key, all_connections);
146 if (actual_connection == act)
147 actual_connection = all_connections;
149 ECPGlog("ecpg_finish: Connection %s closed.\n", act->name);
151 for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ECPGfree(ptr));
156 ECPGlog("ecpg_finish: called an extra time.\n");
160 ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
162 struct connection *con = ECPGget_connection(connection_name);
165 if (!ECPGinit(con, connection_name, lineno))
168 ECPGlog("ECPGsetcommit line %d action = %s connection = %s\n", lineno, mode, con->name);
170 if (con->autocommit == true && strncmp(mode, "off", strlen("off")) == 0)
174 results = PQexec(con->connection, "begin transaction");
175 if (!ECPGcheck_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
178 con->committed = false;
180 con->autocommit = false;
182 else if (con->autocommit == false && strncmp(mode, "on", strlen("on")) == 0)
186 results = PQexec(con->connection, "commit");
187 if (!ECPGcheck_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
190 con->committed = true;
192 con->autocommit = true;
199 ECPGsetconn(int lineno, const char *connection_name)
201 struct connection *con = ECPGget_connection(connection_name);
203 if (!ECPGinit(con, connection_name, lineno))
206 #ifdef ENABLE_THREAD_SAFETY
207 pthread_setspecific(actual_connection_key, con);
209 actual_connection = con;
216 ECPGnoticeReceiver(void *arg, const PGresult *result)
218 char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
219 char *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
220 struct sqlca_t *sqlca = ECPGget_sqlca();
224 if (sqlstate == NULL)
225 sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR;
227 if (message == NULL) /* Shouldn't happen, but need to be sure */
228 message = "No message received";
230 /* these are not warnings */
231 if (strncmp(sqlstate, "00", 2) == 0)
234 ECPGlog("ECPGnoticeReceiver %s\n", message);
236 /* map to SQLCODE for backward compatibility */
237 if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME) == 0)
238 sqlcode = ECPG_WARNING_UNKNOWN_PORTAL;
239 else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION) == 0)
240 sqlcode = ECPG_WARNING_IN_TRANSACTION;
241 else if (strcmp(sqlstate, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION) == 0)
242 sqlcode = ECPG_WARNING_NO_TRANSACTION;
243 else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR) == 0)
244 sqlcode = ECPG_WARNING_PORTAL_EXISTS;
248 strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
249 sqlca->sqlcode = sqlcode;
250 sqlca->sqlwarn[2] = 'W';
251 sqlca->sqlwarn[0] = 'W';
253 strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
254 sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
255 sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
257 ECPGlog("raising sqlcode %d\n", sqlcode);
261 /* this contains some quick hacks, needs to be cleaned up, but it works */
263 ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
265 struct sqlca_t *sqlca = ECPGget_sqlca();
266 enum COMPAT_MODE compat = c;
267 struct connection *this;
268 char *dbname = name ? ECPGstrdup(name, lineno) : NULL,
275 ECPGinit_sqlca(sqlca);
277 /* clear auto_mem structure because some error handling functions might access it */
278 ECPGclear_auto_mem();
280 if (INFORMIX_MODE(compat))
285 * Informix uses an environment variable DBPATH that overrides the
286 * connection parameters given here. We do the same with PG_DBPATH as
287 * the syntax is different.
289 envname = getenv("PG_DBPATH");
293 dbname = ECPGstrdup(envname, lineno);
298 if (dbname == NULL && connection_name == NULL)
299 connection_name = "DEFAULT";
301 #if ENABLE_THREAD_SAFETY
302 ecpg_pthreads_init();
305 /* check if the identifier is unique */
306 if (ECPGget_connection(connection_name))
309 ECPGlog("connect: connection identifier %s is already in use\n",
314 if ((this = (struct connection *) ECPGalloc(sizeof(struct connection), lineno)) == NULL)
319 /* get the detail information out of dbname */
320 if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
325 * only allow protocols tcp and unix
327 if (strncmp(dbname, "tcp:", 4) == 0)
329 else if (strncmp(dbname, "unix:", 5) == 0)
332 if (strncmp(dbname + offset, "postgresql://", strlen("postgresql://")) == 0)
337 * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:]
338 * [/db name][?options]
341 offset += strlen("postgresql://");
343 tmp = strrchr(dbname + offset, '?');
344 if (tmp != NULL) /* options given */
346 options = ECPGstrdup(tmp + 1, lineno);
350 tmp = last_dir_separator(dbname + offset);
351 if (tmp != NULL) /* database name given */
353 realname = ECPGstrdup(tmp + 1, lineno);
357 tmp = strrchr(dbname + offset, ':');
358 if (tmp != NULL) /* port number or Unix socket path given */
363 if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
366 host = ECPGstrdup(tmp + 1, lineno);
367 if (strncmp(dbname, "unix:", 5) != 0)
369 ECPGlog("connect: socketname %s given for TCP connection in line %d\n", host, lineno);
370 ECPGraise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : "<DEFAULT>");
375 * port not set yet if (port) ECPGfree(port);
388 port = ECPGstrdup(tmp + 1, lineno);
391 if (strncmp(dbname, "unix:", 5) == 0)
393 if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0)
395 ECPGlog("connect: non-localhost access via sockets in line %d\n", lineno);
396 ECPGraise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : "<DEFAULT>");
412 host = ECPGstrdup(dbname + offset, lineno);
418 /* old style: dbname[@server][:port] */
419 tmp = strrchr(dbname, ':');
420 if (tmp != NULL) /* port number given */
422 port = ECPGstrdup(tmp + 1, lineno);
426 tmp = strrchr(dbname, '@');
427 if (tmp != NULL) /* host name given */
429 host = ECPGstrdup(tmp + 1, lineno);
433 realname = (strlen(dbname) > 0) ? ECPGstrdup(dbname, lineno) : NULL;
439 /* add connection to our list */
440 #ifdef ENABLE_THREAD_SAFETY
441 pthread_mutex_lock(&connections_mutex);
443 if (connection_name != NULL)
444 this->name = ECPGstrdup(connection_name, lineno);
446 this->name = ECPGstrdup(realname, lineno);
448 this->cache_head = NULL;
449 this->prep_stmts = NULL;
451 if (all_connections == NULL)
454 this->next = all_connections;
456 all_connections = this;
457 #ifdef ENABLE_THREAD_SAFETY
458 pthread_setspecific(actual_connection_key, all_connections);
460 actual_connection = all_connections;
462 ECPGlog("ECPGconnect: opening database %s on %s port %s %s%s%s%s\n",
463 realname ? realname : "<DEFAULT>",
464 host ? host : "<DEFAULT>",
465 port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>",
466 options ? "with options " : "", options ? options : "",
467 user ? "for user " : "", user ? user : "");
469 this->connection = PQsetdbLogin(host, port, options, NULL, realname, user, passwd);
471 if (PQstatus(this->connection) == CONNECTION_BAD)
473 const char *errmsg = PQerrorMessage(this->connection);
474 const char *db = realname ? realname : "<DEFAULT>";
476 ECPGlog("connect: could not open database %s on %s port %s %s%s%s%s in line %d\n\t%s\n",
478 host ? host : "<DEFAULT>",
479 port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>",
480 options ? "with options " : "", options ? options : "",
481 user ? "for user " : "", user ? user : "",
485 #ifdef ENABLE_THREAD_SAFETY
486 pthread_mutex_unlock(&connections_mutex);
489 ECPGraise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
502 #ifdef ENABLE_THREAD_SAFETY
503 pthread_mutex_unlock(&connections_mutex);
517 this->committed = true;
518 this->autocommit = autocommit;
520 PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, (void *) this);
526 ECPGdisconnect(int lineno, const char *connection_name)
528 struct sqlca_t *sqlca = ECPGget_sqlca();
529 struct connection *con;
531 #ifdef ENABLE_THREAD_SAFETY
532 pthread_mutex_lock(&connections_mutex);
535 if (strcmp(connection_name, "ALL") == 0)
537 ECPGinit_sqlca(sqlca);
538 for (con = all_connections; con;)
540 struct connection *f = con;
548 con = ecpg_get_connection_nr(connection_name);
550 if (!ECPGinit(con, connection_name, lineno))
552 #ifdef ENABLE_THREAD_SAFETY
553 pthread_mutex_unlock(&connections_mutex);
561 #ifdef ENABLE_THREAD_SAFETY
562 pthread_mutex_unlock(&connections_mutex);