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

Generated by: LCOV version 1.16