Le 29/12/2009 14:12, Guillaume Lelarge a écrit : > Le 29/12/2009 00:03, Guillaume Lelarge a écrit : >> Le 28/12/2009 22:59, Tom Lane a écrit : >>> Guillaume Lelarge <guilla...@lelarge.info> writes: >>>> Le 28/12/2009 17:06, Tom Lane a écrit : >>>>> I think we were stalled on the question of whether to use one array >>>>> or two parallel arrays. Do you want to try coding up a sample usage >>>>> of each possibility so we can see which one seems more useful? >>> >>>> I'm interested in working on this. But I don't find the thread that talk >>>> about this. >>> >>> Try here >>> http://archives.postgresql.org/message-id/4aae8ccf.9070...@esilo.com >>> >> >> Thanks. I've read all the "new version of PQconnectdb" and "Determining >> client_encoding from client locale" threads. I think I understand the >> goal. Still need to re-read this one >> (http://archives.postgresql.org/message-id/6222.1253734...@sss.pgh.pa.us) and >> completely understand it (will probably need to look at the code, at >> least the PQconnectdb one). But I'm definitely working on this. >> > > If I try to sum up my readings so far, this is what we still have to do: > > 1. try the one-array approach > PGconn *PQconnectParams(const char **params) > > 2. try the two-arrays approach > PGconn *PQconnectParams(const char **keywords, const char **values) > > Instead of doing a wrapper around PQconnectdb, we need to refactor the > whole function, so that we can get rid of the parsing of the conninfo > string (which is quite complicated). > > Using psql as an example would be a good idea, AFAICT. > > Am I right? did I misunderstand or forget something? >
I supposed I was right since noone yell at me :) I worked on this tonight. You'll find two patches attached, one for the one-array approach, one for the two-arrays approach. I know some more factoring can be done (at least, the "get the fallback resources..." part). I'm OK to do them. I just need to know if I'm on the right track. -- Guillaume. http://www.postgresqlfr.org http://dalibo.com
Index: src/bin/psql/startup.c =================================================================== RCS file: /opt/cvsroot_postgresql/pgsql/src/bin/psql/startup.c,v retrieving revision 1.158 diff -c -p -c -r1.158 startup.c *** src/bin/psql/startup.c 2 Jan 2010 16:57:59 -0000 1.158 --- src/bin/psql/startup.c 4 Jan 2010 21:04:13 -0000 *************** main(int argc, char *argv[]) *** 171,181 **** /* loop until we have a password if requested by backend */ do { ! new_pass = false; ! pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL, ! options.action == ACT_LIST_DB && options.dbname == NULL ? ! "postgres" : options.dbname, ! options.username, password); if (PQstatus(pset.db) == CONNECTION_BAD && PQconnectionNeedsPassword(pset.db) && --- 171,190 ---- /* loop until we have a password if requested by backend */ do { ! const char *params[] = { ! "host", options.host, ! "port", options.port, ! "dbname", (options.action == ACT_LIST_DB && ! options.dbname == NULL) ? "postgres" : options.dbname, ! "user", options.username, ! "password", password, ! "application_name", pset.progname, ! NULL, NULL ! }; ! ! new_pass = false; ! ! pset.db = PQconnectdbParams(params); if (PQstatus(pset.db) == CONNECTION_BAD && PQconnectionNeedsPassword(pset.db) && Index: src/interfaces/libpq/exports.txt =================================================================== RCS file: /opt/cvsroot_postgresql/pgsql/src/interfaces/libpq/exports.txt,v retrieving revision 1.23 diff -c -p -c -r1.23 exports.txt *** src/interfaces/libpq/exports.txt 31 Mar 2009 01:41:27 -0000 1.23 --- src/interfaces/libpq/exports.txt 4 Jan 2010 20:51:13 -0000 *************** PQresultSetInstanceData 150 *** 153,155 **** --- 153,157 ---- PQfireResultCreateEvents 151 PQconninfoParse 152 PQinitOpenSSL 153 + PQconnectdbParams 154 + PQconnectStartParams 155 Index: src/interfaces/libpq/fe-connect.c =================================================================== RCS file: /opt/cvsroot_postgresql/pgsql/src/interfaces/libpq/fe-connect.c,v retrieving revision 1.382 diff -c -p -c -r1.382 fe-connect.c *** src/interfaces/libpq/fe-connect.c 2 Jan 2010 16:58:11 -0000 1.382 --- src/interfaces/libpq/fe-connect.c 4 Jan 2010 20:54:12 -0000 *************** static bool connectOptions2(PGconn *conn *** 259,264 **** --- 259,265 ---- static int connectDBStart(PGconn *conn); static int connectDBComplete(PGconn *conn); static PGconn *makeEmptyPGconn(void); + static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions); static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); static PQconninfoOption *conninfo_parse(const char *conninfo, *************** pgthreadlock_t pg_g_threadlock = default *** 299,304 **** --- 300,337 ---- */ /* + * PQconnectdbParams + * + * establishes a connection to a postgres backend through the postmaster + * using connection information in a struct. + * + * The params struct string is defined as + * + * const char *params[] = {option1, value1, option2, value2, NULL} + * + * definitions. + * + * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL + * if a memory allocation failed. + * If the status field of the connection returned is CONNECTION_BAD, + * then some fields may be null'ed out instead of having valid values. + * + * You should call PQfinish (if conn is not NULL) regardless of whether this + * call succeeded. + */ + PGconn * + PQconnectdbParams(const char * const *params) + { + PGconn *conn = PQconnectStartParams(params); + + if (conn && conn->status != CONNECTION_BAD) + (void) connectDBComplete(conn); + + return conn; + + } + + /* * PQconnectdb * * establishes a connection to a postgres backend through the postmaster *************** PQconnectdb(const char *conninfo) *** 332,343 **** } /* ! * PQconnectStart * * Begins the establishment of a connection to a postgres backend through the ! * postmaster using connection information in a string. * ! * See comment for PQconnectdb for the definition of the string format. * * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and * you should not attempt to proceed with this connection. If the status --- 365,376 ---- } /* ! * PQconnectStartParams * * Begins the establishment of a connection to a postgres backend through the ! * postmaster using connection information in a struct. * ! * See comment for PQconnectdbParams for the definition of the string format. * * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and * you should not attempt to proceed with this connection. If the status *************** PQconnectdb(const char *conninfo) *** 351,359 **** * See PQconnectPoll for more info. */ PGconn * ! PQconnectStart(const char *conninfo) { ! PGconn *conn; /* * Allocate memory for the conn structure --- 384,395 ---- * See PQconnectPoll for more info. */ PGconn * ! PQconnectStartParams(const char * const *params) { ! PGconn *conn; ! PQconninfoOption *options; ! PQconninfoOption *option; ! char *tmp; /* * Allocate memory for the conn structure *************** PQconnectStart(const char *conninfo) *** 363,372 **** return NULL; /* ! * Parse the conninfo string */ ! if (!connectOptions1(conn, conninfo)) ! return conn; /* * Compute derived options --- 399,546 ---- return NULL; /* ! * Make a working copy of PQconninfoOptions ! */ ! options = malloc(sizeof(PQconninfoOptions)); ! if (options == NULL) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("out of memory\n")); ! return NULL; ! } ! memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions)); ! ! /* ! * Parse the params struct */ ! while(*params) ! { ! const char *pname = params[0]; ! const char *pvalue = params[1]; ! ! if (pvalue != NULL) ! { ! /* ! * Now we have the name and the value. Search for the param record. ! */ ! for (option = options; option->keyword != NULL; option++) ! { ! if (strcmp(option->keyword, pname) == 0) ! break; ! } ! ! /* ! * Check for invalid connection option ! */ ! if (option->keyword == NULL) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("invalid connection option \"%s\"\n"), ! pname); ! PQconninfoFree(options); ! return NULL; ! } ! ! /* ! * Store the value ! */ ! if (option->val) ! free(option->val); ! option->val = strdup(pvalue); ! if (!option->val) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("out of memory\n")); ! PQconninfoFree(options); ! return NULL; ! } ! } ! ! params+=2; ! } ! ! /* ! * If there's a service spec, use it to obtain any not-explicitly-given ! * parameters. ! */ ! if (parseServiceInfo(options, &conn->errorMessage)) ! { ! PQconninfoFree(options); ! return NULL; ! } ! ! /* ! * Get the fallback resources for parameters not specified in the conninfo ! * string nor the service. ! */ ! for (option = options; option->keyword != NULL; option++) ! { ! if (option->val != NULL) ! continue; /* Value was in conninfo or service */ ! ! /* ! * Try to get the environment variable fallback ! */ ! if (option->envvar != NULL) ! { ! if ((tmp = getenv(option->envvar)) != NULL) ! { ! option->val = strdup(tmp); ! if (!option->val) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("out of memory\n")); ! PQconninfoFree(options); ! return NULL; ! } ! continue; ! } ! } ! ! /* ! * No environment variable specified or this one isn't set - try ! * compiled in ! */ ! if (option->compiled != NULL) ! { ! option->val = strdup(option->compiled); ! if (!option->val) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("out of memory\n")); ! PQconninfoFree(options); ! return NULL; ! } ! continue; ! } ! ! /* ! * Special handling for user ! */ ! if (strcmp(option->keyword, "user") == 0) ! { ! option->val = pg_fe_getauthname(&conn->errorMessage); ! continue; ! } ! } ! ! if (options == NULL) ! { ! conn->status = CONNECTION_BAD; ! /* errorMessage is already set */ ! return false; ! } ! ! /* ! * Move option values into conn structure ! */ ! fillPGconn(conn, options); ! ! ! /* ! * Free the option info - all is in conn now ! */ ! PQconninfoFree(options); /* * Compute derived options *************** PQconnectStart(const char *conninfo) *** 383,419 **** conn->status = CONNECTION_BAD; } ! return conn; } /* ! * connectOptions1 * ! * Internal subroutine to set up connection parameters given an already- ! * created PGconn and a conninfo string. Derived settings should be ! * processed by calling connectOptions2 next. (We split them because ! * PQsetdbLogin overrides defaults in between.) * ! * Returns true if OK, false if trouble (in which case errorMessage is set ! * and so is conn->status). */ ! static bool ! connectOptions1(PGconn *conn, const char *conninfo) { ! PQconninfoOption *connOptions; ! char *tmp; /* * Parse the conninfo string */ ! connOptions = conninfo_parse(conninfo, &conn->errorMessage, true); ! if (connOptions == NULL) { conn->status = CONNECTION_BAD; - /* errorMessage is already set */ - return false; } /* * Move option values into conn structure * --- 557,625 ---- conn->status = CONNECTION_BAD; } ! return conn; } /* ! * PQconnectStart * ! * Begins the establishment of a connection to a postgres backend through the ! * postmaster using connection information in a string. * ! * See comment for PQconnectdb for the definition of the string format. ! * ! * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and ! * you should not attempt to proceed with this connection. If the status ! * field of the connection returned is CONNECTION_BAD, an error has ! * occurred. In this case you should call PQfinish on the result, (perhaps ! * inspecting the error message first). Other fields of the structure may not ! * be valid if that occurs. If the status field is not CONNECTION_BAD, then ! * this stage has succeeded - call PQconnectPoll, using select(2) to see when ! * this is necessary. ! * ! * See PQconnectPoll for more info. */ ! PGconn * ! PQconnectStart(const char *conninfo) { ! PGconn *conn; ! ! /* ! * Allocate memory for the conn structure ! */ ! conn = makeEmptyPGconn(); ! if (conn == NULL) ! return NULL; /* * Parse the conninfo string */ ! if (!connectOptions1(conn, conninfo)) ! return conn; ! ! /* ! * Compute derived options ! */ ! if (!connectOptions2(conn)) ! return conn; ! ! /* ! * Connect to the database ! */ ! if (!connectDBStart(conn)) { + /* Just in case we failed to set it in connectDBStart */ conn->status = CONNECTION_BAD; } + return conn; + } + + static void + fillPGconn(PGconn *conn, PQconninfoOption *connOptions) + { + char *tmp; + /* * Move option values into conn structure * *************** connectOptions1(PGconn *conn, const char *** 472,477 **** --- 678,716 ---- tmp = conninfo_getval(connOptions, "gsslib"); conn->gsslib = tmp ? strdup(tmp) : NULL; #endif + } + + /* + * connectOptions1 + * + * Internal subroutine to set up connection parameters given an already- + * created PGconn and a conninfo string. Derived settings should be + * processed by calling connectOptions2 next. (We split them because + * PQsetdbLogin overrides defaults in between.) + * + * Returns true if OK, false if trouble (in which case errorMessage is set + * and so is conn->status). + */ + static bool + connectOptions1(PGconn *conn, const char *conninfo) + { + PQconninfoOption *connOptions; + + /* + * Parse the conninfo string + */ + connOptions = conninfo_parse(conninfo, &conn->errorMessage, true); + if (connOptions == NULL) + { + conn->status = CONNECTION_BAD; + /* errorMessage is already set */ + return false; + } + + /* + * Move option values into conn structure + */ + fillPGconn(conn, connOptions); /* * Free the option info - all is in conn now Index: src/interfaces/libpq/libpq-fe.h =================================================================== RCS file: /opt/cvsroot_postgresql/pgsql/src/interfaces/libpq/libpq-fe.h,v retrieving revision 1.148 diff -c -p -c -r1.148 libpq-fe.h *** src/interfaces/libpq/libpq-fe.h 2 Jan 2010 16:58:12 -0000 1.148 --- src/interfaces/libpq/libpq-fe.h 4 Jan 2010 20:51:53 -0000 *************** typedef struct pgresAttDesc *** 226,235 **** --- 226,237 ---- /* make a new client connection to the backend */ /* Asynchronous (non-blocking) */ extern PGconn *PQconnectStart(const char *conninfo); + extern PGconn *PQconnectStartParams(const char * const *params); extern PostgresPollingStatusType PQconnectPoll(PGconn *conn); /* Synchronous (blocking) */ extern PGconn *PQconnectdb(const char *conninfo); + extern PGconn *PQconnectdbParams(const char * const *params); extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName,
Index: src/bin/psql/startup.c =================================================================== RCS file: /opt/cvsroot_postgresql/pgsql/src/bin/psql/startup.c,v retrieving revision 1.158 diff -c -p -c -r1.158 startup.c *** src/bin/psql/startup.c 2 Jan 2010 16:57:59 -0000 1.158 --- src/bin/psql/startup.c 4 Jan 2010 21:27:12 -0000 *************** main(int argc, char *argv[]) *** 168,181 **** if (pset.getPassword == TRI_YES) password = simple_prompt(password_prompt, 100, false); /* loop until we have a password if requested by backend */ do { ! new_pass = false; ! pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL, ! options.action == ACT_LIST_DB && options.dbname == NULL ? ! "postgres" : options.dbname, ! options.username, password); if (PQstatus(pset.db) == CONNECTION_BAD && PQconnectionNeedsPassword(pset.db) && --- 168,200 ---- if (pset.getPassword == TRI_YES) password = simple_prompt(password_prompt, 100, false); + const char *keywords[] = { + "host", + "port", + "dbname", + "user", + "password", + "application_name", + NULL + }; + /* loop until we have a password if requested by backend */ do { ! const char *values[] = { ! options.host, ! options.port, ! (options.action == ACT_LIST_DB && ! options.dbname == NULL) ? "postgres" : options.dbname, ! options.username, ! password, ! pset.progname, ! NULL ! }; ! ! new_pass = false; ! ! pset.db = PQconnectdbParams(keywords, values); if (PQstatus(pset.db) == CONNECTION_BAD && PQconnectionNeedsPassword(pset.db) && Index: src/interfaces/libpq/exports.txt =================================================================== RCS file: /opt/cvsroot_postgresql/pgsql/src/interfaces/libpq/exports.txt,v retrieving revision 1.23 diff -c -p -c -r1.23 exports.txt *** src/interfaces/libpq/exports.txt 31 Mar 2009 01:41:27 -0000 1.23 --- src/interfaces/libpq/exports.txt 4 Jan 2010 21:07:49 -0000 *************** PQresultSetInstanceData 150 *** 153,155 **** --- 153,157 ---- PQfireResultCreateEvents 151 PQconninfoParse 152 PQinitOpenSSL 153 + PQconnectdbParams 154 + PQconnectStartParams 155 Index: src/interfaces/libpq/fe-connect.c =================================================================== RCS file: /opt/cvsroot_postgresql/pgsql/src/interfaces/libpq/fe-connect.c,v retrieving revision 1.382 diff -c -p -c -r1.382 fe-connect.c *** src/interfaces/libpq/fe-connect.c 2 Jan 2010 16:58:11 -0000 1.382 --- src/interfaces/libpq/fe-connect.c 4 Jan 2010 21:18:52 -0000 *************** static bool connectOptions2(PGconn *conn *** 259,264 **** --- 259,265 ---- static int connectDBStart(PGconn *conn); static int connectDBComplete(PGconn *conn); static PGconn *makeEmptyPGconn(void); + static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions); static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); static PQconninfoOption *conninfo_parse(const char *conninfo, *************** pgthreadlock_t pg_g_threadlock = default *** 299,304 **** --- 300,339 ---- */ /* + * PQconnectdbParams + * + * establishes a connection to a postgres backend through the postmaster + * using connection information in two structs. + * + * The keywords struct is defined as + * + * const char *params[] = {option1, option2, NULL} + * + * The values struct is defined as + * + * const char *params[] = {option1, option2, NULL} + * + * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL + * if a memory allocation failed. + * If the status field of the connection returned is CONNECTION_BAD, + * then some fields may be null'ed out instead of having valid values. + * + * You should call PQfinish (if conn is not NULL) regardless of whether this + * call succeeded. + */ + PGconn * + PQconnectdbParams(const char **keywords, const char **values) + { + PGconn *conn = PQconnectStartParams(keywords, values); + + if (conn && conn->status != CONNECTION_BAD) + (void) connectDBComplete(conn); + + return conn; + + } + + /* * PQconnectdb * * establishes a connection to a postgres backend through the postmaster *************** PQconnectdb(const char *conninfo) *** 332,343 **** } /* ! * PQconnectStart * * Begins the establishment of a connection to a postgres backend through the ! * postmaster using connection information in a string. * ! * See comment for PQconnectdb for the definition of the string format. * * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and * you should not attempt to proceed with this connection. If the status --- 367,378 ---- } /* ! * PQconnectStartParams * * Begins the establishment of a connection to a postgres backend through the ! * postmaster using connection information in a struct. * ! * See comment for PQconnectdbParams for the definition of the string format. * * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and * you should not attempt to proceed with this connection. If the status *************** PQconnectdb(const char *conninfo) *** 351,359 **** * See PQconnectPoll for more info. */ PGconn * ! PQconnectStart(const char *conninfo) { ! PGconn *conn; /* * Allocate memory for the conn structure --- 386,397 ---- * See PQconnectPoll for more info. */ PGconn * ! PQconnectStartParams(const char **keywords, const char **values) { ! PGconn *conn; ! PQconninfoOption *options; ! PQconninfoOption *option; ! char *tmp; /* * Allocate memory for the conn structure *************** PQconnectStart(const char *conninfo) *** 363,372 **** return NULL; /* ! * Parse the conninfo string */ ! if (!connectOptions1(conn, conninfo)) ! return conn; /* * Compute derived options --- 401,549 ---- return NULL; /* ! * Make a working copy of PQconninfoOptions ! */ ! options = malloc(sizeof(PQconninfoOptions)); ! if (options == NULL) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("out of memory\n")); ! return NULL; ! } ! memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions)); ! ! /* ! * Parse the params struct */ ! while(*keywords) ! { ! const char *pname = keywords[0]; ! const char *pvalue = values[0]; ! ! if (pvalue != NULL) ! { ! /* ! * Now we have the name and the value. Search for the param record. ! */ ! for (option = options; option->keyword != NULL; option++) ! { ! if (strcmp(option->keyword, pname) == 0) ! break; ! } ! ! /* ! * Check for invalid connection option ! */ ! if (option->keyword == NULL) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("invalid connection option \"%s\"\n"), ! pname); ! PQconninfoFree(options); ! return NULL; ! } ! ! /* ! * Store the value ! */ ! if (option->val) ! free(option->val); ! option->val = strdup(pvalue); ! if (!option->val) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("out of memory\n")); ! PQconninfoFree(options); ! return NULL; ! } ! } ! ! keywords+=1; ! values+=1; ! } ! ! /* ! * If there's a service spec, use it to obtain any not-explicitly-given ! * parameters. ! */ ! if (parseServiceInfo(options, &conn->errorMessage)) ! { ! PQconninfoFree(options); ! return NULL; ! } ! ! /* ! * Get the fallback resources for parameters not specified in the conninfo ! * string nor the service. ! */ ! for (option = options; option->keyword != NULL; option++) ! { ! if (option->val != NULL) ! continue; /* Value was in conninfo or service */ ! ! /* ! * Try to get the environment variable fallback ! */ ! if (option->envvar != NULL) ! { ! if ((tmp = getenv(option->envvar)) != NULL) ! { ! option->val = strdup(tmp); ! if (!option->val) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("out of memory\n")); ! PQconninfoFree(options); ! return NULL; ! } ! continue; ! } ! } ! ! /* ! * No environment variable specified or this one isn't set - try ! * compiled in ! */ ! if (option->compiled != NULL) ! { ! option->val = strdup(option->compiled); ! if (!option->val) ! { ! printfPQExpBuffer(&conn->errorMessage, ! libpq_gettext("out of memory\n")); ! PQconninfoFree(options); ! return NULL; ! } ! continue; ! } ! ! /* ! * Special handling for user ! */ ! if (strcmp(option->keyword, "user") == 0) ! { ! option->val = pg_fe_getauthname(&conn->errorMessage); ! continue; ! } ! } ! ! if (options == NULL) ! { ! conn->status = CONNECTION_BAD; ! /* errorMessage is already set */ ! return false; ! } ! ! /* ! * Move option values into conn structure ! */ ! fillPGconn(conn, options); ! ! ! /* ! * Free the option info - all is in conn now ! */ ! PQconninfoFree(options); /* * Compute derived options *************** PQconnectStart(const char *conninfo) *** 383,419 **** conn->status = CONNECTION_BAD; } ! return conn; } /* ! * connectOptions1 * ! * Internal subroutine to set up connection parameters given an already- ! * created PGconn and a conninfo string. Derived settings should be ! * processed by calling connectOptions2 next. (We split them because ! * PQsetdbLogin overrides defaults in between.) * ! * Returns true if OK, false if trouble (in which case errorMessage is set ! * and so is conn->status). */ ! static bool ! connectOptions1(PGconn *conn, const char *conninfo) { ! PQconninfoOption *connOptions; ! char *tmp; /* * Parse the conninfo string */ ! connOptions = conninfo_parse(conninfo, &conn->errorMessage, true); ! if (connOptions == NULL) { conn->status = CONNECTION_BAD; - /* errorMessage is already set */ - return false; } /* * Move option values into conn structure * --- 560,628 ---- conn->status = CONNECTION_BAD; } ! return conn; } /* ! * PQconnectStart * ! * Begins the establishment of a connection to a postgres backend through the ! * postmaster using connection information in a string. * ! * See comment for PQconnectdb for the definition of the string format. ! * ! * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and ! * you should not attempt to proceed with this connection. If the status ! * field of the connection returned is CONNECTION_BAD, an error has ! * occurred. In this case you should call PQfinish on the result, (perhaps ! * inspecting the error message first). Other fields of the structure may not ! * be valid if that occurs. If the status field is not CONNECTION_BAD, then ! * this stage has succeeded - call PQconnectPoll, using select(2) to see when ! * this is necessary. ! * ! * See PQconnectPoll for more info. */ ! PGconn * ! PQconnectStart(const char *conninfo) { ! PGconn *conn; ! ! /* ! * Allocate memory for the conn structure ! */ ! conn = makeEmptyPGconn(); ! if (conn == NULL) ! return NULL; /* * Parse the conninfo string */ ! if (!connectOptions1(conn, conninfo)) ! return conn; ! ! /* ! * Compute derived options ! */ ! if (!connectOptions2(conn)) ! return conn; ! ! /* ! * Connect to the database ! */ ! if (!connectDBStart(conn)) { + /* Just in case we failed to set it in connectDBStart */ conn->status = CONNECTION_BAD; } + return conn; + } + + static void + fillPGconn(PGconn *conn, PQconninfoOption *connOptions) + { + char *tmp; + /* * Move option values into conn structure * *************** connectOptions1(PGconn *conn, const char *** 472,477 **** --- 681,719 ---- tmp = conninfo_getval(connOptions, "gsslib"); conn->gsslib = tmp ? strdup(tmp) : NULL; #endif + } + + /* + * connectOptions1 + * + * Internal subroutine to set up connection parameters given an already- + * created PGconn and a conninfo string. Derived settings should be + * processed by calling connectOptions2 next. (We split them because + * PQsetdbLogin overrides defaults in between.) + * + * Returns true if OK, false if trouble (in which case errorMessage is set + * and so is conn->status). + */ + static bool + connectOptions1(PGconn *conn, const char *conninfo) + { + PQconninfoOption *connOptions; + + /* + * Parse the conninfo string + */ + connOptions = conninfo_parse(conninfo, &conn->errorMessage, true); + if (connOptions == NULL) + { + conn->status = CONNECTION_BAD; + /* errorMessage is already set */ + return false; + } + + /* + * Move option values into conn structure + */ + fillPGconn(conn, connOptions); /* * Free the option info - all is in conn now Index: src/interfaces/libpq/libpq-fe.h =================================================================== RCS file: /opt/cvsroot_postgresql/pgsql/src/interfaces/libpq/libpq-fe.h,v retrieving revision 1.148 diff -c -p -c -r1.148 libpq-fe.h *** src/interfaces/libpq/libpq-fe.h 2 Jan 2010 16:58:12 -0000 1.148 --- src/interfaces/libpq/libpq-fe.h 4 Jan 2010 21:14:47 -0000 *************** typedef struct pgresAttDesc *** 226,235 **** --- 226,237 ---- /* make a new client connection to the backend */ /* Asynchronous (non-blocking) */ extern PGconn *PQconnectStart(const char *conninfo); + extern PGconn *PQconnectStartParams(const char **keywords, const char **values); extern PostgresPollingStatusType PQconnectPoll(PGconn *conn); /* Synchronous (blocking) */ extern PGconn *PQconnectdb(const char *conninfo); + extern PGconn *PQconnectdbParams(const char **keywords, const char **values); extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName,
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers