diff options
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 197 |
1 files changed, 123 insertions, 74 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 4f94b7b0a1d..81973e34f63 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.122 2000/02/24 15:53:12 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.123 2000/03/11 03:08:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -76,35 +76,25 @@ struct pg_setenv_state } state; PGconn *conn; PGresult *res; - struct EnvironmentOptions *eo; + const struct EnvironmentOptions *eo; } ; -static int connectDBStart(PGconn *conn); -static int connectDBComplete(PGconn *conn); - #ifdef USE_SSL static SSL_CTX *SSL_context = NULL; #endif -static PGconn *makeEmptyPGconn(void); -static void freePGconn(PGconn *conn); -static void closePGconn(PGconn *conn); -static int conninfo_parse(const char *conninfo, PQExpBuffer errorMessage); -static char *conninfo_getval(char *keyword); -static void conninfo_free(void); -static void defaultNoticeProcessor(void *arg, const char *message); - #define NOTIFYLIST_INITIAL_SIZE 10 #define NOTIFYLIST_GROWBY 10 /* ---------- * Definition of the conninfo parameters and their fallback resources. + * * If Environment-Var and Compiled-in are specified as NULL, no * fallback is available. If after all no value can be determined * for an option, an error is returned. * - * The values for dbname and user are treated special in conninfo_parse. + * The values for dbname and user are treated specially in conninfo_parse. * If the Compiled-in resource is specified as a NULL value, the * user is determined by fe_getauthname() and for dbname the user * name is copied. @@ -112,23 +102,30 @@ static void defaultNoticeProcessor(void *arg, const char *message); * The Label and Disp-Char entries are provided for applications that * want to use PQconndefaults() to create a generic database connection * dialog. Disp-Char is defined as follows: - * "" Normal input field + * "" Normal input field + * "*" Password field - hide value + * "D" Debug option - don't show by default + * + * PQconninfoOptions[] is a constant static array that we use to initialize + * a dynamically allocated working copy. All the "val" fields in + * PQconninfoOptions[] *must* be NULL. In a working copy, non-null "val" + * fields point to malloc'd strings that should be freed when the working + * array is freed (see PQconninfoFree). * ---------- */ -static PQconninfoOption PQconninfoOptions[] = { -/* ----------------------------------------------------------------- */ -/* Option-name Environment-Var Compiled-in Current value */ -/* Label Disp-Char */ -/* ----------------- --------------- --------------- --------------- */ - /* "authtype" is ignored as it is no longer used. */ +static const PQconninfoOption PQconninfoOptions[] = { + /* "authtype" is no longer used, so mark it "don't show". We keep it + * in the array so as not to reject conninfo strings from old apps that + * might still try to set it. + */ {"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL, - "Database-Authtype", "", 20}, + "Database-Authtype", "D", 20}, {"user", "PGUSER", NULL, NULL, "Database-User", "", 20}, {"password", "PGPASSWORD", DefaultPassword, NULL, - "Database-Password", "", 20}, + "Database-Password", "*", 20}, {"dbname", "PGDATABASE", NULL, NULL, "Database-Name", "", 20}, @@ -147,12 +144,13 @@ static PQconninfoOption PQconninfoOptions[] = { {"options", "PGOPTIONS", DefaultOption, NULL, "Backend-Debug-Options", "D", 40}, -/* ----------------- --------------- --------------- --------------- */ + + /* Terminating entry --- MUST BE LAST */ {NULL, NULL, NULL, NULL, NULL, NULL, 0} }; -static struct EnvironmentOptions +static const struct EnvironmentOptions { const char *envName, *pgName; @@ -181,6 +179,18 @@ static struct EnvironmentOptions }; +static int connectDBStart(PGconn *conn); +static int connectDBComplete(PGconn *conn); +static PGconn *makeEmptyPGconn(void); +static void freePGconn(PGconn *conn); +static void closePGconn(PGconn *conn); +static PQconninfoOption *conninfo_parse(const char *conninfo, + PQExpBuffer errorMessage); +static char *conninfo_getval(PQconninfoOption *connOptions, + const char *keyword); +static void defaultNoticeProcessor(void *arg, const char *message); + + /* ---------------- * Connecting to a Database * @@ -262,6 +272,7 @@ PGconn * PQconnectStart(const char *conninfo) { PGconn *conn; + PQconninfoOption *connOptions; char *tmp; /* ---------- @@ -274,37 +285,42 @@ PQconnectStart(const char *conninfo) return (PGconn *) NULL; /* ---------- - * Parse the conninfo string and save settings in conn structure + * Parse the conninfo string * ---------- */ - if (conninfo_parse(conninfo, &conn->errorMessage) < 0) + connOptions = conninfo_parse(conninfo, &conn->errorMessage); + if (connOptions == NULL) { conn->status = CONNECTION_BAD; - conninfo_free(); + /* errorMessage is already set */ return conn; } - tmp = conninfo_getval("hostaddr"); + + /* + * Move option values into conn structure + */ + tmp = conninfo_getval(connOptions, "hostaddr"); conn->pghostaddr = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval("host"); + tmp = conninfo_getval(connOptions, "host"); conn->pghost = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval("port"); + tmp = conninfo_getval(connOptions, "port"); conn->pgport = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval("tty"); + tmp = conninfo_getval(connOptions, "tty"); conn->pgtty = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval("options"); + tmp = conninfo_getval(connOptions, "options"); conn->pgoptions = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval("dbname"); + tmp = conninfo_getval(connOptions, "dbname"); conn->dbName = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval("user"); + tmp = conninfo_getval(connOptions, "user"); conn->pguser = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval("password"); + tmp = conninfo_getval(connOptions, "password"); conn->pgpass = tmp ? strdup(tmp) : NULL; /* ---------- - * Free the connection info - all is in conn now + * Free the option info - all is in conn now * ---------- */ - conninfo_free(); + PQconninfoFree(connOptions); /* ---------- * Connect to the database @@ -323,20 +339,28 @@ PQconnectStart(const char *conninfo) * PQconndefaults * * Parse an empty string like PQconnectdb() would do and return the - * address of the connection options structure. Using this function - * an application might determine all possible options and their - * current default values. + * working connection options array. + * + * Using this function, an application may determine all possible options + * and their current default values. + * + * NOTE: as of PostgreSQL 7.0, the returned array is dynamically allocated + * and should be freed when no longer needed via PQconninfoFree(). (In prior + * versions, the returned array was static, but that's not thread-safe.) + * Pre-7.0 applications that use this function will see a small memory leak + * until they are updated to call PQconninfoFree. * ---------------- */ PQconninfoOption * PQconndefaults(void) { PQExpBufferData errorBuf; + PQconninfoOption *connOptions; initPQExpBuffer(&errorBuf); - conninfo_parse("", &errorBuf); + connOptions = conninfo_parse("", &errorBuf); termPQExpBuffer(&errorBuf); - return PQconninfoOptions; + return connOptions; } /* ---------------- @@ -565,7 +589,7 @@ update_db_info(PGconn *conn) { printfPQExpBuffer(&conn->errorMessage, "connectDBStart() -- " - "non-tcp access only possible on " + "non-TCP access only possible on " "localhost\n"); return 1; } @@ -2037,9 +2061,13 @@ pqPacketSend(PGconn *conn, const char *buf, size_t len) /* ---------------- * Conninfo parser routine + * + * If successful, a malloc'd PQconninfoOption array is returned. + * If not successful, NULL is returned and an error message is + * left in errorMessage. * ---------------- */ -static int +static PQconninfoOption * conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) { char *pname; @@ -2048,16 +2076,27 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) char *tmp; char *cp; char *cp2; + PQconninfoOption *options; PQconninfoOption *option; char errortmp[INITIAL_EXPBUFFER_SIZE]; - conninfo_free(); + /* Make a working copy of PQconninfoOptions */ + options = malloc(sizeof(PQconninfoOptions)); + if (options == NULL) + { + printfPQExpBuffer(errorMessage, + "FATAL: cannot allocate memory for copy of PQconninfoOptions\n"); + return NULL; + } + memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions)); + /* Need a modifiable copy of the input string */ if ((buf = strdup(conninfo)) == NULL) { printfPQExpBuffer(errorMessage, "FATAL: cannot allocate memory for copy of conninfo string\n"); - return -1; + PQconninfoFree(options); + return NULL; } cp = buf; @@ -2094,10 +2133,11 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) if (*cp != '=') { printfPQExpBuffer(errorMessage, - "ERROR: PQconnectdb() - Missing '=' after '%s' in conninfo\n", + "ERROR: Missing '=' after '%s' in conninfo\n", pname); + PQconninfoFree(options); free(buf); - return -1; + return NULL; } *cp++ = '\0'; @@ -2109,6 +2149,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) cp++; } + /* Get the parameter value */ pval = cp; if (*cp != '\'') @@ -2142,8 +2183,9 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) { printfPQExpBuffer(errorMessage, "ERROR: PQconnectdb() - unterminated quoted string in conninfo\n"); + PQconninfoFree(options); free(buf); - return -1; + return NULL; } if (*cp == '\\') { @@ -2167,27 +2209,31 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) * for the param record. * ---------- */ - for (option = PQconninfoOptions; option->keyword != NULL; option++) + for (option = options; option->keyword != NULL; option++) { - if (!strcmp(option->keyword, pname)) + if (strcmp(option->keyword, pname) == 0) break; } if (option->keyword == NULL) { printfPQExpBuffer(errorMessage, - "ERROR: PQconnectdb() - unknown option '%s'\n", + "ERROR: Unknown conninfo option '%s'\n", pname); + PQconninfoFree(options); free(buf); - return -1; + return NULL; } /* ---------- * Store the value * ---------- */ + if (option->val) + free(option->val); option->val = strdup(pval); } + /* Done with the modifiable input string */ free(buf); /* ---------- @@ -2195,7 +2241,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) * in the conninfo string. * ---------- */ - for (option = PQconninfoOptions; option->keyword != NULL; option++) + for (option = options; option->keyword != NULL; option++) { if (option->val != NULL) continue; /* Value was in conninfo */ @@ -2228,7 +2274,7 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) * Special handling for user * ---------- */ - if (!strcmp(option->keyword, "user")) + if (strcmp(option->keyword, "user") == 0) { option->val = fe_getauthname(errortmp); /* note any error message is thrown away */ @@ -2239,27 +2285,28 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) * Special handling for dbname * ---------- */ - if (!strcmp(option->keyword, "dbname")) + if (strcmp(option->keyword, "dbname") == 0) { - tmp = conninfo_getval("user"); + tmp = conninfo_getval(options, "user"); if (tmp) option->val = strdup(tmp); continue; } } - return 0; + return options; } static char * -conninfo_getval(char *keyword) +conninfo_getval(PQconninfoOption *connOptions, + const char *keyword) { PQconninfoOption *option; - for (option = PQconninfoOptions; option->keyword != NULL; option++) + for (option = connOptions; option->keyword != NULL; option++) { - if (!strcmp(option->keyword, keyword)) + if (strcmp(option->keyword, keyword) == 0) return option->val; } @@ -2267,19 +2314,20 @@ conninfo_getval(char *keyword) } -static void -conninfo_free() +void +PQconninfoFree(PQconninfoOption *connOptions) { PQconninfoOption *option; - for (option = PQconninfoOptions; option->keyword != NULL; option++) + if (connOptions == NULL) + return; + + for (option = connOptions; option->keyword != NULL; option++) { if (option->val != NULL) - { free(option->val); - option->val = NULL; - } } + free(connOptions); } /* =========== accessor functions for PGconn ========= */ @@ -2350,10 +2398,9 @@ PQstatus(const PGconn *conn) char * PQerrorMessage(const PGconn *conn) { - static char noConn[] = "PQerrorMessage: conn pointer is NULL\n"; - if (!conn) - return noConn; + return "PQerrorMessage: conn pointer is NULL\n"; + return conn->errorMessage.data; } @@ -2452,13 +2499,15 @@ PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg) { PQnoticeProcessor old; + if (conn == NULL) return NULL; old = conn->noticeHook; - if (proc) { - conn->noticeHook = proc; - conn->noticeArg = arg; + if (proc) + { + conn->noticeHook = proc; + conn->noticeArg = arg; } return old; } |