00001
00002
00003 #define POSTGRES_ECPG_INTERNAL
00004 #include "postgres_fe.h"
00005
00006 #include "ecpg-pthread-win32.h"
00007 #include "ecpgtype.h"
00008 #include "ecpglib.h"
00009 #include "ecpgerrno.h"
00010 #include "extern.h"
00011 #include "sqlca.h"
00012
00013 #ifdef ENABLE_THREAD_SAFETY
00014 static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
00015 static pthread_key_t actual_connection_key;
00016 static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT;
00017 #endif
00018 static struct connection *actual_connection = NULL;
00019 static struct connection *all_connections = NULL;
00020
00021 #ifdef ENABLE_THREAD_SAFETY
00022 static void
00023 ecpg_actual_connection_init(void)
00024 {
00025 pthread_key_create(&actual_connection_key, NULL);
00026 }
00027
00028 void
00029 ecpg_pthreads_init(void)
00030 {
00031 pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
00032 }
00033 #endif
00034
00035 static struct connection *
00036 ecpg_get_connection_nr(const char *connection_name)
00037 {
00038 struct connection *ret = NULL;
00039
00040 if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
00041 {
00042 #ifdef ENABLE_THREAD_SAFETY
00043 ret = pthread_getspecific(actual_connection_key);
00044
00045
00046
00047
00048
00049
00050
00051 if (NULL == ret)
00052
00053 ret = actual_connection;
00054 #else
00055 ret = actual_connection;
00056 #endif
00057 }
00058 else
00059 {
00060 struct connection *con;
00061
00062 for (con = all_connections; con != NULL; con = con->next)
00063 {
00064 if (strcmp(connection_name, con->name) == 0)
00065 break;
00066 }
00067 ret = con;
00068 }
00069
00070 return (ret);
00071 }
00072
00073 struct connection *
00074 ecpg_get_connection(const char *connection_name)
00075 {
00076 struct connection *ret = NULL;
00077
00078 if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
00079 {
00080 #ifdef ENABLE_THREAD_SAFETY
00081 ret = pthread_getspecific(actual_connection_key);
00082
00083
00084
00085
00086
00087
00088
00089 if (NULL == ret)
00090
00091 ret = actual_connection;
00092 #else
00093 ret = actual_connection;
00094 #endif
00095 }
00096 else
00097 {
00098 #ifdef ENABLE_THREAD_SAFETY
00099 pthread_mutex_lock(&connections_mutex);
00100 #endif
00101
00102 ret = ecpg_get_connection_nr(connection_name);
00103
00104 #ifdef ENABLE_THREAD_SAFETY
00105 pthread_mutex_unlock(&connections_mutex);
00106 #endif
00107 }
00108
00109 return (ret);
00110 }
00111
00112 static void
00113 ecpg_finish(struct connection * act)
00114 {
00115 if (act != NULL)
00116 {
00117 struct ECPGtype_information_cache *cache,
00118 *ptr;
00119
00120 ecpg_deallocate_all_conn(0, ECPG_COMPAT_PGSQL, act);
00121 PQfinish(act->connection);
00122
00123
00124
00125
00126
00127
00128
00129 if (act == all_connections)
00130 all_connections = act->next;
00131 else
00132 {
00133 struct connection *con;
00134
00135 for (con = all_connections; con->next && con->next != act; con = con->next);
00136 if (con->next)
00137 con->next = act->next;
00138 }
00139
00140 #ifdef ENABLE_THREAD_SAFETY
00141 if (pthread_getspecific(actual_connection_key) == act)
00142 pthread_setspecific(actual_connection_key, all_connections);
00143 #endif
00144 if (actual_connection == act)
00145 actual_connection = all_connections;
00146
00147 ecpg_log("ecpg_finish: connection %s closed\n", act->name ? act->name : "(null)");
00148
00149 for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ecpg_free(ptr));
00150 ecpg_free(act->name);
00151 ecpg_free(act);
00152
00153 if (all_connections == NULL)
00154 {
00155 struct var_list *iv_ptr;
00156
00157 for (; ivlist; iv_ptr = ivlist, ivlist = ivlist->next, ecpg_free(iv_ptr));
00158 }
00159 }
00160 else
00161 ecpg_log("ecpg_finish: called an extra time\n");
00162 }
00163
00164 bool
00165 ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
00166 {
00167 struct connection *con = ecpg_get_connection(connection_name);
00168 PGresult *results;
00169
00170 if (!ecpg_init(con, connection_name, lineno))
00171 return (false);
00172
00173 ecpg_log("ECPGsetcommit on line %d: action \"%s\"; connection \"%s\"\n", lineno, mode, con->name);
00174
00175 if (con->autocommit && strncmp(mode, "off", strlen("off")) == 0)
00176 {
00177 if (PQtransactionStatus(con->connection) == PQTRANS_IDLE)
00178 {
00179 results = PQexec(con->connection, "begin transaction");
00180 if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
00181 return false;
00182 PQclear(results);
00183 }
00184 con->autocommit = false;
00185 }
00186 else if (!con->autocommit && strncmp(mode, "on", strlen("on")) == 0)
00187 {
00188 if (PQtransactionStatus(con->connection) != PQTRANS_IDLE)
00189 {
00190 results = PQexec(con->connection, "commit");
00191 if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
00192 return false;
00193 PQclear(results);
00194 }
00195 con->autocommit = true;
00196 }
00197
00198 return true;
00199 }
00200
00201 bool
00202 ECPGsetconn(int lineno, const char *connection_name)
00203 {
00204 struct connection *con = ecpg_get_connection(connection_name);
00205
00206 if (!ecpg_init(con, connection_name, lineno))
00207 return (false);
00208
00209 #ifdef ENABLE_THREAD_SAFETY
00210 pthread_setspecific(actual_connection_key, con);
00211 #else
00212 actual_connection = con;
00213 #endif
00214 return true;
00215 }
00216
00217
00218 static void
00219 ECPGnoticeReceiver(void *arg, const PGresult *result)
00220 {
00221 char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
00222 char *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
00223 struct sqlca_t *sqlca = ECPGget_sqlca();
00224 int sqlcode;
00225
00226 (void) arg;
00227 if (sqlstate == NULL)
00228 sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR;
00229
00230 if (message == NULL)
00231 message = ecpg_gettext("empty message text");
00232
00233
00234 if (strncmp(sqlstate, "00", 2) == 0)
00235 return;
00236
00237 ecpg_log("ECPGnoticeReceiver: %s\n", message);
00238
00239
00240 if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME) == 0)
00241 sqlcode = ECPG_WARNING_UNKNOWN_PORTAL;
00242 else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION) == 0)
00243 sqlcode = ECPG_WARNING_IN_TRANSACTION;
00244 else if (strcmp(sqlstate, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION) == 0)
00245 sqlcode = ECPG_WARNING_NO_TRANSACTION;
00246 else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR) == 0)
00247 sqlcode = ECPG_WARNING_PORTAL_EXISTS;
00248 else
00249 sqlcode = 0;
00250
00251 strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
00252 sqlca->sqlcode = sqlcode;
00253 sqlca->sqlwarn[2] = 'W';
00254 sqlca->sqlwarn[0] = 'W';
00255
00256 strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
00257 sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
00258 sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
00259
00260 ecpg_log("raising sqlcode %d\n", sqlcode);
00261 }
00262
00263
00264 bool
00265 ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
00266 {
00267 struct sqlca_t *sqlca = ECPGget_sqlca();
00268 enum COMPAT_MODE compat = c;
00269 struct connection *this;
00270 int i,
00271 connect_params = 0;
00272 char *dbname = name ? ecpg_strdup(name, lineno) : NULL,
00273 *host = NULL,
00274 *tmp,
00275 *port = NULL,
00276 *realname = NULL,
00277 *options = NULL;
00278 const char **conn_keywords;
00279 const char **conn_values;
00280
00281 ecpg_init_sqlca(sqlca);
00282
00283
00284
00285
00286
00287 ecpg_clear_auto_mem();
00288
00289 if (INFORMIX_MODE(compat))
00290 {
00291 char *envname;
00292
00293
00294
00295
00296
00297
00298 envname = getenv("PG_DBPATH");
00299 if (envname)
00300 {
00301 ecpg_free(dbname);
00302 dbname = ecpg_strdup(envname, lineno);
00303 }
00304
00305 }
00306
00307 if (dbname == NULL && connection_name == NULL)
00308 connection_name = "DEFAULT";
00309
00310 #if ENABLE_THREAD_SAFETY
00311 ecpg_pthreads_init();
00312 #endif
00313
00314
00315 if (ecpg_get_connection(connection_name))
00316 {
00317 ecpg_free(dbname);
00318 ecpg_log("ECPGconnect: connection identifier %s is already in use\n",
00319 connection_name);
00320 return false;
00321 }
00322
00323 if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL)
00324 return false;
00325
00326 if (dbname != NULL)
00327 {
00328
00329 if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
00330 {
00331 int offset = 0;
00332
00333
00334
00335
00336 if (strncmp(dbname, "tcp:", 4) == 0)
00337 offset = 4;
00338 else if (strncmp(dbname, "unix:", 5) == 0)
00339 offset = 5;
00340
00341 if (strncmp(dbname + offset, "postgresql://", strlen("postgresql://")) == 0)
00342 {
00343
00344
00345
00346
00347
00348
00349
00350 offset += strlen("postgresql://");
00351
00352 tmp = strrchr(dbname + offset, '?');
00353 if (tmp != NULL)
00354 {
00355 options = ecpg_strdup(tmp + 1, lineno);
00356 *tmp = '\0';
00357 }
00358
00359 tmp = last_dir_separator(dbname + offset);
00360 if (tmp != NULL)
00361 {
00362 if (tmp[1] != '\0')
00363 {
00364 realname = ecpg_strdup(tmp + 1, lineno);
00365 connect_params++;
00366 }
00367 *tmp = '\0';
00368 }
00369
00370 tmp = strrchr(dbname + offset, ':');
00371 if (tmp != NULL)
00372 {
00373 char *tmp2;
00374
00375 *tmp = '\0';
00376 if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
00377 {
00378 *tmp2 = '\0';
00379 host = ecpg_strdup(tmp + 1, lineno);
00380 connect_params++;
00381 if (strncmp(dbname, "unix:", 5) != 0)
00382 {
00383 ecpg_log("ECPGconnect: socketname %s given for TCP connection on line %d\n", host, lineno);
00384 ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
00385 if (host)
00386 ecpg_free(host);
00387
00388
00389
00390
00391 if (options)
00392 ecpg_free(options);
00393 if (realname)
00394 ecpg_free(realname);
00395 if (dbname)
00396 ecpg_free(dbname);
00397 free(this);
00398 return false;
00399 }
00400 }
00401 else
00402 {
00403 port = ecpg_strdup(tmp + 1, lineno);
00404 connect_params++;
00405 }
00406 }
00407
00408 if (strncmp(dbname, "unix:", 5) == 0)
00409 {
00410 if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0)
00411 {
00412 ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno);
00413 ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
00414 if (host)
00415 ecpg_free(host);
00416 if (port)
00417 ecpg_free(port);
00418 if (options)
00419 ecpg_free(options);
00420 if (realname)
00421 ecpg_free(realname);
00422 if (dbname)
00423 ecpg_free(dbname);
00424 free(this);
00425 return false;
00426 }
00427 }
00428 else
00429 {
00430 host = ecpg_strdup(dbname + offset, lineno);
00431 connect_params++;
00432 }
00433
00434 }
00435 }
00436 else
00437 {
00438
00439 tmp = strrchr(dbname, ':');
00440 if (tmp != NULL)
00441 {
00442 port = ecpg_strdup(tmp + 1, lineno);
00443 connect_params++;
00444 *tmp = '\0';
00445 }
00446
00447 tmp = strrchr(dbname, '@');
00448 if (tmp != NULL)
00449 {
00450 host = ecpg_strdup(tmp + 1, lineno);
00451 connect_params++;
00452 *tmp = '\0';
00453 }
00454
00455 if (strlen(dbname) > 0)
00456 {
00457 realname = ecpg_strdup(dbname, lineno);
00458 connect_params++;
00459 }
00460 else
00461 realname = NULL;
00462 }
00463 }
00464 else
00465 realname = NULL;
00466
00467
00468 #ifdef ENABLE_THREAD_SAFETY
00469 pthread_mutex_lock(&connections_mutex);
00470 #endif
00471 if (connection_name != NULL)
00472 this->name = ecpg_strdup(connection_name, lineno);
00473 else
00474 this->name = ecpg_strdup(realname, lineno);
00475
00476 this->cache_head = NULL;
00477 this->prep_stmts = NULL;
00478
00479 if (all_connections == NULL)
00480 this->next = NULL;
00481 else
00482 this->next = all_connections;
00483
00484 all_connections = this;
00485 #ifdef ENABLE_THREAD_SAFETY
00486 pthread_setspecific(actual_connection_key, all_connections);
00487 #endif
00488 actual_connection = all_connections;
00489
00490 ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n",
00491 realname ? realname : "<DEFAULT>",
00492 host ? host : "<DEFAULT>",
00493 port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>",
00494 options ? "with options " : "", options ? options : "",
00495 (user && strlen(user) > 0) ? "for user " : "", user ? user : "");
00496
00497 if (options)
00498 for (i = 0; options[i]; i++)
00499
00500 if (options[i] == '=')
00501 connect_params++;
00502
00503 if (user && strlen(user) > 0)
00504 connect_params++;
00505 if (passwd && strlen(passwd) > 0)
00506 connect_params++;
00507
00508
00509 conn_keywords = (const char **) ecpg_alloc((connect_params + 1) * sizeof(char *), lineno);
00510 conn_values = (const char **) ecpg_alloc(connect_params * sizeof(char *), lineno);
00511 if (conn_keywords == NULL || conn_values == NULL)
00512 {
00513 if (host)
00514 ecpg_free(host);
00515 if (port)
00516 ecpg_free(port);
00517 if (options)
00518 ecpg_free(options);
00519 if (realname)
00520 ecpg_free(realname);
00521 if (dbname)
00522 ecpg_free(dbname);
00523 if (conn_keywords)
00524 ecpg_free(conn_keywords);
00525 if (conn_values)
00526 ecpg_free(conn_values);
00527 free(this);
00528 return false;
00529 }
00530
00531 i = 0;
00532 if (realname)
00533 {
00534 conn_keywords[i] = "dbname";
00535 conn_values[i] = realname;
00536 i++;
00537 }
00538 if (host)
00539 {
00540 conn_keywords[i] = "host";
00541 conn_values[i] = host;
00542 i++;
00543 }
00544 if (port)
00545 {
00546 conn_keywords[i] = "port";
00547 conn_values[i] = port;
00548 i++;
00549 }
00550 if (user && strlen(user) > 0)
00551 {
00552 conn_keywords[i] = "user";
00553 conn_values[i] = user;
00554 i++;
00555 }
00556 if (passwd && strlen(passwd) > 0)
00557 {
00558 conn_keywords[i] = "password";
00559 conn_values[i] = passwd;
00560 i++;
00561 }
00562 if (options)
00563 {
00564 char *str;
00565
00566
00567
00568 for (str = options; *str;)
00569 {
00570 int e,
00571 a;
00572 char *token1,
00573 *token2;
00574
00575 for (token1 = str; *token1 && *token1 == ' '; token1++);
00576 for (e = 0; token1[e] && token1[e] != '='; e++);
00577 if (token1[e])
00578 {
00579 token1[e] = '\0';
00580 for (token2 = token1 + e + 1; *token2 && *token2 == ' '; token2++);
00581 for (a = 0; token2[a] && token2[a] != '&'; a++);
00582 if (token2[a])
00583 {
00584 token2[a] = '\0';
00585 str = token2 + a + 1;
00586 }
00587 else
00588 str = token2 + a;
00589
00590 conn_keywords[i] = token1;
00591 conn_values[i] = token2;
00592 i++;
00593 }
00594 else
00595
00596 str = token1 + e;
00597 }
00598
00599 }
00600 conn_keywords[i] = NULL;
00601
00602 this->connection = PQconnectdbParams(conn_keywords, conn_values, 0);
00603
00604 if (host)
00605 ecpg_free(host);
00606 if (port)
00607 ecpg_free(port);
00608 if (options)
00609 ecpg_free(options);
00610 if (dbname)
00611 ecpg_free(dbname);
00612 ecpg_free(conn_values);
00613 ecpg_free(conn_keywords);
00614
00615 if (PQstatus(this->connection) == CONNECTION_BAD)
00616 {
00617 const char *errmsg = PQerrorMessage(this->connection);
00618 const char *db = realname ? realname : ecpg_gettext("<DEFAULT>");
00619
00620 ecpg_log("ECPGconnect: could not open database: %s\n", errmsg);
00621
00622 ecpg_finish(this);
00623 #ifdef ENABLE_THREAD_SAFETY
00624 pthread_mutex_unlock(&connections_mutex);
00625 #endif
00626
00627 ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
00628 if (realname)
00629 ecpg_free(realname);
00630
00631 return false;
00632 }
00633
00634 if (realname)
00635 ecpg_free(realname);
00636
00637 #ifdef ENABLE_THREAD_SAFETY
00638 pthread_mutex_unlock(&connections_mutex);
00639 #endif
00640
00641 this->autocommit = autocommit;
00642
00643 PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, (void *) this);
00644
00645 return true;
00646 }
00647
00648 bool
00649 ECPGdisconnect(int lineno, const char *connection_name)
00650 {
00651 struct sqlca_t *sqlca = ECPGget_sqlca();
00652 struct connection *con;
00653
00654 #ifdef ENABLE_THREAD_SAFETY
00655 pthread_mutex_lock(&connections_mutex);
00656 #endif
00657
00658 if (strcmp(connection_name, "ALL") == 0)
00659 {
00660 ecpg_init_sqlca(sqlca);
00661 for (con = all_connections; con;)
00662 {
00663 struct connection *f = con;
00664
00665 con = con->next;
00666 ecpg_finish(f);
00667 }
00668 }
00669 else
00670 {
00671 con = ecpg_get_connection_nr(connection_name);
00672
00673 if (!ecpg_init(con, connection_name, lineno))
00674 {
00675 #ifdef ENABLE_THREAD_SAFETY
00676 pthread_mutex_unlock(&connections_mutex);
00677 #endif
00678 return (false);
00679 }
00680 else
00681 ecpg_finish(con);
00682 }
00683
00684 #ifdef ENABLE_THREAD_SAFETY
00685 pthread_mutex_unlock(&connections_mutex);
00686 #endif
00687
00688 return true;
00689 }
00690
00691 PGconn *
00692 ECPGget_PGconn(const char *connection_name)
00693 {
00694 struct connection *con;
00695
00696 con = ecpg_get_connection(connection_name);
00697 if (con == NULL)
00698 return NULL;
00699
00700 return con->connection;
00701 }