1/* src/interfaces/ecpg/ecpglib/connect.c */
3 #define POSTGRES_ECPG_INTERNAL
40 if ((connection_name == NULL) || (strcmp(connection_name,
"CURRENT") == 0))
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
52 /* no TSD connection, going for global */
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.
66 if (con->
name != NULL && strcmp(connection_name, con->
name) == 0)
80 if ((connection_name == NULL) || (strcmp(connection_name,
"CURRENT") == 0))
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
92 /* no TSD connection here either, using global */
119 * no need to lock connections_mutex - we're always called by
120 * ECPGdisconnect or ECPGconnect, which are holding the lock
123 /* remove act from the list */
140 ecpg_log(
"ecpg_finish: connection %s closed\n", act->
name ? act->
name :
"(null)");
145 /* delete cursor variables when last connection gets closed */
154 ecpg_log(
"ecpg_finish: called an extra time\n");
163 if (!
ecpg_init(con, connection_name, lineno))
166 ecpg_log(
"ECPGsetcommit on line %d: action \"%s\"; connection \"%s\"\n", lineno,
mode, con->
name);
179 else if (!con->
autocommit && strncmp(
mode,
"on", strlen(
"on")) == 0)
199 if (!
ecpg_init(con, connection_name, lineno))
221 (void)
arg;
/* keep the compiler quiet */
225 if (message == NULL)
/* Shouldn't happen, but need to be sure */
228 /* these are not warnings */
229 if (strncmp(
sqlstate,
"00", 2) == 0)
232 ecpg_log(
"ECPGnoticeReceiver: %s\n", message);
234 /* map to SQLCODE for backward compatibility */
248 sqlca->sqlwarn[2] =
'W';
249 sqlca->sqlwarn[0] =
'W';
251 strncpy(
sqlca->sqlerrm.sqlerrmc, message,
sizeof(
sqlca->sqlerrm.sqlerrmc));
252 sqlca->sqlerrm.sqlerrmc[
sizeof(
sqlca->sqlerrm.sqlerrmc) - 1] = 0;
253 sqlca->sqlerrm.sqlerrml = strlen(
sqlca->sqlerrm.sqlerrmc);
258/* this contains some quick hacks, needs to be cleaned up, but it works */
267 bool alloc_failed = (
sqlca == NULL);
274 const char **conn_keywords;
275 const char **conn_values;
289 * clear auto_mem structure because some error handling functions might
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.
303 envname = getenv(
"PG_DBPATH");
311 if (
dbname == NULL && connection_name == NULL)
312 connection_name =
"DEFAULT";
316 /* check if the identifier is unique */
320 ecpg_log(
"ECPGconnect: connection identifier %s is already in use\n",
333 /* get the detail information from dbname */
334 if (strncmp(
dbname,
"tcp:", 4) == 0 || strncmp(
dbname,
"unix:", 5) == 0)
339 * only allow protocols tcp and unix
341 if (strncmp(
dbname,
"tcp:", 4) == 0)
343 else if (strncmp(
dbname,
"unix:", 5) == 0)
346 if (strncmp(
dbname + offset,
"postgresql://", strlen(
"postgresql://")) == 0)
351 * <tcp|unix>:postgresql://server[:port][/db-name][?options]
354 offset += strlen(
"postgresql://");
356 tmp = strrchr(
dbname + offset,
'?');
357 if (tmp != NULL)
/* options given */
364 if (tmp != NULL)
/* database name given */
366 if (tmp[1] !=
'0円')
/* non-empty database name */
368 realname =
ecpg_strdup(tmp + 1, lineno, &alloc_failed);
374 tmp = strrchr(
dbname + offset,
':');
375 if (tmp != NULL)
/* port number given */
382 if (strncmp(
dbname,
"unix:", 5) == 0)
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.
389 if (strcmp(
dbname + offset,
"localhost") != 0 &&
390 strcmp(
dbname + offset,
"127.0.0.1") != 0)
392 ecpg_log(
"ECPGconnect: non-localhost access via sockets on line %d\n", lineno);
410 if (*(
dbname + offset) !=
'0円')
420 /* old style: dbname[@server][:port] */
421 tmp = strrchr(
dbname,
':');
422 if (tmp != NULL)
/* port number given */
429 tmp = strrchr(
dbname,
'@');
430 if (tmp != NULL)
/* host name given */
432 host =
ecpg_strdup(tmp + 1, lineno, &alloc_failed);
450 * Count options for the allocation done below (this may produce an
451 * overestimate, it's ok).
460 if (passwd && strlen(passwd) > 0)
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.
468 conn_keywords = (
const char **)
ecpg_alloc((connect_params + 1) *
sizeof(
char *), lineno);
469 conn_values = (
const char **)
ecpg_alloc(connect_params *
sizeof(
char *), lineno);
471 /* Decide on a connection name */
472 if (connection_name != NULL || realname != NULL)
474 this->name =
ecpg_strdup(connection_name ? connection_name : realname,
475 lineno, &alloc_failed);
480 /* Deal with any failed allocations above */
481 if (conn_keywords == NULL || conn_values == NULL || alloc_failed)
503 /* add connection to our list */
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.
513 ecpg_clocale = newlocale(LC_NUMERIC_MASK,
"C", (
locale_t) 0);
549 all_connections =
this;
553 ecpg_log(
"ECPGconnect: opening database %s on %s port %s %s%s %s%s\n",
554 realname ? realname :
"<DEFAULT>",
555 host ? host :
"<DEFAULT>",
563 conn_keywords[
i] =
"dbname";
564 conn_values[
i] = realname;
569 conn_keywords[
i] =
"host";
570 conn_values[
i] = host;
575 conn_keywords[
i] =
"port";
576 conn_values[
i] =
port;
581 conn_keywords[
i] =
"user";
582 conn_values[
i] =
user;
585 if (passwd && strlen(passwd) > 0)
587 conn_keywords[
i] =
"password";
588 conn_values[
i] = passwd;
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.)
611 /* Skip spaces before keyword */
612 for (token1 =
str; *token1 ==
' '; token1++)
614 /* Find end of keyword */
615 for (
e = 0; token1[
e] && token1[
e] !=
'=';
e++)
617 if (token1[
e])
/* found "=" */
620 /* Skip spaces before value */
621 for (token2 = token1 +
e + 1; *token2 ==
' '; token2++)
623 /* Find end of value */
624 for (
a = 0; token2[
a] && token2[
a] !=
'&';
a++)
626 if (token2[
a])
/* found "&" => another option follows */
629 str = token2 +
a + 1;
634 conn_keywords[
i] = token1;
635 conn_values[
i] = token2;
640 /* Bogus options syntax ... ignore trailing garbage */
647 conn_keywords[
i] = NULL;
/* terminator */
665 const char *db = realname ? realname :
ecpg_gettext(
"<DEFAULT>");
667 /* PQerrorMessage's result already has a trailing newline */
707 if (strcmp(connection_name,
"ALL") == 0)
722 if (!
ecpg_init(con, connection_name, lineno))
static struct connection * ecpg_get_connection_nr(const char *connection_name)
static void ecpg_finish(struct connection *act)
static pthread_mutex_t connections_mutex
void ecpg_pthreads_init(void)
static pthread_key_t actual_connection_key
static struct connection * all_connections
PGconn * ECPGget_PGconn(const char *connection_name)
bool ECPGsetconn(int lineno, const char *connection_name)
bool ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
bool ECPGdisconnect(int lineno, const char *connection_name)
static void ECPGnoticeReceiver(void *arg, const PGresult *result)
static pthread_once_t actual_connection_key_once
static struct connection * actual_connection
bool ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
struct connection * ecpg_get_connection(const char *connection_name)
static void ecpg_actual_connection_init(void)
#define ECPG_WARNING_IN_TRANSACTION
#define ECPG_WARNING_UNKNOWN_PORTAL
#define ECPG_WARNING_PORTAL_EXISTS
#define ECPG_WARNING_NO_TRANSACTION
#define ECPG_OUT_OF_MEMORY
#define ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION
bool ecpg_check_PQresult(PGresult *results, int lineno, PGconn *connection, enum COMPAT_MODE compat)
bool ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
#define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY
char * ecpg_strdup(const char *string, int lineno, bool *alloc_failed)
char * ecpg_alloc(long size, int lineno)
#define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR
#define ECPG_SQLSTATE_INVALID_CURSOR_NAME
void ecpg_log(const char *format,...) pg_attribute_printf(1
void ecpg_clear_auto_mem(void)
bool ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
#define ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION
#define ECPG_SQLSTATE_DUPLICATE_CURSOR
void ecpg_init_sqlca(struct sqlca_t *sqlca)
#define ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION
void ecpg_raise(int line, int code, const char *sqlstate, const char *str)
bool ecpg_internal_regression_mode
void ecpg_free(void *ptr)
int errmsg(const char *fmt,...)
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
ConnStatusType PQstatus(const PGconn *conn)
void PQfinish(PGconn *conn)
PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg)
char * PQerrorMessage(const PGconn *conn)
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
PGresult * PQexec(PGconn *conn, const char *query)
Assert(PointerIsAligned(start, uint64))
struct sqlca_t * ECPGget_sqlca(void)
#define PQresultErrorField
static PgChecksumMode mode
char * last_dir_separator(const char *filename)
#define PG_DIAG_MESSAGE_PRIMARY
int pthread_mutex_unlock(pthread_mutex_t *mp)
int pthread_mutex_lock(pthread_mutex_t *mp)
void pthread_setspecific(pthread_key_t key, void *val)
void * pthread_getspecific(pthread_key_t key)
#define PTHREAD_MUTEX_INITIALIZER
struct ECPGtype_information_cache * cache_head
struct prepared_statement * prep_stmts