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

Reply via email to