LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - connect.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 271 349 77.7 %
Date: 2024-11-21 08:14:44 Functions: 10 11 90.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14