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