Age Owner Branch data TLA 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
7846 meskes@postgresql.or 24 :CBC 57 : ecpg_actual_connection_init(void)
25 : : {
7678 bruce@momjian.us 26 : 57 : pthread_key_create(&actual_connection_key, NULL);
7846 meskes@postgresql.or 27 : 57 : }
28 : :
29 : : void
6912 bruce@momjian.us 30 : 6364 : ecpg_pthreads_init(void)
31 : : {
6975 meskes@postgresql.or 32 : 6364 : pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
33 : 6364 : }
34 : :
35 : : static struct connection *
8103 36 : 520 : ecpg_get_connection_nr(const char *connection_name)
37 : : {
8069 bruce@momjian.us 38 : 520 : struct connection *ret = NULL;
39 : :
40 [ + - + + ]: 520 : if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
41 : : {
1180 tgl@sss.pgh.pa.us 42 : 41 : ecpg_pthreads_init(); /* ensure actual_connection_key is valid */
43 : :
7846 meskes@postgresql.or 44 : 41 : 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 : : */
1180 tgl@sss.pgh.pa.us 51 [ + + ]: 41 : if (ret == NULL)
52 : : /* no TSD connection, going for global */
7450 meskes@postgresql.or 53 : 1 : ret = actual_connection;
54 : : }
55 : : else
56 : : {
57 : : struct connection *con;
58 : :
8069 bruce@momjian.us 59 [ + + ]: 2009 : 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 : : */
46 michael@paquier.xyz 66 [ + - + + ]: 1921 : if (con->name != NULL && strcmp(connection_name, con->name) == 0)
8069 bruce@momjian.us 67 : 391 : break;
68 : : }
69 : 479 : ret = con;
70 : : }
71 : :
2942 peter_e@gmx.net 72 : 520 : return ret;
73 : : }
74 : :
75 : : struct connection *
6548 meskes@postgresql.or 76 : 3940 : ecpg_get_connection(const char *connection_name)
77 : : {
8069 bruce@momjian.us 78 : 3940 : struct connection *ret = NULL;
79 : :
7845 80 [ + + - + ]: 3940 : if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
81 : : {
1180 tgl@sss.pgh.pa.us 82 : 3532 : ecpg_pthreads_init(); /* ensure actual_connection_key is valid */
83 : :
7845 bruce@momjian.us 84 : 3532 : 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 : : */
1180 tgl@sss.pgh.pa.us 91 [ + + ]: 3532 : if (ret == NULL)
92 : : /* no TSD connection here either, using global */
7266 bruce@momjian.us 93 : 54 : ret = actual_connection;
94 : : }
95 : : else
96 : : {
7845 97 : 408 : pthread_mutex_lock(&connections_mutex);
98 : :
99 : 408 : ret = ecpg_get_connection_nr(connection_name);
100 : :
101 : 408 : pthread_mutex_unlock(&connections_mutex);
102 : : }
103 : :
2942 peter_e@gmx.net 104 : 3940 : return ret;
105 : : }
106 : :
107 : : static void
2999 tgl@sss.pgh.pa.us 108 : 123 : ecpg_finish(struct connection *act)
109 : : {
8210 meskes@postgresql.or 110 [ + - ]: 123 : if (act != NULL)
111 : : {
112 : : struct ECPGtype_information_cache *cache,
113 : : *ptr;
114 : :
6548 115 : 123 : ecpg_deallocate_all_conn(0, ECPG_COMPAT_PGSQL, act);
8210 116 : 123 : 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 [ + + ]: 123 : if (act == all_connections)
125 : 74 : all_connections = act->next;
126 : : else
127 : : {
128 : : struct connection *con;
129 : :
130 [ + - + + ]: 250 : for (con = all_connections; con->next && con->next != act; con = con->next);
131 [ + - ]: 49 : if (con->next)
132 : 49 : con->next = act->next;
133 : : }
134 : :
7678 bruce@momjian.us 135 [ + - ]: 123 : if (pthread_getspecific(actual_connection_key) == act)
136 : 123 : pthread_setspecific(actual_connection_key, all_connections);
8210 meskes@postgresql.or 137 [ + + ]: 123 : if (actual_connection == act)
138 : 74 : actual_connection = all_connections;
139 : :
6107 140 [ + - ]: 123 : ecpg_log("ecpg_finish: connection %s closed\n", act->name ? act->name : "(null)");
141 : :
6548 142 [ + + ]: 2509 : for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ecpg_free(ptr));
143 : 123 : ecpg_free(act->name);
144 : 123 : ecpg_free(act);
145 : : /* delete cursor variables when last connection gets closed */
4993 146 [ + + ]: 123 : if (all_connections == NULL)
147 : : {
148 : : struct var_list *iv_ptr;
149 : :
150 [ + + ]: 82 : for (; ivlist; iv_ptr = ivlist, ivlist = ivlist->next, ecpg_free(iv_ptr));
151 : : }
152 : : }
153 : : else
6322 peter_e@gmx.net 154 :UBC 0 : ecpg_log("ecpg_finish: called an extra time\n");
8210 meskes@postgresql.or 155 :CBC 123 : }
156 : :
157 : : bool
158 : 43 : ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
159 : : {
6548 160 : 43 : struct connection *con = ecpg_get_connection(connection_name);
161 : : PGresult *results;
162 : :
163 [ - + ]: 43 : if (!ecpg_init(con, connection_name, lineno))
2942 peter_e@gmx.net 164 :UBC 0 : return false;
165 : :
6322 peter_e@gmx.net 166 :CBC 43 : ecpg_log("ECPGsetcommit on line %d: action \"%s\"; connection \"%s\"\n", lineno, mode, con->name);
167 : :
5410 rhaas@postgresql.org 168 [ - + - - ]: 43 : if (con->autocommit && strncmp(mode, "off", strlen("off")) == 0)
169 : : {
5441 meskes@postgresql.or 170 [ # # ]:UBC 0 : if (PQtransactionStatus(con->connection) == PQTRANS_IDLE)
171 : : {
6598 172 : 0 : results = PQexec(con->connection, "begin transaction");
6548 173 [ # # ]: 0 : if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
8210 174 : 0 : return false;
175 : 0 : PQclear(results);
176 : : }
177 : 0 : con->autocommit = false;
178 : : }
5410 rhaas@postgresql.org 179 [ + - + + ]:CBC 43 : else if (!con->autocommit && strncmp(mode, "on", strlen("on")) == 0)
180 : : {
5441 meskes@postgresql.or 181 [ - + ]: 40 : if (PQtransactionStatus(con->connection) != PQTRANS_IDLE)
182 : : {
6598 meskes@postgresql.or 183 :UBC 0 : results = PQexec(con->connection, "commit");
6548 184 [ # # ]: 0 : if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
8210 185 : 0 : return false;
186 : 0 : PQclear(results);
187 : : }
8210 meskes@postgresql.or 188 :CBC 40 : con->autocommit = true;
189 : : }
190 : :
191 : 43 : return true;
192 : : }
193 : :
194 : : bool
195 : 2 : ECPGsetconn(int lineno, const char *connection_name)
196 : : {
6548 197 : 2 : struct connection *con = ecpg_get_connection(connection_name);
198 : :
199 [ - + ]: 2 : if (!ecpg_init(con, connection_name, lineno))
2942 peter_e@gmx.net 200 :UBC 0 : return false;
201 : :
7846 meskes@postgresql.or 202 :CBC 2 : pthread_setspecific(actual_connection_key, con);
8210 203 : 2 : return true;
204 : : }
205 : :
206 : :
207 : : static void
8072 peter_e@gmx.net 208 : 2 : ECPGnoticeReceiver(void *arg, const PGresult *result)
209 : : {
8049 210 : 2 : char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
211 : 2 : char *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
8119 bruce@momjian.us 212 : 2 : struct sqlca_t *sqlca = ECPGget_sqlca();
213 : : int sqlcode;
214 : :
3736 meskes@postgresql.or 215 [ - + ]: 2 : if (sqlca == NULL)
216 : : {
3736 meskes@postgresql.or 217 :UBC 0 : ecpg_log("out of memory");
218 : 0 : return;
219 : : }
220 : :
221 : : (void) arg; /* keep the compiler quiet */
8065 peter_e@gmx.net 222 [ - + ]:CBC 2 : if (sqlstate == NULL)
8065 peter_e@gmx.net 223 :UBC 0 : sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR;
224 : :
6912 bruce@momjian.us 225 [ - + ]:CBC 2 : if (message == NULL) /* Shouldn't happen, but need to be sure */
6078 peter_e@gmx.net 226 :UBC 0 : message = ecpg_gettext("empty message text");
227 : :
228 : : /* these are not warnings */
8069 bruce@momjian.us 229 [ + + ]:CBC 2 : if (strncmp(sqlstate, "00", 2) == 0)
8210 meskes@postgresql.or 230 : 1 : return;
231 : :
6322 peter_e@gmx.net 232 : 1 : ecpg_log("ECPGnoticeReceiver: %s\n", message);
233 : :
234 : : /* map to SQLCODE for backward compatibility */
8069 bruce@momjian.us 235 [ - + ]: 1 : if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME) == 0)
8072 peter_e@gmx.net 236 :UBC 0 : sqlcode = ECPG_WARNING_UNKNOWN_PORTAL;
8069 bruce@momjian.us 237 [ - + ]:CBC 1 : else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION) == 0)
8072 peter_e@gmx.net 238 :UBC 0 : sqlcode = ECPG_WARNING_IN_TRANSACTION;
8069 bruce@momjian.us 239 [ - + ]:CBC 1 : else if (strcmp(sqlstate, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION) == 0)
8072 peter_e@gmx.net 240 :UBC 0 : sqlcode = ECPG_WARNING_NO_TRANSACTION;
8069 bruce@momjian.us 241 [ - + ]:CBC 1 : else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR) == 0)
8072 peter_e@gmx.net 242 :UBC 0 : sqlcode = ECPG_WARNING_PORTAL_EXISTS;
243 : : else
8072 peter_e@gmx.net 244 :CBC 1 : sqlcode = 0;
245 : :
246 : 1 : strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
247 : 1 : sqlca->sqlcode = sqlcode;
8119 bruce@momjian.us 248 : 1 : sqlca->sqlwarn[2] = 'W';
249 : 1 : sqlca->sqlwarn[0] = 'W';
250 : :
8072 peter_e@gmx.net 251 : 1 : strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
252 : 1 : sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
253 : 1 : sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
254 : :
6548 meskes@postgresql.or 255 : 1 : 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
8109 260 : 131 : ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
261 : : {
8119 bruce@momjian.us 262 : 131 : struct sqlca_t *sqlca = ECPGget_sqlca();
8109 meskes@postgresql.or 263 : 131 : enum COMPAT_MODE compat = c;
264 : : struct connection *this;
265 : : int i,
4836 bruce@momjian.us 266 : 131 : connect_params = 0;
45 michael@paquier.xyz 267 :GNC 131 : bool alloc_failed = (sqlca == NULL);
268 [ + - ]: 131 : char *dbname = name ? ecpg_strdup(name, lineno, &alloc_failed) : NULL,
8210 meskes@postgresql.or 269 :CBC 131 : *host = NULL,
270 : : *tmp,
271 : 131 : *port = NULL,
272 : 131 : *realname = NULL,
4964 273 : 131 : *options = NULL;
274 : : const char **conn_keywords;
275 : : const char **conn_values;
276 : :
45 michael@paquier.xyz 277 [ - + ]:GNC 131 : if (alloc_failed)
278 : : {
3736 meskes@postgresql.or 279 :UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
280 : : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
45 michael@paquier.xyz 281 [ # # ]:UNC 0 : if (dbname)
282 : 0 : ecpg_free(dbname);
3736 meskes@postgresql.or 283 :UBC 0 : return false;
284 : : }
285 : :
6548 meskes@postgresql.or 286 :CBC 131 : ecpg_init_sqlca(sqlca);
287 : :
288 : : /*
289 : : * clear auto_mem structure because some error handling functions might
290 : : * access it
291 : : */
292 : 131 : ecpg_clear_auto_mem();
293 : :
8108 294 [ + + - + ]: 131 : 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 : : */
8109 303 : 6 : envname = getenv("PG_DBPATH");
304 [ - + ]: 6 : if (envname)
305 : : {
6548 meskes@postgresql.or 306 :UBC 0 : ecpg_free(dbname);
45 michael@paquier.xyz 307 :UNC 0 : dbname = ecpg_strdup(envname, lineno, &alloc_failed);
308 : : }
309 : : }
310 : :
8210 meskes@postgresql.or 311 [ - + - - ]:CBC 131 : if (dbname == NULL && connection_name == NULL)
8210 meskes@postgresql.or 312 :UBC 0 : connection_name = "DEFAULT";
313 : :
6975 meskes@postgresql.or 314 :CBC 131 : ecpg_pthreads_init();
315 : :
316 : : /* check if the identifier is unique */
6548 317 [ + + ]: 131 : if (ecpg_get_connection(connection_name))
318 : : {
319 : 2 : ecpg_free(dbname);
320 : 2 : ecpg_log("ECPGconnect: connection identifier %s is already in use\n",
321 : : connection_name);
6980 322 : 2 : return false;
323 : : }
324 : :
6548 325 [ - + ]: 129 : if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL)
326 : : {
3736 meskes@postgresql.or 327 :UBC 0 : ecpg_free(dbname);
6980 328 : 0 : return false;
329 : : }
330 : :
7555 meskes@postgresql.or 331 [ + - ]:CBC 129 : if (dbname != NULL)
332 : : {
333 : : /* get the detail information from dbname */
6950 334 [ + - + + ]: 129 : if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
7555 335 : 5 : {
336 : 6 : int offset = 0;
337 : :
338 : : /*
339 : : * only allow protocols tcp and unix
340 : : */
341 [ - + ]: 6 : if (strncmp(dbname, "tcp:", 4) == 0)
7555 meskes@postgresql.or 342 :UBC 0 : offset = 4;
7555 meskes@postgresql.or 343 [ + - ]:CBC 6 : else if (strncmp(dbname, "unix:", 5) == 0)
344 : 6 : offset = 5;
345 : :
346 [ + - ]: 6 : 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 : 6 : offset += strlen("postgresql://");
355 : :
356 : 6 : tmp = strrchr(dbname + offset, '?');
357 [ + + ]: 6 : if (tmp != NULL) /* options given */
358 : : {
45 michael@paquier.xyz 359 :GNC 2 : options = ecpg_strdup(tmp + 1, lineno, &alloc_failed);
7555 meskes@postgresql.or 360 :CBC 2 : *tmp = '\0';
361 : : }
362 : :
363 : 6 : tmp = last_dir_separator(dbname + offset);
364 [ + - ]: 6 : if (tmp != NULL) /* database name given */
365 : : {
6372 366 [ + + ]: 6 : if (tmp[1] != '\0') /* non-empty database name */
367 : : {
45 michael@paquier.xyz 368 :GNC 5 : realname = ecpg_strdup(tmp + 1, lineno, &alloc_failed);
4950 meskes@postgresql.or 369 :CBC 5 : connect_params++;
370 : : }
7555 371 : 6 : *tmp = '\0';
372 : : }
373 : :
374 : 6 : tmp = strrchr(dbname + offset, ':');
1668 tgl@sss.pgh.pa.us 375 [ - + ]: 6 : if (tmp != NULL) /* port number given */
376 : : {
7555 meskes@postgresql.or 377 :UBC 0 : *tmp = '\0';
45 michael@paquier.xyz 378 :UNC 0 : port = ecpg_strdup(tmp + 1, lineno, &alloc_failed);
1668 tgl@sss.pgh.pa.us 379 :UBC 0 : connect_params++;
380 : : }
381 : :
7555 meskes@postgresql.or 382 [ + - ]:CBC 6 : 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 : : */
1668 tgl@sss.pgh.pa.us 389 [ + + ]: 6 : if (strcmp(dbname + offset, "localhost") != 0 &&
390 [ + - ]: 1 : strcmp(dbname + offset, "127.0.0.1") != 0)
391 : : {
6322 peter_e@gmx.net 392 : 1 : ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno);
6078 393 [ - + ]: 1 : ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
8210 meskes@postgresql.or 394 [ - + ]: 1 : if (host)
6548 meskes@postgresql.or 395 :UBC 0 : ecpg_free(host);
8210 meskes@postgresql.or 396 [ - + ]:CBC 1 : if (port)
6548 meskes@postgresql.or 397 :UBC 0 : ecpg_free(port);
8210 meskes@postgresql.or 398 [ - + ]:CBC 1 : if (options)
6548 meskes@postgresql.or 399 :UBC 0 : ecpg_free(options);
8210 meskes@postgresql.or 400 [ + - ]:CBC 1 : if (realname)
6548 401 : 1 : ecpg_free(realname);
8210 402 [ + - ]: 1 : if (dbname)
6548 403 : 1 : ecpg_free(dbname);
6950 404 : 1 : free(this);
8210 405 : 1 : return false;
406 : : }
407 : : }
408 : : else
409 : : {
4266 meskes@postgresql.or 410 [ # # ]:UBC 0 : if (*(dbname + offset) != '\0')
411 : : {
45 michael@paquier.xyz 412 :UNC 0 : host = ecpg_strdup(dbname + offset, lineno, &alloc_failed);
4266 meskes@postgresql.or 413 :UBC 0 : connect_params++;
414 : : }
415 : : }
416 : : }
417 : : }
418 : : else
419 : : {
420 : : /* old style: dbname[@server][:port] */
6950 meskes@postgresql.or 421 :CBC 123 : tmp = strrchr(dbname, ':');
422 [ - + ]: 123 : if (tmp != NULL) /* port number given */
423 : : {
45 michael@paquier.xyz 424 :UNC 0 : port = ecpg_strdup(tmp + 1, lineno, &alloc_failed);
4950 meskes@postgresql.or 425 :UBC 0 : connect_params++;
6950 426 : 0 : *tmp = '\0';
427 : : }
428 : :
6950 meskes@postgresql.or 429 :CBC 123 : tmp = strrchr(dbname, '@');
430 [ - + ]: 123 : if (tmp != NULL) /* host name given */
431 : : {
45 michael@paquier.xyz 432 :UNC 0 : host = ecpg_strdup(tmp + 1, lineno, &alloc_failed);
4950 meskes@postgresql.or 433 :UBC 0 : connect_params++;
6950 434 : 0 : *tmp = '\0';
435 : : }
436 : :
4950 meskes@postgresql.or 437 [ + - ]:CBC 123 : if (strlen(dbname) > 0)
438 : : {
45 michael@paquier.xyz 439 :GNC 123 : realname = ecpg_strdup(dbname, lineno, &alloc_failed);
4950 meskes@postgresql.or 440 :CBC 123 : connect_params++;
441 : : }
442 : : else
4950 meskes@postgresql.or 443 :UBC 0 : realname = NULL;
444 : : }
445 : : }
446 : : else
7555 447 : 0 : realname = NULL;
448 : :
449 : : /*
450 : : * Count options for the allocation done below (this may produce an
451 : : * overestimate, it's ok).
452 : : */
4950 meskes@postgresql.or 453 [ + + ]:CBC 128 : if (options)
6372 454 [ + + ]: 65 : for (i = 0; options[i]; i++)
4950 455 [ + + ]: 63 : if (options[i] == '=')
456 : 3 : connect_params++;
457 : :
458 [ + + + - ]: 128 : if (user && strlen(user) > 0)
459 : 6 : connect_params++;
460 [ + + + - ]: 128 : if (passwd && strlen(passwd) > 0)
461 : 6 : 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 : : */
4836 bruce@momjian.us 468 : 128 : conn_keywords = (const char **) ecpg_alloc((connect_params + 1) * sizeof(char *), lineno);
469 : 128 : conn_values = (const char **) ecpg_alloc(connect_params * sizeof(char *), lineno);
470 : :
471 : : /* Decide on a connection name */
45 michael@paquier.xyz 472 [ + + + - ]:GNC 128 : if (connection_name != NULL || realname != NULL)
473 : : {
474 [ + + ]: 128 : this->name = ecpg_strdup(connection_name ? connection_name : realname,
475 : : lineno, &alloc_failed);
476 : : }
477 : : else
45 michael@paquier.xyz 478 :UNC 0 : this->name = NULL;
479 : :
480 : : /* Deal with any failed allocations above */
45 michael@paquier.xyz 481 [ + - + - :GNC 128 : if (conn_keywords == NULL || conn_values == NULL || alloc_failed)
- + ]
482 : : {
4950 meskes@postgresql.or 483 [ # # ]:UBC 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);
4930 peter_e@gmx.net 493 [ # # ]: 0 : if (conn_keywords)
494 : 0 : ecpg_free(conn_keywords);
495 [ # # ]: 0 : if (conn_values)
496 : 0 : ecpg_free(conn_values);
45 michael@paquier.xyz 497 [ # # ]:UNC 0 : if (this->name)
498 : 0 : ecpg_free(this->name);
4950 meskes@postgresql.or 499 :UBC 0 : free(this);
500 : 0 : return false;
501 : : }
502 : :
503 : : /* add connection to our list */
1454 michael@paquier.xyz 504 :CBC 128 : 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
162 peter@eisentraut.org 511 [ + + ]: 128 : if (!ecpg_clocale)
512 : : {
513 : 56 : ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
514 [ - + ]: 56 : if (!ecpg_clocale)
515 : : {
162 peter@eisentraut.org 516 :UBC 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);
45 michael@paquier.xyz 533 [ # # ]:UNC 0 : if (this->name)
534 : 0 : ecpg_free(this->name);
162 peter@eisentraut.org 535 :UBC 0 : free(this);
536 : 0 : return false;
537 : : }
538 : : }
539 : : #endif
540 : :
1454 michael@paquier.xyz 541 :CBC 128 : this->cache_head = NULL;
542 : 128 : this->prep_stmts = NULL;
543 : :
544 [ + + ]: 128 : if (all_connections == NULL)
545 : 73 : this->next = NULL;
546 : : else
547 : 55 : this->next = all_connections;
548 : :
549 : 128 : all_connections = this;
550 : 128 : pthread_setspecific(actual_connection_key, all_connections);
551 : 128 : actual_connection = all_connections;
552 : :
553 [ + + + + : 134 : ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n",
+ + + + -
+ - + +
+ ]
554 : : realname ? realname : "<DEFAULT>",
555 : : host ? host : "<DEFAULT>",
1454 michael@paquier.xyz 556 [ # # ]:UBC 0 : port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>",
557 : : options ? "with options " : "", options ? options : "",
1454 michael@paquier.xyz 558 [ + - ]:CBC 6 : (user && strlen(user) > 0) ? "for user " : "", user ? user : "");
559 : :
4964 meskes@postgresql.or 560 : 128 : i = 0;
561 [ + + ]: 128 : if (realname)
562 : : {
563 : 127 : conn_keywords[i] = "dbname";
564 : 127 : conn_values[i] = realname;
565 : 127 : i++;
566 : : }
567 [ - + ]: 128 : if (host)
568 : : {
4964 meskes@postgresql.or 569 :UBC 0 : conn_keywords[i] = "host";
570 : 0 : conn_values[i] = host;
571 : 0 : i++;
572 : : }
4964 meskes@postgresql.or 573 [ - + ]:CBC 128 : if (port)
574 : : {
4964 meskes@postgresql.or 575 :UBC 0 : conn_keywords[i] = "port";
576 : 0 : conn_values[i] = port;
577 : 0 : i++;
578 : : }
4964 meskes@postgresql.or 579 [ + + + - ]:CBC 128 : if (user && strlen(user) > 0)
580 : : {
581 : 6 : conn_keywords[i] = "user";
582 : 6 : conn_values[i] = user;
583 : 6 : i++;
584 : : }
585 [ + + + - ]: 128 : if (passwd && strlen(passwd) > 0)
586 : : {
587 : 6 : conn_keywords[i] = "password";
588 : 6 : conn_values[i] = passwd;
589 : 6 : i++;
590 : : }
591 [ + + ]: 128 : 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 : : */
4948 604 [ + + ]: 5 : for (str = options; *str;)
605 : : {
606 : : int e,
607 : : a;
608 : : char *token1,
609 : : *token2;
610 : :
611 : : /* Skip spaces before keyword */
2198 tgl@sss.pgh.pa.us 612 [ - + ]: 3 : for (token1 = str; *token1 == ' '; token1++)
613 : : /* skip */ ;
614 : : /* Find end of keyword */
615 [ + - + + ]: 43 : for (e = 0; token1[e] && token1[e] != '='; e++)
616 : : /* skip */ ;
4836 bruce@momjian.us 617 [ + - ]: 3 : if (token1[e]) /* found "=" */
618 : : {
4948 meskes@postgresql.or 619 : 3 : token1[e] = '\0';
620 : : /* Skip spaces before value */
2198 tgl@sss.pgh.pa.us 621 [ - + ]: 3 : for (token2 = token1 + e + 1; *token2 == ' '; token2++)
622 : : /* skip */ ;
623 : : /* Find end of value */
624 [ + + + + ]: 22 : for (a = 0; token2[a] && token2[a] != '&'; a++)
625 : : /* skip */ ;
4836 bruce@momjian.us 626 [ + + ]: 3 : if (token2[a]) /* found "&" => another option follows */
627 : : {
4948 meskes@postgresql.or 628 : 1 : token2[a] = '\0';
629 : 1 : str = token2 + a + 1;
630 : : }
631 : : else
632 : 2 : str = token2 + a;
633 : :
634 : 3 : conn_keywords[i] = token1;
635 : 3 : conn_values[i] = token2;
636 : 3 : i++;
637 : : }
638 : : else
639 : : {
640 : : /* Bogus options syntax ... ignore trailing garbage */
4836 bruce@momjian.us 641 :UBC 0 : str = token1 + e;
642 : : }
643 : : }
644 : : }
645 : :
2198 tgl@sss.pgh.pa.us 646 [ - + ]:CBC 128 : Assert(i <= connect_params);
4964 meskes@postgresql.or 647 : 128 : conn_keywords[i] = NULL; /* terminator */
648 : :
649 : 128 : this->connection = PQconnectdbParams(conn_keywords, conn_values, 0);
650 : :
6372 651 [ - + ]: 128 : if (host)
6372 meskes@postgresql.or 652 :UBC 0 : ecpg_free(host);
6372 meskes@postgresql.or 653 [ - + ]:CBC 128 : if (port)
6372 meskes@postgresql.or 654 :UBC 0 : ecpg_free(port);
6372 meskes@postgresql.or 655 [ + + ]:CBC 128 : if (options)
656 : 2 : ecpg_free(options);
657 [ + - ]: 128 : if (dbname)
658 : 128 : ecpg_free(dbname);
4950 659 : 128 : ecpg_free(conn_values);
660 : 128 : ecpg_free(conn_keywords);
661 : :
8210 662 [ + + ]: 128 : if (PQstatus(this->connection) == CONNECTION_BAD)
663 : : {
8069 bruce@momjian.us 664 : 1 : const char *errmsg = PQerrorMessage(this->connection);
6078 peter_e@gmx.net 665 [ + - ]: 1 : const char *db = realname ? realname : ecpg_gettext("<DEFAULT>");
666 : :
667 : : /* PQerrorMessage's result already has a trailing newline */
1688 tgl@sss.pgh.pa.us 668 : 1 : ecpg_log("ECPGconnect: %s", errmsg);
669 : :
7019 meskes@postgresql.or 670 : 1 : ecpg_finish(this);
671 : 1 : pthread_mutex_unlock(&connections_mutex);
672 : :
6548 673 : 1 : ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
8210 674 [ - + ]: 1 : if (realname)
6548 meskes@postgresql.or 675 :UBC 0 : ecpg_free(realname);
676 : :
8210 meskes@postgresql.or 677 :CBC 1 : return false;
678 : : }
679 : :
680 [ + - ]: 127 : if (realname)
6548 681 : 127 : ecpg_free(realname);
682 : :
6372 683 : 127 : pthread_mutex_unlock(&connections_mutex);
684 : :
8210 685 : 127 : this->autocommit = autocommit;
686 : :
282 peter@eisentraut.org 687 : 127 : PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, this);
688 : :
8210 meskes@postgresql.or 689 : 127 : return true;
690 : : }
691 : :
692 : : bool
693 : 128 : ECPGdisconnect(int lineno, const char *connection_name)
694 : : {
8119 bruce@momjian.us 695 : 128 : struct sqlca_t *sqlca = ECPGget_sqlca();
696 : : struct connection *con;
697 : :
3736 meskes@postgresql.or 698 [ - + ]: 128 : if (sqlca == NULL)
699 : : {
3736 meskes@postgresql.or 700 :UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
701 : : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
2942 peter_e@gmx.net 702 : 0 : return false;
703 : : }
704 : :
8119 bruce@momjian.us 705 :CBC 128 : pthread_mutex_lock(&connections_mutex);
706 : :
8210 meskes@postgresql.or 707 [ + + ]: 128 : if (strcmp(connection_name, "ALL") == 0)
708 : : {
6548 709 : 16 : ecpg_init_sqlca(sqlca);
8210 710 [ + + ]: 34 : for (con = all_connections; con;)
711 : : {
712 : 18 : struct connection *f = con;
713 : :
714 : 18 : con = con->next;
715 : 18 : ecpg_finish(f);
716 : : }
717 : : }
718 : : else
719 : : {
8103 720 : 112 : con = ecpg_get_connection_nr(connection_name);
721 : :
6548 722 [ + + ]: 112 : if (!ecpg_init(con, connection_name, lineno))
723 : : {
8069 bruce@momjian.us 724 : 8 : pthread_mutex_unlock(&connections_mutex);
2942 peter_e@gmx.net 725 : 8 : return false;
726 : : }
727 : : else
8069 bruce@momjian.us 728 : 104 : ecpg_finish(con);
729 : : }
730 : :
8119 731 : 120 : pthread_mutex_unlock(&connections_mutex);
732 : :
8210 meskes@postgresql.or 733 : 120 : return true;
734 : : }
735 : :
736 : : PGconn *
5931 bruce@momjian.us 737 :UBC 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 : :
6379 meskes@postgresql.or 745 : 0 : return con->connection;
746 : : }
|