Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v
retrieving revision 1.165
diff -c -c -r1.165 libpq.sgml
*** doc/src/sgml/libpq.sgml	1 Oct 2004 17:34:17 -0000	1.165
--- doc/src/sgml/libpq.sgml	18 Oct 2004 18:13:09 -0000
***************
*** 1183,1194 ****
  </varlistentry>
  </variablelist>
  
! Presently, prepared statements for use with <function>PQexecPrepared</>
! must be set up by executing an SQL <command>PREPARE</> command,
! which is typically sent with <function>PQexec</> (though any of
! <application>libpq</>'s query-submission functions may be used).
! A lower-level interface for preparing statements may be offered in a
! future release.
  </para>
  
  <para>
--- 1183,1238 ----
  </varlistentry>
  </variablelist>
  
! Prepared statements for use with <function>PQexecPrepared</> can be
! created by executing an SQL <command>PREPARE</> statement (which is
! sent with <function>PQexec</>, or one of the other query-submission
! functions), or with <function>PQprepare</>. The latter does not
! require parameter types to be pre-specified.
! </para>
! 
! <para>
! <variablelist>
! <varlistentry>
! <term><function>PQprepare</function><indexterm><primary>PQprepare</></></term>
! <listitem>
! <para>
!           Submits a request to create a prepared statement with the
!           given parameters, and waits for completion.
! <synopsis>
! PGresult *PQprepare(PGconn *conn,
!                     const char *stmtName,
!                     const char *query,
!                     int nParams,
!                     const Oid *paramTypes);
! </synopsis>
! </para>
! 
! <para>
! <function>PQprepare</> creates a prepared statement for execution with
! <function>PQexecPrepared</>. Unlike <command>PREPARE</>, it allows the
! client to prepare a statement without pre-specifying the types of each
! parameter. This function is supported only in protocol 3.0 and later
! connections; it will fail when using protocol 2.0.
! </para>
! 
! <para>
! The function creates a prepared statement named <parameter>stmtName</>
! (which may be <literal>""</>, to refer to the unnamed statement) from
! the <parameter>query</>. If any parameters are used, they are referred
! to in the query as <literal>$1</>, <literal>$2</>, etc.
! 
! <parameter>nParams</> is the number of parameters for which types are
! pre-specified in the array <parameter>paramTypes[]</>. It may be zero,
! or up to the number of parameters used in the query. Each entry in the
! <parameter>paramTypes[]</> array should contain the OID of the type of
! the corresponding parameter. If <parameter>nParams</> is 0, the server
! assigns a data type to each parameter, as it would for untyped literal
! strings. Likewise, if any element in the type array is zero, its type
! is inferred.
! </para>
! </listitem>
! </varlistentry>
! </variablelist>
  </para>
  
  <para>
***************
*** 2353,2358 ****
--- 2397,2423 ----
  </varlistentry>
  
  <varlistentry>
+ <term><function>PQsendPrepare</><indexterm><primary>PQsendPrepare</></></term>
+ <listitem>
+ <para>
+         Sends a request to create a prepared statement with the given
+         parameters, without waiting for completion.
+ <synopsis>
+ int PQsendPrepare(PGconn *conn,
+                   const char *stmtName,
+                   const char *query,
+                   int nParams,
+                   const Oid *paramTypes);
+ </synopsis>
+ 
+         This is an asynchronous version of <function>PQprepare</>, and
+         its parameters are handled identically. It will not work on 2.0
+         protocol connections.
+ </para>
+ </listitem>
+ </varlistentry>
+ 
+ <varlistentry>
  <term><function>PQgetResult</function><indexterm><primary>PQgetResult</></></term>
  <listitem>
  <para>
Index: src/interfaces/libpq/fe-exec.c
===================================================================
RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v
retrieving revision 1.163
diff -c -c -r1.163 fe-exec.c
*** src/interfaces/libpq/fe-exec.c	16 Oct 2004 22:52:53 -0000	1.163
--- src/interfaces/libpq/fe-exec.c	18 Oct 2004 18:13:23 -0000
***************
*** 635,640 ****
--- 635,704 ----
  
  
  /*
+  * PQsendPrepare
+  *   Submit a Parse message, but don't wait for it to finish.
+  *
+  * Returns: 1 if successfully submitted
+  *          0 if error (conn->errorMessage is set)
+  */
+ int
+ PQsendPrepare(PGconn *conn,
+ 			  const char *stmtName, const char *query,
+ 			  int nParams, const Oid *paramTypes)
+ {
+ 	if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
+ 	{
+ 		printfPQExpBuffer(&conn->errorMessage,
+ 						  libpq_gettext("function requires at least protocol version 3.0\n"));
+ 		return 0;
+ 	}
+ 
+ 	if (!PQsendQueryStart(conn))
+ 		return 0;
+ 
+ 	if (pqPutMsgStart('P', false, conn) < 0 ||
+ 		pqPuts(stmtName, conn) < 0 ||
+ 		pqPuts(query, conn) < 0)
+ 		goto sendFailed;
+ 
+ 	if (nParams > 0 && paramTypes)
+ 	{
+ 		int i;
+ 
+ 		if (pqPutInt(nParams, 2, conn) < 0)
+ 			goto sendFailed;
+ 		for (i = 0; i < nParams; i++)
+ 		{
+ 			if (pqPutInt(paramTypes[i], 4, conn) < 0)
+ 				goto sendFailed;
+ 		}
+ 	}
+ 	else
+ 	{
+ 		if (pqPutInt(0, 2, conn) < 0)
+ 			goto sendFailed;
+ 	}
+ 	if (pqPutMsgEnd(conn) < 0)
+ 		goto sendFailed;
+ 
+ 	if (pqPutMsgStart('S', false, conn) < 0 ||
+ 		pqPutMsgEnd(conn) < 0)
+ 		goto sendFailed;
+ 
+ 	conn->ext_query = true;
+ 	conn->sent_prepare = true;
+ 	if (pqFlush(conn) < 0)
+ 		goto sendFailed;
+ 	conn->asyncStatus = PGASYNC_BUSY;
+ 	return 1;
+ 
+ sendFailed:
+ 	pqHandleSendFailure(conn);
+ 	return 0;
+ }
+ 
+ 
+ /*
   * PQsendQuery
   *	 Submit a query, but don't wait for it to finish
   *
***************
*** 1145,1150 ****
--- 1209,1236 ----
  	return PQexecFinish(conn);
  }
  
+ 
+ /*
+  * PQprepare
+  *    Creates a prepared statement by issuing a v3.0 parse message.
+  *
+  * Returns NULL if the query failed, and a new PGresult otherwise. The
+  * user is responsible for calling PQclient() on the result.
+  */
+ 
+ PGresult *
+ PQprepare(PGconn *conn,
+ 		  const char *stmtName, const char *query,
+ 		  int nParams, const Oid *paramTypes)
+ {
+ 	if (!PQexecStart(conn))
+ 		return NULL;
+ 	if (!PQsendPrepare(conn, stmtName, query, nParams, paramTypes))
+ 		return NULL;
+ 	return PQexecFinish(conn);
+ }
+ 
+ 
  /*
   * PQexecParams
   *		Like PQexec, but use protocol 3.0 so we can pass parameters
Index: src/interfaces/libpq/fe-protocol3.c
===================================================================
RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-protocol3.c,v
retrieving revision 1.18
diff -c -c -r1.18 fe-protocol3.c
*** src/interfaces/libpq/fe-protocol3.c	16 Oct 2004 22:52:54 -0000	1.18
--- src/interfaces/libpq/fe-protocol3.c	18 Oct 2004 18:13:26 -0000
***************
*** 220,225 ****
--- 220,233 ----
  					conn->asyncStatus = PGASYNC_READY;
  					break;
  				case '1':		/* Parse Complete */
+ 					if (conn->sent_prepare) {
+ 						if (!conn->result)
+ 							conn->result = PQmakeEmptyPGresult(conn,
+ 															   PGRES_COMMAND_OK);
+ 						conn->asyncStatus = PGASYNC_READY;
+ 						conn->sent_prepare = false;
+ 					}
+ 					break;
  				case '2':		/* Bind Complete */
  				case '3':		/* Close Complete */
  					/* Nothing to do for these message types */
Index: src/interfaces/libpq/libpq-fe.h
===================================================================
RCS file: /cvsroot/pgsql/src/interfaces/libpq/libpq-fe.h,v
retrieving revision 1.111
diff -c -c -r1.111 libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h	16 Oct 2004 22:52:55 -0000	1.111
--- src/interfaces/libpq/libpq-fe.h	18 Oct 2004 18:13:28 -0000
***************
*** 296,301 ****
--- 296,304 ----
  
  /* Simple synchronous query */
  extern PGresult *PQexec(PGconn *conn, const char *query);
+ extern PGresult *PQprepare(PGconn *conn, const char *stmtName,
+ 						   const char *query, int nParams,
+ 						   const Oid *paramTypes);
  extern PGresult *PQexecParams(PGconn *conn,
  			 const char *command,
  			 int nParams,
***************
*** 313,318 ****
--- 316,324 ----
  			   int resultFormat);
  
  /* Interface for multiple-result or asynchronous queries */
+ extern int PQsendPrepare(PGconn *conn, const char *stmtName,
+ 						 const char *query, int nParams,
+ 						 const Oid *paramTypes);
  extern int	PQsendQuery(PGconn *conn, const char *query);
  extern int PQsendQueryParams(PGconn *conn,
  				  const char *command,
Index: src/interfaces/libpq/libpq-int.h
===================================================================
RCS file: /cvsroot/pgsql/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.94
diff -c -c -r1.94 libpq-int.h
*** src/interfaces/libpq/libpq-int.h	16 Oct 2004 22:52:55 -0000	1.94
--- src/interfaces/libpq/libpq-int.h	18 Oct 2004 18:13:29 -0000
***************
*** 268,273 ****
--- 268,275 ----
  								 * nonblock sending semantics */
  	bool		ext_query;		/* was our last query sent with extended
  								 * query protocol? */
+ 	bool		sent_prepare;	/* was our last Parse message sent with
+ 								 * PQprepare? */
  	char		copy_is_binary; /* 1 = copy binary, 0 = copy text */
  	int			copy_already_done;		/* # bytes already returned in
  										 * COPY OUT */
