Header And Logo

PostgreSQL
| The world's most advanced open source database.

connect.c

Go to the documentation of this file.
00001 /* src/interfaces/ecpg/ecpglib/connect.c */
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          * if no connection in TSD for this thread, get the global default
00047          * connection and hope the user knows what they're doing (i.e. using
00048          * their own mutex to protect that connection from concurrent accesses
00049          */
00050         /* if !ret then  we  got the connection from TSD */
00051         if (NULL == ret)
00052             /* no TSD connection, going for global */
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          * if no connection in TSD for this thread, get the global default
00085          * connection and hope the user knows what they're doing (i.e. using
00086          * their own mutex to protect that connection from concurrent accesses
00087          */
00088         /* if !ret then  we  got the connection from TSD */
00089         if (NULL == ret)
00090             /* no TSD connection here either, using global */
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          * no need to lock connections_mutex - we're always called by
00125          * ECPGdisconnect or ECPGconnect, which are holding the lock
00126          */
00127 
00128         /* remove act from the list */
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         /* delete cursor variables when last connection gets closed */
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;                 /* keep the compiler quiet */
00227     if (sqlstate == NULL)
00228         sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR;
00229 
00230     if (message == NULL)        /* Shouldn't happen, but need to be sure */
00231         message = ecpg_gettext("empty message text");
00232 
00233     /* these are not warnings */
00234     if (strncmp(sqlstate, "00", 2) == 0)
00235         return;
00236 
00237     ecpg_log("ECPGnoticeReceiver: %s\n", message);
00238 
00239     /* map to SQLCODE for backward compatibility */
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 /* this contains some quick hacks, needs to be cleaned up, but it works */
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      * clear auto_mem structure because some error handling functions might
00285      * access it
00286      */
00287     ecpg_clear_auto_mem();
00288 
00289     if (INFORMIX_MODE(compat))
00290     {
00291         char       *envname;
00292 
00293         /*
00294          * Informix uses an environment variable DBPATH that overrides the
00295          * connection parameters given here. We do the same with PG_DBPATH as
00296          * the syntax is different.
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     /* check if the identifier is unique */
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         /* get the detail information out of dbname */
00329         if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
00330         {
00331             int         offset = 0;
00332 
00333             /*
00334              * only allow protocols tcp and unix
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                  * new style:
00346                  *  <tcp|unix>:postgresql://server[:port|:/unixsocket/path:]
00347                  *  [/db name][?options]
00348                  *------
00349                  */
00350                 offset += strlen("postgresql://");
00351 
00352                 tmp = strrchr(dbname + offset, '?');
00353                 if (tmp != NULL)    /* options given */
00354                 {
00355                     options = ecpg_strdup(tmp + 1, lineno);
00356                     *tmp = '\0';
00357                 }
00358 
00359                 tmp = last_dir_separator(dbname + offset);
00360                 if (tmp != NULL)    /* database name given */
00361                 {
00362                     if (tmp[1] != '\0') /* non-empty database name */
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)    /* port number or Unix socket path given */
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                              * port not set yet if (port) ecpg_free(port);
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             /* old style: dbname[@server][:port] */
00439             tmp = strrchr(dbname, ':');
00440             if (tmp != NULL)    /* port number given */
00441             {
00442                 port = ecpg_strdup(tmp + 1, lineno);
00443                 connect_params++;
00444                 *tmp = '\0';
00445             }
00446 
00447             tmp = strrchr(dbname, '@');
00448             if (tmp != NULL)    /* host name given */
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     /* add connection to our list */
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             /* count options */
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     /* allocate enough space for all connection parameters */
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         /* options look like this "option1 = value1 option2 = value2 ... */
00567         /* we have to break up the string into single options */
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])      /* found "=" */
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])  /* found "&" => another option follows */
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                 /* the parser should not be able to create this invalid option */
00596                 str = token1 + e;
00597         }
00598 
00599     }
00600     conn_keywords[i] = NULL;    /* terminator */
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 }