/* print out an error message */ void sqlprint(void) { struct sqlca_t *sqlca = ECPGget_sqlca(); sqlca->sqlerrm.sqlerrmc[sqlca->sqlerrm.sqlerrml] = '\0'; fprintf(stderr, ecpg_gettext("SQL error: %s\n"), sqlca->sqlerrm.sqlerrmc); }
void ecpg_raise_backend(int line, PGresult *result, PGconn *conn, int compat) { struct sqlca_t *sqlca = ECPGget_sqlca(); char *sqlstate; char *message; if (result) { sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE); if (sqlstate == NULL) sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR; message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY); } else { sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR; message = PQerrorMessage(conn); } if (strcmp(sqlstate, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR) == 0) { /* we might get here if the connection breaks down, so let's * check for this instead of giving just the generic internal error */ if (PQstatus(conn) == CONNECTION_BAD) { sqlstate = "57P02"; message = ecpg_gettext("the connection to the server was lost"); } } /* copy error message */ snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "%s on line %d", message, line); sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc); /* copy SQLSTATE */ strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate)); /* assign SQLCODE for backward compatibility */ if (strncmp(sqlca->sqlstate, "23505", sizeof(sqlca->sqlstate)) == 0) sqlca->sqlcode = INFORMIX_MODE(compat) ? ECPG_INFORMIX_DUPLICATE_KEY : ECPG_DUPLICATE_KEY; else if (strncmp(sqlca->sqlstate, "21000", sizeof(sqlca->sqlstate)) == 0) sqlca->sqlcode = INFORMIX_MODE(compat) ? ECPG_INFORMIX_SUBSELECT_NOT_ONE : ECPG_SUBSELECT_NOT_ONE; else sqlca->sqlcode = ECPG_PGSQL; /* %.*s is safe here as long as sqlstate is all-ASCII */ ecpg_log("raising sqlstate %.*s (sqlcode %d): %s\n", sizeof(sqlca->sqlstate), sqlca->sqlstate, sqlca->sqlcode, sqlca->sqlerrm.sqlerrmc); /* free all memory we have allocated for the user */ ECPGfree_auto_mem(); }
void ecpg_log(const char *format,...) { va_list ap; struct sqlca_t *sqlca = ECPGget_sqlca(); const char *intl_format; int bufsize; char *fmt; if (!simple_debug) return; /* internationalize the error message string */ intl_format = ecpg_gettext(format); /* * Insert PID into the format, unless ecpg_internal_regression_mode is set * (regression tests want unchanging output). */ bufsize = strlen(intl_format) + 100; fmt = (char *) malloc(bufsize); if (fmt == NULL) return; if (ecpg_internal_regression_mode) snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format); else snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format); #ifdef ENABLE_THREAD_SAFETY pthread_mutex_lock(&debug_mutex); #endif va_start(ap, format); vfprintf(debugstream, fmt, ap); va_end(ap); /* dump out internal sqlca variables */ if (ecpg_internal_regression_mode && sqlca != NULL) { fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n", sqlca->sqlcode, sqlca->sqlstate); } fflush(debugstream); #ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&debug_mutex); #endif free(fmt); }
/* print out an error message */ void sqlprint(void) { struct sqlca_t *sqlca = ECPGget_sqlca(); if (sqlca == NULL) { ecpg_log("out of memory"); return; } sqlca->sqlerrm.sqlerrmc[sqlca->sqlerrm.sqlerrml] = '\0'; fprintf(stderr, ecpg_gettext("SQL error: %s\n"), sqlca->sqlerrm.sqlerrmc); }
static void ECPGnoticeReceiver(void *arg, const PGresult *result) { char *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE); char *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY); struct sqlca_t *sqlca = ECPGget_sqlca(); int sqlcode; if (sqlca == NULL) { ecpg_log("out of memory"); return; } (void) arg; /* keep the compiler quiet */ if (sqlstate == NULL) sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR; if (message == NULL) /* Shouldn't happen, but need to be sure */ message = ecpg_gettext("empty message text"); /* these are not warnings */ if (strncmp(sqlstate, "00", 2) == 0) return; ecpg_log("ECPGnoticeReceiver: %s\n", message); /* map to SQLCODE for backward compatibility */ if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME) == 0) sqlcode = ECPG_WARNING_UNKNOWN_PORTAL; else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION) == 0) sqlcode = ECPG_WARNING_IN_TRANSACTION; else if (strcmp(sqlstate, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION) == 0) sqlcode = ECPG_WARNING_NO_TRANSACTION; else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR) == 0) sqlcode = ECPG_WARNING_PORTAL_EXISTS; else sqlcode = 0; strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate)); sqlca->sqlcode = sqlcode; sqlca->sqlwarn[2] = 'W'; sqlca->sqlwarn[0] = 'W'; strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc)); sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0; sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc); ecpg_log("raising sqlcode %d\n", sqlcode); }
bool ecpg_init(const struct connection * con, const char *connection_name, const int lineno) { struct sqlca_t *sqlca = ECPGget_sqlca(); ecpg_init_sqlca(sqlca); if (con == NULL) { ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST, connection_name ? connection_name : ecpg_gettext("NULL")); return (false); } return (true); }
void ecpg_raise(int line, int code, const char *sqlstate, const char *str) { struct sqlca_t *sqlca = ECPGget_sqlca(); sqlca->sqlcode = code; strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate)); switch (code) { case ECPG_NOT_FOUND: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("no data found on line %d"), line); break; case ECPG_OUT_OF_MEMORY: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("out of memory on line %d"), line); break; case ECPG_UNSUPPORTED: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("unsupported type \"%s\" on line %d"), str, line); break; case ECPG_TOO_MANY_ARGUMENTS: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("too many arguments on line %d"), line); break; case ECPG_TOO_FEW_ARGUMENTS: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("too few arguments on line %d"), line); break; case ECPG_INT_FORMAT: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("invalid input syntax for type int: \"%s\", on line %d"), str, line); break; case ECPG_UINT_FORMAT: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("invalid input syntax for type unsigned int: \"%s\", on line %d"), str, line); break; case ECPG_FLOAT_FORMAT: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("invalid input syntax for floating-point type: \"%s\", on line %d"), str, line); break; case ECPG_CONVERT_BOOL: if (str) snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("invalid syntax for type boolean: \"%s\", on line %d"), str, line); else snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("could not convert boolean value: size mismatch, on line %d"), line); break; case ECPG_EMPTY: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("empty query on line %d"), line); break; case ECPG_MISSING_INDICATOR: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("null value without indicator on line %d"), line); break; case ECPG_NO_ARRAY: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("variable does not have an array type on line %d"), line); break; case ECPG_DATA_NOT_ARRAY: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("data read from server is not an array on line %d"), line); break; case ECPG_ARRAY_INSERT: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("inserting an array of variables is not supported on line %d"), line); break; case ECPG_NO_CONN: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("connection \"%s\" does not exist on line %d"), str, line); break; case ECPG_NOT_CONN: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("not connected to connection \"%s\" on line %d"), str, line); break; case ECPG_INVALID_STMT: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("invalid statement name \"%s\" on line %d"), str, line); break; case ECPG_UNKNOWN_DESCRIPTOR: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("descriptor \"%s\" not found on line %d"), str, line); break; case ECPG_INVALID_DESCRIPTOR_INDEX: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("descriptor index out of range on line %d"), line); break; case ECPG_UNKNOWN_DESCRIPTOR_ITEM: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("unrecognized descriptor item \"%s\" on line %d"), str, line); break; case ECPG_VAR_NOT_NUMERIC: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("variable does not have a numeric type on line %d"), line); break; case ECPG_VAR_NOT_CHAR: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("variable does not have a character type on line %d"), line); break; case ECPG_TRANS: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("error in transaction processing on line %d"), line); break; case ECPG_CONNECT: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("could not connect to database \"%s\" on line %d"), str, line); break; default: snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), /* * translator: this string will be truncated at 149 characters * expanded. */ ecpg_gettext("SQL error %d on line %d"), code, line); break; } sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc); ecpg_log("raising sqlcode %d on line %d: %s\n", code, line, sqlca->sqlerrm.sqlerrmc); /* free all memory we have allocated for the user */ ECPGfree_auto_mem(); }
/* this contains some quick hacks, needs to be cleaned up, but it works */ bool ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit) { struct sqlca_t *sqlca = ECPGget_sqlca(); enum COMPAT_MODE compat = c; struct connection *this; int i; char *dbname = name ? ecpg_strdup(name, lineno) : NULL, *host = NULL, *tmp, *port = NULL, *realname = NULL, *options = NULL, *connect_string = NULL; ecpg_init_sqlca(sqlca); /* * clear auto_mem structure because some error handling functions might * access it */ ecpg_clear_auto_mem(); if (INFORMIX_MODE(compat)) { char *envname; /* * Informix uses an environment variable DBPATH that overrides the * connection parameters given here. We do the same with PG_DBPATH as * the syntax is different. */ envname = getenv("PG_DBPATH"); if (envname) { ecpg_free(dbname); dbname = ecpg_strdup(envname, lineno); } } if (dbname == NULL && connection_name == NULL) connection_name = "DEFAULT"; #if ENABLE_THREAD_SAFETY ecpg_pthreads_init(); #endif /* check if the identifier is unique */ if (ecpg_get_connection(connection_name)) { ecpg_free(dbname); ecpg_log("ECPGconnect: connection identifier %s is already in use\n", connection_name); return false; } if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL) return false; if (dbname != NULL) { /* get the detail information out of dbname */ if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0) { int offset = 0; /* * only allow protocols tcp and unix */ if (strncmp(dbname, "tcp:", 4) == 0) offset = 4; else if (strncmp(dbname, "unix:", 5) == 0) offset = 5; if (strncmp(dbname + offset, "postgresql://", strlen("postgresql://")) == 0) { /*------ * new style: * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:] * [/db name][?options] *------ */ offset += strlen("postgresql://"); tmp = strrchr(dbname + offset, '?'); if (tmp != NULL) /* options given */ { options = ecpg_strdup(tmp + 1, lineno); *tmp = '\0'; } tmp = last_dir_separator(dbname + offset); if (tmp != NULL) /* database name given */ { if (tmp[1] != '\0') /* non-empty database name */ realname = ecpg_strdup(tmp + 1, lineno); *tmp = '\0'; } tmp = strrchr(dbname + offset, ':'); if (tmp != NULL) /* port number or Unix socket path given */ { char *tmp2; *tmp = '\0'; if ((tmp2 = strchr(tmp + 1, ':')) != NULL) { *tmp2 = '\0'; host = ecpg_strdup(tmp + 1, lineno); if (strncmp(dbname, "unix:", 5) != 0) { ecpg_log("ECPGconnect: socketname %s given for TCP connection on line %d\n", host, lineno); ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>")); if (host) ecpg_free(host); /* * port not set yet if (port) ecpg_free(port); */ if (options) ecpg_free(options); if (realname) ecpg_free(realname); if (dbname) ecpg_free(dbname); free(this); return false; } } else port = ecpg_strdup(tmp + 1, lineno); } if (strncmp(dbname, "unix:", 5) == 0) { if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0) { ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno); ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>")); if (host) ecpg_free(host); if (port) ecpg_free(port); if (options) ecpg_free(options); if (realname) ecpg_free(realname); if (dbname) ecpg_free(dbname); free(this); return false; } } else host = ecpg_strdup(dbname + offset, lineno); } } else { /* old style: dbname[@server][:port] */ tmp = strrchr(dbname, ':'); if (tmp != NULL) /* port number given */ { port = ecpg_strdup(tmp + 1, lineno); *tmp = '\0'; } tmp = strrchr(dbname, '@'); if (tmp != NULL) /* host name given */ { host = ecpg_strdup(tmp + 1, lineno); *tmp = '\0'; } realname = (strlen(dbname) > 0) ? ecpg_strdup(dbname, lineno) : NULL; } } else realname = NULL; /* add connection to our list */ #ifdef ENABLE_THREAD_SAFETY pthread_mutex_lock(&connections_mutex); #endif if (connection_name != NULL) this->name = ecpg_strdup(connection_name, lineno); else this->name = ecpg_strdup(realname, lineno); this->cache_head = NULL; this->prep_stmts = NULL; if (all_connections == NULL) this->next = NULL; else this->next = all_connections; all_connections = this; #ifdef ENABLE_THREAD_SAFETY pthread_setspecific(actual_connection_key, all_connections); #endif actual_connection = all_connections; ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n", realname ? realname : "<DEFAULT>", host ? host : "<DEFAULT>", port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>", options ? "with options " : "", options ? options : "", (user && strlen(user) > 0) ? "for user " : "", user ? user : ""); connect_string = ecpg_alloc(strlen_or_null(host) + strlen_or_null(port) + strlen_or_null(options) + strlen_or_null(realname) + strlen_or_null(user) + strlen_or_null(passwd) + sizeof(" host = port = dbname = user = password ="******"%s%s %s%s %s%s %s%s %s%s %s", realname ? "dbname=" : "", realname ? realname : "", host ? "host=" : "", host ? host : "", port ? "port=" : "", port ? port : "", (user && strlen(user) > 0) ? "user="******"", user ? user : "", (passwd && strlen(passwd) > 0) ? "password="******"", passwd ? passwd : "", options ? options : ""); /* * this is deprecated this->connection = PQsetdbLogin(host, port, options, * NULL, realname, user, passwd); */ this->connection = PQconnectdb(connect_string); ecpg_free(connect_string); if (host) ecpg_free(host); if (port) ecpg_free(port); if (options) ecpg_free(options); if (dbname) ecpg_free(dbname); if (PQstatus(this->connection) == CONNECTION_BAD) { const char *errmsg = PQerrorMessage(this->connection); const char *db = realname ? realname : ecpg_gettext("<DEFAULT>"); ecpg_log("ECPGconnect: could not open database: %s\n", errmsg); ecpg_finish(this); #ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); #endif ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db); if (realname) ecpg_free(realname); return false; } if (realname) ecpg_free(realname); #ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); #endif this->autocommit = autocommit; PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, (void *) this); return true; }
/* this contains some quick hacks, needs to be cleaned up, but it works */ bool ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit) { struct sqlca_t *sqlca = ECPGget_sqlca(); enum COMPAT_MODE compat = c; struct connection *this; int i, connect_params = 0; char *dbname = name ? ecpg_strdup(name, lineno) : NULL, *host = NULL, *tmp, *port = NULL, *realname = NULL, *options = NULL; const char **conn_keywords; const char **conn_values; ecpg_init_sqlca(sqlca); /* * clear auto_mem structure because some error handling functions might * access it */ ecpg_clear_auto_mem(); if (INFORMIX_MODE(compat)) { char *envname; /* * Informix uses an environment variable DBPATH that overrides the * connection parameters given here. We do the same with PG_DBPATH as * the syntax is different. */ envname = getenv("PG_DBPATH"); if (envname) { ecpg_free(dbname); dbname = ecpg_strdup(envname, lineno); } } if (dbname == NULL && connection_name == NULL) connection_name = "DEFAULT"; #if ENABLE_THREAD_SAFETY ecpg_pthreads_init(); #endif /* check if the identifier is unique */ if (ecpg_get_connection(connection_name)) { ecpg_free(dbname); ecpg_log("ECPGconnect: connection identifier %s is already in use\n", connection_name); return false; } if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL) return false; if (dbname != NULL) { /* get the detail information from dbname */ if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0) { int offset = 0; /* * only allow protocols tcp and unix */ if (strncmp(dbname, "tcp:", 4) == 0) offset = 4; else if (strncmp(dbname, "unix:", 5) == 0) offset = 5; if (strncmp(dbname + offset, "postgresql://", strlen("postgresql://")) == 0) { /*------ * new style: * <tcp|unix>:postgresql://server[:port|:/unixsocket/path:] * [/db-name][?options] *------ */ offset += strlen("postgresql://"); tmp = strrchr(dbname + offset, '?'); if (tmp != NULL) /* options given */ { options = ecpg_strdup(tmp + 1, lineno); *tmp = '\0'; } tmp = last_dir_separator(dbname + offset); if (tmp != NULL) /* database name given */ { if (tmp[1] != '\0') /* non-empty database name */ { realname = ecpg_strdup(tmp + 1, lineno); connect_params++; } *tmp = '\0'; } tmp = strrchr(dbname + offset, ':'); if (tmp != NULL) /* port number or Unix socket path given */ { char *tmp2; *tmp = '\0'; if ((tmp2 = strchr(tmp + 1, ':')) != NULL) { *tmp2 = '\0'; host = ecpg_strdup(tmp + 1, lineno); connect_params++; if (strncmp(dbname, "unix:", 5) != 0) { ecpg_log("ECPGconnect: socketname %s given for TCP connection on line %d\n", host, lineno); ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>")); if (host) ecpg_free(host); /* * port not set yet if (port) ecpg_free(port); */ if (options) ecpg_free(options); if (realname) ecpg_free(realname); if (dbname) ecpg_free(dbname); free(this); return false; } } else { port = ecpg_strdup(tmp + 1, lineno); connect_params++; } } if (strncmp(dbname, "unix:", 5) == 0) { if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0) { ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno); ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>")); if (host) ecpg_free(host); if (port) ecpg_free(port); if (options) ecpg_free(options); if (realname) ecpg_free(realname); if (dbname) ecpg_free(dbname); free(this); return false; } } else { if (*(dbname + offset) != '\0') { host = ecpg_strdup(dbname + offset, lineno); connect_params++; } } } } else { /* old style: dbname[@server][:port] */ tmp = strrchr(dbname, ':'); if (tmp != NULL) /* port number given */ { port = ecpg_strdup(tmp + 1, lineno); connect_params++; *tmp = '\0'; } tmp = strrchr(dbname, '@'); if (tmp != NULL) /* host name given */ { host = ecpg_strdup(tmp + 1, lineno); connect_params++; *tmp = '\0'; } if (strlen(dbname) > 0) { realname = ecpg_strdup(dbname, lineno); connect_params++; } else realname = NULL; } } else realname = NULL; /* add connection to our list */ #ifdef ENABLE_THREAD_SAFETY pthread_mutex_lock(&connections_mutex); #endif if (connection_name != NULL) this->name = ecpg_strdup(connection_name, lineno); else this->name = ecpg_strdup(realname, lineno); this->cache_head = NULL; this->prep_stmts = NULL; if (all_connections == NULL) this->next = NULL; else this->next = all_connections; all_connections = this; #ifdef ENABLE_THREAD_SAFETY pthread_setspecific(actual_connection_key, all_connections); #endif actual_connection = all_connections; ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n", realname ? realname : "<DEFAULT>", host ? host : "<DEFAULT>", port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>", options ? "with options " : "", options ? options : "", (user && strlen(user) > 0) ? "for user " : "", user ? user : ""); if (options) for (i = 0; options[i]; i++) /* count options */ if (options[i] == '=') connect_params++; if (user && strlen(user) > 0) connect_params++; if (passwd && strlen(passwd) > 0) connect_params++; /* allocate enough space for all connection parameters */ conn_keywords = (const char **) ecpg_alloc((connect_params + 1) * sizeof(char *), lineno); conn_values = (const char **) ecpg_alloc(connect_params * sizeof(char *), lineno); if (conn_keywords == NULL || conn_values == NULL) { if (host) ecpg_free(host); if (port) ecpg_free(port); if (options) ecpg_free(options); if (realname) ecpg_free(realname); if (dbname) ecpg_free(dbname); if (conn_keywords) ecpg_free(conn_keywords); if (conn_values) ecpg_free(conn_values); free(this); return false; } i = 0; if (realname) { conn_keywords[i] = "dbname"; conn_values[i] = realname; i++; } if (host) { conn_keywords[i] = "host"; conn_values[i] = host; i++; } if (port) { conn_keywords[i] = "port"; conn_values[i] = port; i++; } if (user && strlen(user) > 0) { conn_keywords[i] = "user"; conn_values[i] = user; i++; } if (passwd && strlen(passwd) > 0) { conn_keywords[i] = "password"; conn_values[i] = passwd; i++; } if (options) { char *str; /* options look like this "option1 = value1 option2 = value2 ... */ /* we have to break up the string into single options */ for (str = options; *str;) { int e, a; char *token1, *token2; for (token1 = str; *token1 && *token1 == ' '; token1++); for (e = 0; token1[e] && token1[e] != '='; e++); if (token1[e]) /* found "=" */ { token1[e] = '\0'; for (token2 = token1 + e + 1; *token2 && *token2 == ' '; token2++); for (a = 0; token2[a] && token2[a] != '&'; a++); if (token2[a]) /* found "&" => another option follows */ { token2[a] = '\0'; str = token2 + a + 1; } else str = token2 + a; conn_keywords[i] = token1; conn_values[i] = token2; i++; } else /* the parser should not be able to create this invalid option */ str = token1 + e; } } conn_keywords[i] = NULL; /* terminator */ this->connection = PQconnectdbParams(conn_keywords, conn_values, 0); if (host) ecpg_free(host); if (port) ecpg_free(port); if (options) ecpg_free(options); if (dbname) ecpg_free(dbname); ecpg_free(conn_values); ecpg_free(conn_keywords); if (PQstatus(this->connection) == CONNECTION_BAD) { const char *errmsg = PQerrorMessage(this->connection); const char *db = realname ? realname : ecpg_gettext("<DEFAULT>"); ecpg_log("ECPGconnect: could not open database: %s\n", errmsg); ecpg_finish(this); #ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); #endif ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db); if (realname) ecpg_free(realname); return false; } if (realname) ecpg_free(realname); #ifdef ENABLE_THREAD_SAFETY pthread_mutex_unlock(&connections_mutex); #endif this->autocommit = autocommit; PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, (void *) this); return true; }