Here is a mega-patch that merges in your four previous patches.  Is this
ready to be applied?  Making libpq changes during beta is risky so we
had better be careful.

I have also attached your pgtest.c file.

---------------------------------------------------------------------------

Abhijit Menon-Sen wrote:
> At 2004-10-16 18:41:05 -0400, [EMAIL PROTECTED] wrote:
> >
> > I think the cleanest solution is probably to add a state flag indicating
> > whether ParseComplete should generate a PGresult or not.
> 
> Like the appended (incremental) patch?
> 
> (I didn't think this would work, because I thought libpq would allow you
> to send multiple queries before trying to read results. But you said it
> didn't support that, so...)
> 
> -- ams
> 
> --- libpq-int.h.1~    2004-10-18 17:42:13.175759981 +0530
> +++ libpq-int.h       2004-10-18 17:43:40.105986570 +0530
> @@ -269,6 +269,8 @@
>                                                                * 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 */
> 
> --- fe-exec.c.2~      2004-10-18 17:47:55.540189274 +0530
> +++ fe-exec.c 2004-10-18 17:48:30.119038902 +0530
> @@ -686,6 +686,7 @@
>               goto sendFailed;
>  
>       conn->ext_query = true;
> +     conn->sent_prepare = true;
>       if (pqFlush(conn) < 0)
>               goto sendFailed;
>       conn->asyncStatus = PGASYNC_BUSY;
> 
> --- fe-protocol3.c.2~ 2004-10-18 17:44:06.616198123 +0530
> +++ fe-protocol3.c    2004-10-18 17:46:34.431656569 +0530
> @@ -220,10 +220,13 @@
>                                       conn->asyncStatus = PGASYNC_READY;
>                                       break;
>                               case '1':               /* Parse Complete */
> -                                     if (conn->result == NULL)
> -                                             conn->result = 
> PQmakeEmptyPGresult(conn,
> -                                                                                    
>                             PGRES_COMMAND_OK);
> -                                     conn->asyncStatus = PGASYNC_READY;
> +                                     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 */
> 
> --- libpq-fe.h.2~     2004-10-18 17:55:40.632064120 +0530
> +++ libpq-fe.h        2004-10-18 17:56:26.501634328 +0530
> @@ -312,9 +312,9 @@
>                          int resultFormat);
>  
>  /* Interface for multiple-result or asynchronous queries */
> -extern PGresult *PQsendPrepare(PGconn *conn, const char *stmtName,
> -                                                        const char *query, int 
> nParams,
> -                                                        const Oid *paramTypes);
> +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,
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
> 
>                http://www.postgresql.org/docs/faqs/FAQ.html
> 

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  [EMAIL PROTECTED]               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
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 */
/*
 * Test program for PQprepare/PQdescribe.
 * Abhijit Menon-Sen <[EMAIL PROTECTED]>
 *
 * create table pqtest (a int, b text, c text);
 * insert into pqtest (a,b,c) values (1,'foo','bar');
 * insert into pqtest (a,b,c) values (1,'foo','baz');
 * insert into pqtest (a,b,c) values (2,'foo','barf');
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libpq-fe.h"


int main(int argc, char *argv[])
{
    int i, a, b, c;
    PGconn *conn;
    PGresult *res;

    char *query = "select * from pqtest where a=$1 and b=$2";
    const char *values[2];

    conn = PQconnectdb("");
    if (PQstatus(conn) != CONNECTION_OK) {
        fprintf(stderr, "Couldn't connect to the database: %s",
                PQerrorMessage(conn));
        PQfinish(conn);
        exit(-1);
    }

    res = PQprepare(conn, "prep", query, 0, NULL);
    if (PQresultStatus(res) != PGRES_COMMAND_OK) {
        fprintf(stderr, "PREPARE failed: %s", PQerrorMessage(conn));
        PQclear(res);
        PQfinish(conn);
        exit(-1);
    }

    PQclear(res);
    values[0] = "1";
    values[1] = "foo";
    res = PQexecPrepared(conn, "prep", 2, values, NULL, NULL, 0);
    if (PQresultStatus(res) != PGRES_TUPLES_OK) {
        fprintf(stderr, "EXECUTE failed: %s", PQerrorMessage(conn));
        PQclear(res);
        PQfinish(conn);
        exit(-1);
    }

    a = PQfnumber(res, "a");
    b = PQfnumber(res, "b");
    c = PQfnumber(res, "c");

    printf("Results:\n");
    for(i = 0; i < PQntuples(res); i++) {
        char *av = PQgetvalue(res, i, a);
        char *bv = PQgetvalue(res, i, b);
        char *cv = PQgetvalue(res, i, c);
        printf("  (a=%s)(b=%s)(c=%s)\n", av, bv, cv);
    }
    printf("%d rows\n", i);

    PQclear(res);
    PQfinish(conn);
    return 0;
}
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]

Reply via email to