LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - connect.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 72.7 % 355 258
Test Date: 2026-02-17 17:20:33 Functions: 90.9 % 11 10
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          115 : ecpg_actual_connection_init(void)
      25              : {
      26          115 :     pthread_key_create(&actual_connection_key, NULL);
      27          115 : }
      28              : 
      29              : void
      30        12732 : ecpg_pthreads_init(void)
      31              : {
      32        12732 :     pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
      33        12732 : }
      34              : 
      35              : static struct connection *
      36         1052 : ecpg_get_connection_nr(const char *connection_name)
      37              : {
      38         1052 :     struct connection *ret = NULL;
      39              : 
      40         1052 :     if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
      41              :     {
      42           89 :         ecpg_pthreads_init();   /* ensure actual_connection_key is valid */
      43              : 
      44           89 :         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           89 :         if (ret == NULL)
      52              :             /* no TSD connection, going for global */
      53            4 :             ret = actual_connection;
      54              :     }
      55              :     else
      56              :     {
      57              :         struct connection *con;
      58              : 
      59         3864 :         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         3684 :             if (con->name != NULL && strcmp(connection_name, con->name) == 0)
      67          783 :                 break;
      68              :         }
      69          963 :         ret = con;
      70              :     }
      71              : 
      72         1052 :     return ret;
      73              : }
      74              : 
      75              : struct connection *
      76         7880 : ecpg_get_connection(const char *connection_name)
      77              : {
      78         7880 :     struct connection *ret = NULL;
      79              : 
      80         7880 :     if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
      81              :     {
      82         7061 :         ecpg_pthreads_init();   /* ensure actual_connection_key is valid */
      83              : 
      84         7061 :         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         7061 :         if (ret == NULL)
      92              :             /* no TSD connection here either, using global */
      93          116 :             ret = actual_connection;
      94              :     }
      95              :     else
      96              :     {
      97          819 :         pthread_mutex_lock(&connections_mutex);
      98              : 
      99          819 :         ret = ecpg_get_connection_nr(connection_name);
     100              : 
     101          819 :         pthread_mutex_unlock(&connections_mutex);
     102              :     }
     103              : 
     104         7880 :     return ret;
     105              : }
     106              : 
     107              : static void
     108          256 : ecpg_finish(struct connection *act)
     109              : {
     110          256 :     if (act != NULL)
     111              :     {
     112              :         struct ECPGtype_information_cache *cache,
     113              :                    *ptr;
     114              : 
     115          256 :         ecpg_deallocate_all_conn(0, ECPG_COMPAT_PGSQL, act);
     116          256 :         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          256 :         if (act == all_connections)
     125          161 :             all_connections = act->next;
     126              :         else
     127              :         {
     128              :             struct connection *con;
     129              : 
     130          481 :             for (con = all_connections; con->next && con->next != act; con = con->next);
     131           95 :             if (con->next)
     132           95 :                 con->next = act->next;
     133              :         }
     134              : 
     135          256 :         if (pthread_getspecific(actual_connection_key) == act)
     136          256 :             pthread_setspecific(actual_connection_key, all_connections);
     137          256 :         if (actual_connection == act)
     138          161 :             actual_connection = all_connections;
     139              : 
     140          256 :         ecpg_log("ecpg_finish: connection %s closed\n", act->name ? act->name : "(null)");
     141              : 
     142         5028 :         for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ecpg_free(ptr));
     143          256 :         ecpg_free(act->name);
     144          256 :         ecpg_free(act);
     145              :         /* delete cursor variables when last connection gets closed */
     146          256 :         if (all_connections == NULL)
     147              :         {
     148              :             struct var_list *iv_ptr;
     149              : 
     150          174 :             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          256 : }
     156              : 
     157              : bool
     158           86 : ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
     159              : {
     160           86 :     struct connection *con = ecpg_get_connection(connection_name);
     161              :     PGresult   *results;
     162              : 
     163           86 :     if (!ecpg_init(con, connection_name, lineno))
     164            0 :         return false;
     165              : 
     166           86 :     ecpg_log("ECPGsetcommit on line %d: action \"%s\"; connection \"%s\"\n", lineno, mode, con->name);
     167              : 
     168           86 :     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           86 :     else if (!con->autocommit && strncmp(mode, "on", strlen("on")) == 0)
     180              :     {
     181           80 :         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           80 :         con->autocommit = true;
     189              :     }
     190              : 
     191           86 :     return true;
     192              : }
     193              : 
     194              : bool
     195            4 : ECPGsetconn(int lineno, const char *connection_name)
     196              : {
     197            4 :     struct connection *con = ecpg_get_connection(connection_name);
     198              : 
     199            4 :     if (!ecpg_init(con, connection_name, lineno))
     200            0 :         return false;
     201              : 
     202            4 :     pthread_setspecific(actual_connection_key, con);
     203            4 :     return true;
     204              : }
     205              : 
     206              : 
     207              : static void
     208            2 : ECPGnoticeReceiver(void *arg, const PGresult *result)
     209              : {
     210            2 :     char       *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
     211            2 :     char       *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
     212            2 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     213              :     int         sqlcode;
     214              : 
     215            2 :     if (sqlca == NULL)
     216              :     {
     217            0 :         ecpg_log("out of memory");
     218            0 :         return;
     219              :     }
     220              : 
     221              :     (void) arg;                 /* keep the compiler quiet */
     222            2 :     if (sqlstate == NULL)
     223            0 :         sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR;
     224              : 
     225            2 :     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            2 :     if (strncmp(sqlstate, "00", 2) == 0)
     230            2 :         return;
     231              : 
     232            0 :     ecpg_log("ECPGnoticeReceiver: %s\n", message);
     233              : 
     234              :     /* map to SQLCODE for backward compatibility */
     235            0 :     if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME) == 0)
     236            0 :         sqlcode = ECPG_WARNING_UNKNOWN_PORTAL;
     237            0 :     else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION) == 0)
     238            0 :         sqlcode = ECPG_WARNING_IN_TRANSACTION;
     239            0 :     else if (strcmp(sqlstate, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION) == 0)
     240            0 :         sqlcode = ECPG_WARNING_NO_TRANSACTION;
     241            0 :     else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR) == 0)
     242            0 :         sqlcode = ECPG_WARNING_PORTAL_EXISTS;
     243              :     else
     244            0 :         sqlcode = 0;
     245              : 
     246            0 :     strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
     247            0 :     sqlca->sqlcode = sqlcode;
     248            0 :     sqlca->sqlwarn[2] = 'W';
     249            0 :     sqlca->sqlwarn[0] = 'W';
     250              : 
     251            0 :     strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
     252            0 :     sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
     253            0 :     sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
     254              : 
     255            0 :     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          273 : ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
     261              : {
     262          273 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     263          273 :     enum COMPAT_MODE compat = c;
     264              :     struct connection *this;
     265              :     int         i,
     266          273 :                 connect_params = 0;
     267          273 :     bool        alloc_failed = (sqlca == NULL);
     268          273 :     char       *dbname = name ? ecpg_strdup(name, lineno, &alloc_failed) : NULL,
     269          273 :                *host = NULL,
     270              :                *tmp,
     271          273 :                *port = NULL,
     272          273 :                *realname = NULL,
     273          273 :                *options = NULL;
     274              :     const char **conn_keywords;
     275              :     const char **conn_values;
     276              : 
     277          273 :     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          273 :     ecpg_init_sqlca(sqlca);
     287              : 
     288              :     /*
     289              :      * clear auto_mem structure because some error handling functions might
     290              :      * access it
     291              :      */
     292          273 :     ecpg_clear_auto_mem();
     293              : 
     294          273 :     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           12 :         envname = getenv("PG_DBPATH");
     304           12 :         if (envname)
     305              :         {
     306            0 :             ecpg_free(dbname);
     307            0 :             dbname = ecpg_strdup(envname, lineno, &alloc_failed);
     308              :         }
     309              :     }
     310              : 
     311          273 :     if (dbname == NULL && connection_name == NULL)
     312            0 :         connection_name = "DEFAULT";
     313              : 
     314          273 :     ecpg_pthreads_init();
     315              : 
     316              :     /* check if the identifier is unique */
     317          273 :     if (ecpg_get_connection(connection_name))
     318              :     {
     319            4 :         ecpg_free(dbname);
     320            4 :         ecpg_log("ECPGconnect: connection identifier %s is already in use\n",
     321              :                  connection_name);
     322            4 :         return false;
     323              :     }
     324              : 
     325          269 :     if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL)
     326              :     {
     327            0 :         ecpg_free(dbname);
     328            0 :         return false;
     329              :     }
     330              : 
     331          269 :     if (dbname != NULL)
     332              :     {
     333              :         /* get the detail information from dbname */
     334          269 :         if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
     335           18 :         {
     336           20 :             int         offset = 0;
     337              : 
     338              :             /*
     339              :              * only allow protocols tcp and unix
     340              :              */
     341           20 :             if (strncmp(dbname, "tcp:", 4) == 0)
     342            5 :                 offset = 4;
     343           15 :             else if (strncmp(dbname, "unix:", 5) == 0)
     344           15 :                 offset = 5;
     345              : 
     346           20 :             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           20 :                 offset += strlen("postgresql://");
     355              : 
     356           20 :                 tmp = strrchr(dbname + offset, '?');
     357           20 :                 if (tmp != NULL)    /* options given */
     358              :                 {
     359            5 :                     options = ecpg_strdup(tmp + 1, lineno, &alloc_failed);
     360            5 :                     *tmp = '\0';
     361              :                 }
     362              : 
     363           20 :                 tmp = last_dir_separator(dbname + offset);
     364           20 :                 if (tmp != NULL)    /* database name given */
     365              :                 {
     366           20 :                     if (tmp[1] != '\0') /* non-empty database name */
     367              :                     {
     368           17 :                         realname = ecpg_strdup(tmp + 1, lineno, &alloc_failed);
     369           17 :                         connect_params++;
     370              :                     }
     371           20 :                     *tmp = '\0';
     372              :                 }
     373              : 
     374           20 :                 tmp = strrchr(dbname + offset, ':');
     375           20 :                 if (tmp != NULL)    /* port number given */
     376              :                 {
     377            1 :                     *tmp = '\0';
     378            1 :                     port = ecpg_strdup(tmp + 1, lineno, &alloc_failed);
     379            1 :                     connect_params++;
     380              :                 }
     381              : 
     382           20 :                 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           15 :                     if (strcmp(dbname + offset, "localhost") != 0 &&
     390            2 :                         strcmp(dbname + offset, "127.0.0.1") != 0)
     391              :                     {
     392            2 :                         ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno);
     393            2 :                         ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
     394            2 :                         if (host)
     395            0 :                             ecpg_free(host);
     396            2 :                         if (port)
     397            0 :                             ecpg_free(port);
     398            2 :                         if (options)
     399            0 :                             ecpg_free(options);
     400            2 :                         if (realname)
     401            2 :                             ecpg_free(realname);
     402            2 :                         if (dbname)
     403            2 :                             ecpg_free(dbname);
     404            2 :                         free(this);
     405            2 :                         return false;
     406              :                     }
     407              :                 }
     408              :                 else
     409              :                 {
     410            5 :                     if (*(dbname + offset) != '\0')
     411              :                     {
     412            5 :                         host = ecpg_strdup(dbname + offset, lineno, &alloc_failed);
     413            5 :                         connect_params++;
     414              :                     }
     415              :                 }
     416              :             }
     417              :         }
     418              :         else
     419              :         {
     420              :             /* old style: dbname[@server][:port] */
     421          249 :             tmp = strrchr(dbname, ':');
     422          249 :             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          249 :             tmp = strrchr(dbname, '@');
     430          249 :             if (tmp != NULL)    /* host name given */
     431              :             {
     432            2 :                 host = ecpg_strdup(tmp + 1, lineno, &alloc_failed);
     433            2 :                 connect_params++;
     434            2 :                 *tmp = '\0';
     435              :             }
     436              : 
     437          249 :             if (strlen(dbname) > 0)
     438              :             {
     439          248 :                 realname = ecpg_strdup(dbname, lineno, &alloc_failed);
     440          248 :                 connect_params++;
     441              :             }
     442              :             else
     443            1 :                 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          267 :     if (options)
     454          150 :         for (i = 0; options[i]; i++)
     455          145 :             if (options[i] == '=')
     456            7 :                 connect_params++;
     457              : 
     458          267 :     if (user && strlen(user) > 0)
     459           21 :         connect_params++;
     460          267 :     if (passwd && strlen(passwd) > 0)
     461           18 :         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          267 :     conn_keywords = (const char **) ecpg_alloc((connect_params + 1) * sizeof(char *), lineno);
     469          267 :     conn_values = (const char **) ecpg_alloc(connect_params * sizeof(char *), lineno);
     470              : 
     471              :     /* Decide on a connection name */
     472          267 :     if (connection_name != NULL || realname != NULL)
     473              :     {
     474          266 :         this->name = ecpg_strdup(connection_name ? connection_name : realname,
     475              :                                  lineno, &alloc_failed);
     476              :     }
     477              :     else
     478            1 :         this->name = NULL;
     479              : 
     480              :     /* Deal with any failed allocations above */
     481          267 :     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          267 :     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          267 :     if (!ecpg_clocale)
     512              :     {
     513          113 :         ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
     514          113 :         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          267 :     this->cache_head = NULL;
     542          267 :     this->prep_stmts = NULL;
     543              : 
     544          267 :     if (all_connections == NULL)
     545          157 :         this->next = NULL;
     546              :     else
     547          110 :         this->next = all_connections;
     548              : 
     549          267 :     all_connections = this;
     550          267 :     pthread_setspecific(actual_connection_key, all_connections);
     551          267 :     actual_connection = all_connections;
     552              : 
     553          289 :     ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n",
     554              :              realname ? realname : "<DEFAULT>",
     555              :              host ? host : "<DEFAULT>",
     556            1 :              port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>",
     557              :              options ? "with options " : "", options ? options : "",
     558           21 :              (user && strlen(user) > 0) ? "for user " : "", user ? user : "");
     559              : 
     560          267 :     i = 0;
     561          267 :     if (realname)
     562              :     {
     563          263 :         conn_keywords[i] = "dbname";
     564          263 :         conn_values[i] = realname;
     565          263 :         i++;
     566              :     }
     567          267 :     if (host)
     568              :     {
     569            7 :         conn_keywords[i] = "host";
     570            7 :         conn_values[i] = host;
     571            7 :         i++;
     572              :     }
     573          267 :     if (port)
     574              :     {
     575            1 :         conn_keywords[i] = "port";
     576            1 :         conn_values[i] = port;
     577            1 :         i++;
     578              :     }
     579          267 :     if (user && strlen(user) > 0)
     580              :     {
     581           21 :         conn_keywords[i] = "user";
     582           21 :         conn_values[i] = user;
     583           21 :         i++;
     584              :     }
     585          267 :     if (passwd && strlen(passwd) > 0)
     586              :     {
     587           18 :         conn_keywords[i] = "password";
     588           18 :         conn_values[i] = passwd;
     589           18 :         i++;
     590              :     }
     591          267 :     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           12 :         for (str = options; *str;)
     605              :         {
     606              :             int         e,
     607              :                         a;
     608              :             char       *token1,
     609              :                        *token2;
     610              : 
     611              :             /* Skip spaces before keyword */
     612            7 :             for (token1 = str; *token1 == ' '; token1++)
     613              :                  /* skip */ ;
     614              :             /* Find end of keyword */
     615          102 :             for (e = 0; token1[e] && token1[e] != '='; e++)
     616              :                  /* skip */ ;
     617            7 :             if (token1[e])      /* found "=" */
     618              :             {
     619            7 :                 token1[e] = '\0';
     620              :                 /* Skip spaces before value */
     621            7 :                 for (token2 = token1 + e + 1; *token2 == ' '; token2++)
     622              :                      /* skip */ ;
     623              :                 /* Find end of value */
     624           48 :                 for (a = 0; token2[a] && token2[a] != '&'; a++)
     625              :                      /* skip */ ;
     626            7 :                 if (token2[a])  /* found "&" => another option follows */
     627              :                 {
     628            2 :                     token2[a] = '\0';
     629            2 :                     str = token2 + a + 1;
     630              :                 }
     631              :                 else
     632            5 :                     str = token2 + a;
     633              : 
     634            7 :                 conn_keywords[i] = token1;
     635            7 :                 conn_values[i] = token2;
     636            7 :                 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          267 :     conn_keywords[i] = NULL;    /* terminator */
     648              : 
     649          267 :     this->connection = PQconnectdbParams(conn_keywords, conn_values, 0);
     650              : 
     651          267 :     if (host)
     652            7 :         ecpg_free(host);
     653          267 :     if (port)
     654            1 :         ecpg_free(port);
     655          267 :     if (options)
     656            5 :         ecpg_free(options);
     657          267 :     if (dbname)
     658          267 :         ecpg_free(dbname);
     659          267 :     ecpg_free(conn_values);
     660          267 :     ecpg_free(conn_keywords);
     661              : 
     662          267 :     if (PQstatus(this->connection) == CONNECTION_BAD)
     663              :     {
     664            6 :         const char *errmsg = PQerrorMessage(this->connection);
     665            6 :         const char *db = realname ? realname : ecpg_gettext("<DEFAULT>");
     666              : 
     667              :         /* PQerrorMessage's result already has a trailing newline */
     668            6 :         ecpg_log("ECPGconnect: %s", errmsg);
     669              : 
     670            6 :         ecpg_finish(this);
     671            6 :         pthread_mutex_unlock(&connections_mutex);
     672              : 
     673            6 :         ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
     674            6 :         if (realname)
     675            2 :             ecpg_free(realname);
     676              : 
     677            6 :         return false;
     678              :     }
     679              : 
     680          261 :     if (realname)
     681          261 :         ecpg_free(realname);
     682              : 
     683          261 :     pthread_mutex_unlock(&connections_mutex);
     684              : 
     685          261 :     this->autocommit = autocommit;
     686              : 
     687          261 :     PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, this);
     688              : 
     689          261 :     return true;
     690              : }
     691              : 
     692              : bool
     693          265 : ECPGdisconnect(int lineno, const char *connection_name)
     694              : {
     695          265 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     696              :     struct connection *con;
     697              : 
     698          265 :     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          265 :     pthread_mutex_lock(&connections_mutex);
     706              : 
     707          265 :     if (strcmp(connection_name, "ALL") == 0)
     708              :     {
     709           32 :         ecpg_init_sqlca(sqlca);
     710           68 :         for (con = all_connections; con;)
     711              :         {
     712           36 :             struct connection *f = con;
     713              : 
     714           36 :             con = con->next;
     715           36 :             ecpg_finish(f);
     716              :         }
     717              :     }
     718              :     else
     719              :     {
     720          233 :         con = ecpg_get_connection_nr(connection_name);
     721              : 
     722          233 :         if (!ecpg_init(con, connection_name, lineno))
     723              :         {
     724           19 :             pthread_mutex_unlock(&connections_mutex);
     725           19 :             return false;
     726              :         }
     727              :         else
     728          214 :             ecpg_finish(con);
     729              :     }
     730              : 
     731          246 :     pthread_mutex_unlock(&connections_mutex);
     732              : 
     733          246 :     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 2.0-1