diff --git a/src/interfaces/libpgtcl/pgtclCmds.c b/src/interfaces/libpgtcl/pgtclCmds.c index 9ed84c11d6..10aa2f01bc 100644 --- a/src/interfaces/libpgtcl/pgtclCmds.c +++ b/src/interfaces/libpgtcl/pgtclCmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.47 2000/02/27 07:44:22 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.48 2000/03/11 03:08:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -237,25 +237,32 @@ tcl_value(char *value) int Pg_conndefaults(ClientData cData, Tcl_Interp *interp, int argc, char **argv) { + PQconninfoOption *options = PQconndefaults(); PQconninfoOption *option; Tcl_DString result; char ibuf[32]; - Tcl_DStringInit(&result); - for (option = PQconndefaults(); option->keyword != NULL; option++) + if (options) { - char *val = option->val ? option->val : ""; + Tcl_DStringInit(&result); - sprintf(ibuf, "%d", option->dispsize); - Tcl_DStringStartSublist(&result); - Tcl_DStringAppendElement(&result, option->keyword); - Tcl_DStringAppendElement(&result, option->label); - Tcl_DStringAppendElement(&result, option->dispchar); - Tcl_DStringAppendElement(&result, ibuf); - Tcl_DStringAppendElement(&result, val); - Tcl_DStringEndSublist(&result); + for (option = options; option->keyword != NULL; option++) + { + char *val = option->val ? option->val : ""; + + sprintf(ibuf, "%d", option->dispsize); + Tcl_DStringStartSublist(&result); + Tcl_DStringAppendElement(&result, option->keyword); + Tcl_DStringAppendElement(&result, option->label); + Tcl_DStringAppendElement(&result, option->dispchar); + Tcl_DStringAppendElement(&result, ibuf); + Tcl_DStringAppendElement(&result, val); + Tcl_DStringEndSublist(&result); + } + Tcl_DStringResult(interp, &result); + + PQconninfoFree(options); } - Tcl_DStringResult(interp, &result); return TCL_OK; } diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 7a3bff45e9..fe870963df 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -10,7 +10,7 @@ * exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes). * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.37 2000/02/07 23:10:08 petere Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.38 2000/03/11 03:08:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -75,7 +75,7 @@ struct authsvc * allowed. Unauthenticated connections are disallowed unless there * isn't any authentication system. */ -static struct authsvc authsvcs[] = { +static const struct authsvc authsvcs[] = { #ifdef KRB4 {"krb4", STARTUP_KRB4_MSG, 1}, {"kerberos", STARTUP_KRB4_MSG, 1}, @@ -94,7 +94,7 @@ static struct authsvc authsvcs[] = { {"password", STARTUP_PASSWORD_MSG, 0} }; -static int n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc); +static const int n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc); #ifdef KRB4 /*---------------------------------------------------------------- @@ -549,7 +549,14 @@ fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname, * * Set/return the authentication service currently selected for use by the * frontend. (You can only use one in the frontend, obviously.) + * + * NB: This is not thread-safe if different threads try to select different + * authentication services! It's OK for fe_getauthsvc to select the default, + * since that will be the same for all threads, but direct application use + * of fe_setauthsvc is not thread-safe. However, use of fe_setauthsvc is + * deprecated anyway... */ + static int pg_authsvc = -1; void @@ -558,7 +565,7 @@ fe_setauthsvc(const char *name, char *PQerrormsg) int i; for (i = 0; i < n_authsvcs; ++i) - if (!strcmp(name, authsvcs[i].name)) + if (strcmp(name, authsvcs[i].name) == 0) { pg_authsvc = i; break; diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 4f94b7b0a1..81973e34f6 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; } diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 7be05bd525..5d614ebe37 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.91 2000/02/24 04:50:51 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.92 2000/03/11 03:08:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,6 +39,7 @@ char * const pgresStatus[] = { }; +/* Note: DONOTICE macro will work if applied to either PGconn or PGresult */ #define DONOTICE(conn,message) \ ((*(conn)->noticeHook) ((conn)->noticeArg, (message))) @@ -135,7 +136,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status) result = (PGresult *) malloc(sizeof(PGresult)); - result->conn = conn; /* might be NULL */ + result->xconn = conn; /* might be NULL */ result->ntups = 0; result->numAttributes = 0; result->attDescs = NULL; @@ -150,8 +151,11 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status) result->curOffset = 0; result->spaceLeft = 0; - if (conn) /* consider copying conn's errorMessage */ + if (conn) { + result->noticeHook = conn->noticeHook; + result->noticeArg = conn->noticeArg; + /* consider copying conn's errorMessage */ switch (status) { case PGRES_EMPTY_QUERY: @@ -166,6 +170,12 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status) break; } } + else + { + result->noticeHook = NULL; + result->noticeArg = NULL; + } + return result; } @@ -1833,12 +1843,12 @@ check_field_number(const char *routineName, const PGresult *res, int field_num) return FALSE; /* no way to display error message... */ if (field_num < 0 || field_num >= res->numAttributes) { - if (res->conn) + if (res->noticeHook) { sprintf(noticeBuf, "%s: ERROR! field number %d is out of range 0..%d\n", routineName, field_num, res->numAttributes - 1); - DONOTICE(res->conn, noticeBuf); + DONOTICE(res, noticeBuf); } return FALSE; } @@ -1855,23 +1865,23 @@ check_tuple_field_number(const char *routineName, const PGresult *res, return FALSE; /* no way to display error message... */ if (tup_num < 0 || tup_num >= res->ntups) { - if (res->conn) + if (res->noticeHook) { sprintf(noticeBuf, "%s: ERROR! tuple number %d is out of range 0..%d\n", routineName, tup_num, res->ntups - 1); - DONOTICE(res->conn, noticeBuf); + DONOTICE(res, noticeBuf); } return FALSE; } if (field_num < 0 || field_num >= res->numAttributes) { - if (res->conn) + if (res->noticeHook) { sprintf(noticeBuf, "%s: ERROR! field number %d is out of range 0..%d\n", routineName, field_num, res->numAttributes - 1); - DONOTICE(res->conn, noticeBuf); + DONOTICE(res, noticeBuf); } return FALSE; } @@ -1982,11 +1992,11 @@ PQcmdStatus(PGresult *res) char * PQoidStatus(const PGresult *res) { - /* - * This must be enough to hold the result. Don't laugh, this is - * better than what this function used to do. - */ - static char buf[24]; + /* + * This must be enough to hold the result. Don't laugh, this is + * better than what this function used to do. + */ + static char buf[24]; size_t len; @@ -1995,7 +2005,7 @@ PQoidStatus(const PGresult *res) len = strspn(res->cmdStatus + 7, "0123456789"); if (len > 23) - len = 23; + len = 23; strncpy(buf, res->cmdStatus + 7, len); buf[23] = '\0'; @@ -2046,12 +2056,12 @@ PQcmdTuples(PGresult *res) if (*p == 0) { - if (res->conn) + if (res->noticeHook) { sprintf(noticeBuf, "PQcmdTuples (%s) -- bad input from server\n", res->cmdStatus); - DONOTICE(res->conn, noticeBuf); + DONOTICE(res, noticeBuf); } return ""; } @@ -2062,11 +2072,11 @@ PQcmdTuples(PGresult *res) p++; /* INSERT: skip oid */ if (*p == 0) { - if (res->conn) + if (res->noticeHook) { sprintf(noticeBuf, "PQcmdTuples (INSERT) -- there's no # of tuples\n"); - DONOTICE(res->conn, noticeBuf); + DONOTICE(res, noticeBuf); } return ""; } diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 66437a903f..fcd8e7819e 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-fe.h,v 1.60 2000/02/07 23:10:11 petere Exp $ + * $Id: libpq-fe.h,v 1.61 2000/03/11 03:08:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -130,6 +130,10 @@ extern "C" /* ---------------- * Structure for the conninfo parameter definitions returned by PQconndefaults + * + * All fields except "val" point at static strings which must not be altered. + * "val" is either NULL or a malloc'd current-value string. PQconninfoFree() + * will release both the val strings and the PQconninfoOption array itself. * ---------------- */ typedef struct _PQconninfoOption @@ -137,14 +141,14 @@ extern "C" char *keyword; /* The keyword of the option */ char *envvar; /* Fallback environment variable name */ char *compiled; /* Fallback compiled in default value */ - char *val; /* Options value */ + char *val; /* Option's current value, or NULL */ char *label; /* Label for field in connect dialog */ - char *dispchar; /* Character to display for this field */ - /* in a connect dialog. Values are: */ - /* "" Display entered value as is */ - /* "*" Password field - hide value */ - /* "D" Debug options - don't */ - /* create a field by default */ + char *dispchar; /* Character to display for this field + * in a connect dialog. Values are: + * "" Display entered value as is + * "*" Password field - hide value + * "D" Debug option - don't show by default + */ int dispsize; /* Field size in characters for dialog */ } PQconninfoOption; @@ -183,11 +187,14 @@ extern "C" #define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME) \ PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL) + /* close the current connection and free the PGconn data structure */ + extern void PQfinish(PGconn *conn); + /* get info about connection options known to PQconnectdb */ extern PQconninfoOption *PQconndefaults(void); - /* close the current connection and free the PGconn data structure */ - extern void PQfinish(PGconn *conn); + /* free the data structure returned by PQconndefaults() */ + extern void PQconninfoFree(PQconninfoOption *connOptions); /* * close the current connection and restablish a new one with the same diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 16555d9885..92bd9cfba8 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-int.h,v 1.19 2000/02/07 23:10:11 petere Exp $ + * $Id: libpq-int.h,v 1.20 2000/03/11 03:08:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -121,7 +121,21 @@ struct pg_result * last query */ int binary; /* binary tuple values if binary == 1, * otherwise ASCII */ - PGconn *conn; /* connection we did the query on, if any */ + /* + * The conn link in PGresult is no longer used by any libpq code. + * It should be removed entirely, because it could be a dangling link + * (the application could keep the PGresult around longer than it keeps + * the PGconn!) But there may be apps out there that depend on it, + * so we will leave it here at least for a release or so. + */ + PGconn *xconn; /* connection we did the query on, if any */ + + /* Callback procedure for notice/error message processing + * (copied from originating PGconn). + */ + PQnoticeProcessor noticeHook; + void *noticeArg; + char *errMsg; /* error message, or NULL if no error */ /* All NULL attributes in the query result point to this null string */ diff --git a/src/interfaces/libpq/libpqdll.def b/src/interfaces/libpq/libpqdll.def index 4c8e0e54a1..32b0fa6ec3 100644 --- a/src/interfaces/libpq/libpqdll.def +++ b/src/interfaces/libpq/libpqdll.def @@ -78,3 +78,4 @@ EXPORTS appendPQExpBufferStr @ 75 destroyPQExpBuffer @ 76 createPQExpBuffer @ 77 + PQconninfoFree @ 78 diff --git a/src/interfaces/perl5/Pg.xs b/src/interfaces/perl5/Pg.xs index 2c884c9c03..cd8e5fe681 100644 --- a/src/interfaces/perl5/Pg.xs +++ b/src/interfaces/perl5/Pg.xs @@ -1,6 +1,6 @@ /*------------------------------------------------------- * - * $Id: Pg.xs,v 1.13 1999/10/13 02:26:37 momjian Exp $ with patch for NULs + * $Id: Pg.xs,v 1.14 2000/03/11 03:08:37 tgl Exp $ with patch for NULs * * Copyright (c) 1997, 1998 Edmund Mergl * @@ -247,17 +247,18 @@ PQsetdb(pghost, pgport, pgoptions, pgtty, dbname) HV * PQconndefaults() CODE: - PQconninfoOption *infoOption; + PQconninfoOption *infoOptions; RETVAL = newHV(); - if (infoOption = PQconndefaults()) { - while (infoOption->keyword != NULL) { - if (infoOption->val != NULL) { - hv_store(RETVAL, infoOption->keyword, strlen(infoOption->keyword), newSVpv(infoOption->val, 0), 0); + if (infoOptions = PQconndefaults()) { + PQconninfoOption *option; + for (option = infoOptions; option->keyword != NULL; option++) { + if (option->val != NULL) { + hv_store(RETVAL, option->keyword, strlen(option->keyword), newSVpv(option->val, 0), 0); } else { - hv_store(RETVAL, infoOption->keyword, strlen(infoOption->keyword), newSVpv("", 0), 0); + hv_store(RETVAL, option->keyword, strlen(option->keyword), newSVpv("", 0), 0); } - infoOption++; } + PQconninfoFree(infoOptions); } OUTPUT: RETVAL @@ -774,17 +775,18 @@ setdb(pghost, pgport, pgoptions, pgtty, dbname) HV * conndefaults() CODE: - PQconninfoOption *infoOption; + PQconninfoOption *infoOptions; RETVAL = newHV(); - if (infoOption = PQconndefaults()) { - while (infoOption->keyword != NULL) { - if (infoOption->val != NULL) { - hv_store(RETVAL, infoOption->keyword, strlen(infoOption->keyword), newSVpv(infoOption->val, 0), 0); + if (infoOptions = PQconndefaults()) { + PQconninfoOption *option; + for (option = infoOptions; option->keyword != NULL; option++) { + if (option->val != NULL) { + hv_store(RETVAL, option->keyword, strlen(option->keyword), newSVpv(option->val, 0), 0); } else { - hv_store(RETVAL, infoOption->keyword, strlen(infoOption->keyword), newSVpv("", 0), 0); + hv_store(RETVAL, option->keyword, strlen(option->keyword), newSVpv("", 0), 0); } - infoOption++; } + PQconninfoFree(infoOptions); } OUTPUT: RETVAL