]> granicus.if.org Git - postgresql/commitdiff
Add PQdescribePrepared, PQdescribePortal, and related functions to libpq
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 18 Aug 2006 19:52:39 +0000 (19:52 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 18 Aug 2006 19:52:39 +0000 (19:52 +0000)
to allow obtaining information about previously prepared statements and
open cursors.  Volkan Yazici

doc/src/sgml/libpq.sgml
src/interfaces/libpq/exports.txt
src/interfaces/libpq/fe-exec.c
src/interfaces/libpq/fe-protocol3.c
src/interfaces/libpq/libpq-fe.h
src/interfaces/libpq/libpq-int.h

index 7ffd15a0388d3d957eed028b434b905e5bd58c67..db6525e0c881a32ca52b58a2db333f8049ac751c 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.214 2006/07/27 13:20:24 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.215 2006/08/18 19:52:39 tgl Exp $ -->
 
  <chapter id="libpq">
   <title><application>libpq</application> - C Library</title>
@@ -1244,7 +1244,8 @@ or any particular element in the array is zero, the server assigns a data type
 to the parameter symbol in the same way it would do for an untyped literal
 string.  Also, the query may use parameter symbols with numbers higher than
 <parameter>nParams</>; data types will be inferred for these symbols as
-well.
+well.  (See <function>PQdescribePrepared</function> for a means to find out
+what data types were inferred.)
 </para>
 
 <para>
@@ -1255,13 +1256,6 @@ send the command at all.
 Use <function>PQerrorMessage</function> to get more information
 about such errors.
 </para>
-
-<para>
-At present, there is no way to determine the actual data type inferred for
-any parameters whose types are not specified in <parameter>paramTypes[]</>.
-This is a <application>libpq</> omission that will probably be rectified
-in a future release.
-</para>
 </listitem>
 </varlistentry>
 </variablelist>
@@ -1315,6 +1309,72 @@ the prepared statement's parameter types were determined when it was created).
 </para>
 </listitem>
 </varlistentry>
+
+<varlistentry>
+<term><function>PQdescribePrepared</function><indexterm><primary>PQdescribePrepared</></></term>
+<listitem>
+<para>
+          Submits a request to obtain information about the specified
+          prepared statement, and waits for completion.
+<synopsis>
+PGresult *PQdescribePrepared(PGconn *conn, const char *stmtName);
+</synopsis>
+</para>
+
+<para>
+<function>PQdescribePrepared</> allows an application to obtain information
+about a previously prepared statement.
+<function>PQdescribePrepared</> is supported only in protocol 3.0 and later
+connections; it will fail when using protocol 2.0.
+</para>
+
+<para>
+<parameter>stmtName</> may be <literal>""</> or NULL to reference the unnamed
+statement, otherwise it must be the name of an existing prepared statement.
+On success, a <structname>PGresult</> with status
+<literal>PGRES_COMMAND_OK</literal> is returned.  The functions
+<function>PQnparams</function> and <function>PQparamtype</function>
+may be applied to this <structname>PGresult</> to obtain information
+about the parameters of the prepared statement, and the functions
+<function>PQnfields</function>, <function>PQfname</function>,
+<function>PQftype</function>, etc provide information about the result
+columns (if any) of the statement.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><function>PQdescribePortal</function><indexterm><primary>PQdescribePortal</></></term>
+<listitem>
+<para>
+          Submits a request to obtain information about the specified
+          portal, and waits for completion.
+<synopsis>
+PGresult *PQdescribePortal(PGconn *conn, const char *portalName);
+</synopsis>
+</para>
+
+<para>
+<function>PQdescribePortal</> allows an application to obtain information
+about a previously created portal.  (<application>libpq</> does not provide
+any direct access to portals, but you can use this function to inspect the
+properties of a cursor created with a <command>DECLARE CURSOR</> SQL command.)
+<function>PQdescribePortal</> is supported only in protocol 3.0 and later
+connections; it will fail when using protocol 2.0.
+</para>
+
+<para>
+<parameter>portalName</> may be <literal>""</> or NULL to reference the unnamed
+portal, otherwise it must be the name of an existing portal.
+On success, a <structname>PGresult</> with status
+<literal>PGRES_COMMAND_OK</literal> is returned.  The functions
+<function>PQnfields</function>, <function>PQfname</function>,
+<function>PQftype</function>, etc may be applied to the
+<structname>PGresult</> to obtain information about the result
+columns (if any) of the portal.
+</para>
+</listitem>
+</varlistentry>
 </variablelist>
 </para>
 
@@ -1707,8 +1767,11 @@ object, just as with a <structname>PGresult</structname> returned by
 These functions are used to extract information from a
 <structname>PGresult</structname> object that represents a successful
 query result (that is, one that has status
-<literal>PGRES_TUPLES_OK</literal>).  For objects with other status
-values they will act as though the result has zero rows and zero columns.
+<literal>PGRES_TUPLES_OK</literal>).  They can also be used to extract
+information from a successful Describe operation: a Describe's result
+has all the same column information that actual execution of the query
+would provide, but it has zero rows.  For objects with other status values,
+these functions will act as though the result has zero rows and zero columns.
 </para>
 
 <variablelist>
@@ -2040,6 +2103,43 @@ on <function>PQfsize</function> to obtain the actual data length.
 </listitem>
 </varlistentry>
 
+<varlistentry>
+<term><function>PQnparams</function><indexterm><primary>PQnparams</></></term>
+<listitem>
+<para>
+          Returns the number of parameters of a prepared statement.
+<synopsis>
+int PQnparams(const PGresult *res);
+</synopsis>
+</para>
+
+<para>
+This function is only useful when inspecting the result of
+<function>PQdescribePrepared</>.  For other types of queries it will
+return zero.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><function>PQparamtype</function><indexterm><primary>PQparamtype</></></term>
+<listitem>
+<para>
+          Returns the data type of the indicated statement parameter.
+          Parameter numbers start at 0.
+<synopsis>
+Oid PQparamtype(const PGresult *res, int param_number);
+</synopsis>
+</para>
+
+<para>
+This function is only useful when inspecting the result of
+<function>PQdescribePrepared</>.  For other types of queries it will
+return zero.
+</para>
+</listitem>
+</varlistentry>
+
 <varlistentry>
 <term><function>PQprint</function><indexterm><primary>PQprint</></></term>
 <listitem>
@@ -2486,13 +2586,17 @@ underlying functions that <function>PQexec</function> is built from:
 <function>PQsendQuery</function> and <function>PQgetResult</function>.
 There are also
 <function>PQsendQueryParams</function>,
-<function>PQsendPrepare</function>, and
+<function>PQsendPrepare</function>,
 <function>PQsendQueryPrepared</function>,
+<function>PQsendDescribePrepared</function>, and
+<function>PQsendDescribePortal</function>,
 which can be used with <function>PQgetResult</function> to duplicate the
 functionality of
 <function>PQexecParams</function>,
-<function>PQprepare</function>, and
-<function>PQexecPrepared</function>
+<function>PQprepare</function>,
+<function>PQexecPrepared</function>,
+<function>PQdescribePrepared</function>, and
+<function>PQdescribePortal</function>
 respectively.
 
 <variablelist>
@@ -2598,6 +2702,50 @@ int PQsendQueryPrepared(PGconn *conn,
 </listitem>
 </varlistentry>
 
+<varlistentry>
+<term><function>PQsendDescribePrepared</><indexterm><primary>PQsendDescribePrepared</></></term>
+<listitem>
+<para>
+        Submits a request to obtain information about the specified
+        prepared statement, without waiting for completion.
+<synopsis>
+int PQsendDescribePrepared(PGconn *conn, const char *stmtName);
+</synopsis>
+
+        This is an asynchronous version of <function>PQdescribePrepared</>: it
+        returns 1 if it was able to dispatch the request, and 0 if not.
+        After a successful call, call <function>PQgetResult</function>
+        to obtain the results.
+        The function's parameters are handled identically to
+        <function>PQdescribePrepared</function>.  Like
+        <function>PQdescribePrepared</function>, it will not work on 2.0-protocol
+        connections.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><function>PQsendDescribePortal</><indexterm><primary>PQsendDescribePortal</></></term>
+<listitem>
+<para>
+        Submits a request to obtain information about the specified
+        portal, without waiting for completion.
+<synopsis>
+int PQsendDescribePortal(PGconn *conn, const char *portalName);
+</synopsis>
+
+        This is an asynchronous version of <function>PQdescribePortal</>: it
+        returns 1 if it was able to dispatch the request, and 0 if not.
+        After a successful call, call <function>PQgetResult</function>
+        to obtain the results.
+        The function's parameters are handled identically to
+        <function>PQdescribePortal</function>.  Like
+        <function>PQdescribePortal</function>, it will not work on 2.0-protocol
+        connections.
+</para>
+</listitem>
+</varlistentry>
+
 <varlistentry>
 <term><function>PQgetResult</function><indexterm><primary>PQgetResult</></></term>
 <listitem>
index 078e4f9771a668a35b22eb218d6341d887150e00..606133bd00da0d88aba761fa07bfe0faef2559ff 100644 (file)
@@ -1,4 +1,4 @@
-# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.13 2006/07/04 13:22:15 momjian Exp $
+# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.14 2006/08/18 19:52:39 tgl Exp $
 # Functions to be exported by libpq DLLs
 PQconnectdb               1
 PQsetdbLogin              2
@@ -130,3 +130,9 @@ PQescapeByteaConn         127
 PQencryptPassword         128
 PQisthreadsafe            129
 enlargePQExpBuffer        130
+PQnparams                 131
+PQparamtype               132
+PQdescribePrepared        133
+PQdescribePortal          134
+PQsendDescribePrepared    135
+PQsendDescribePortal      136
index 3906a52c8ccc6cb4f078df7b8b117ebfa2a9fbf4..71d9c02eb1ed79085eabb10069d7cd60fa7af845 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.189 2006/08/04 22:20:06 momjian Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.190 2006/08/18 19:52:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,6 +61,8 @@ static int PQsendQueryGuts(PGconn *conn,
 static void parseInput(PGconn *conn);
 static bool PQexecStart(PGconn *conn);
 static PGresult *PQexecFinish(PGconn *conn);
+static int     PQsendDescribe(PGconn *conn, char desc_type,
+                                                  const char *desc_target);
 
 
 /* ----------------
@@ -147,6 +149,8 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
        result->attDescs = NULL;
        result->tuples = NULL;
        result->tupArrSize = 0;
+       result->numParameters = 0;
+       result->paramDescs = NULL;
        result->resultStatus = status;
        result->cmdStatus[0] = '\0';
        result->binary = 0;
@@ -367,6 +371,7 @@ PQclear(PGresult *res)
        /* zero out the pointer fields to catch programming errors */
        res->attDescs = NULL;
        res->tuples = NULL;
+       res->paramDescs = NULL;
        res->errFields = NULL;
        /* res->curBlock was zeroed out earlier */
 
@@ -1471,6 +1476,139 @@ PQexecFinish(PGconn *conn)
        return lastResult;
 }
 
+/*
+ * PQdescribePrepared
+ *       Obtain information about a previously prepared statement
+ *
+ * If the query was not even sent, return NULL; conn->errorMessage is set to
+ * a relevant message.
+ * If the query was sent, a new PGresult is returned (which could indicate
+ * either success or failure).  On success, the PGresult contains status
+ * PGRES_COMMAND_OK, and its parameter and column-heading fields describe
+ * the statement's inputs and outputs respectively.
+ * The user is responsible for freeing the PGresult via PQclear()
+ * when done with it.
+ */
+PGresult *
+PQdescribePrepared(PGconn *conn, const char *stmt)
+{
+       if (!PQexecStart(conn))
+               return NULL;
+       if (!PQsendDescribe(conn, 'S', stmt))
+               return NULL;
+       return PQexecFinish(conn);
+}
+
+/*
+ * PQdescribePortal
+ *       Obtain information about a previously created portal
+ *
+ * This is much like PQdescribePrepared, except that no parameter info is
+ * returned.  Note that at the moment, libpq doesn't really expose portals
+ * to the client; but this can be used with a portal created by a SQL
+ * DECLARE CURSOR command.
+ */
+PGresult *
+PQdescribePortal(PGconn *conn, const char *portal)
+{
+       if (!PQexecStart(conn))
+               return NULL;
+       if (!PQsendDescribe(conn, 'P', portal))
+               return NULL;
+       return PQexecFinish(conn);
+}
+
+/*
+ * PQsendDescribePrepared
+ *      Submit a Describe Statement command, but don't wait for it to finish
+ *
+ * Returns: 1 if successfully submitted
+ *                     0 if error (conn->errorMessage is set)
+ */
+int
+PQsendDescribePrepared(PGconn *conn, const char *stmt)
+{
+       return PQsendDescribe(conn, 'S', stmt);
+}
+
+/*
+ * PQsendDescribePortal
+ *      Submit a Describe Portal command, but don't wait for it to finish
+ *
+ * Returns: 1 if successfully submitted
+ *                     0 if error (conn->errorMessage is set)
+ */
+int
+PQsendDescribePortal(PGconn *conn, const char *portal)
+{
+       return PQsendDescribe(conn, 'P', portal);
+}
+
+/*
+ * PQsendDescribe
+ *      Common code to send a Describe command
+ *
+ * Available options for desc_type are
+ *   'S' to describe a prepared statement; or
+ *   'P' to describe a portal.
+ * Returns 1 on success and 0 on failure.
+ */
+static int
+PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
+{
+       /* Treat null desc_target as empty string */
+       if (!desc_target)
+               desc_target = "";
+
+       if (!PQsendQueryStart(conn))
+               return 0;
+
+       /* This isn't gonna work on a 2.0 server */
+       if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                libpq_gettext("function requires at least protocol version 3.0\n"));
+               return 0;
+       }
+
+       /* construct the Describe message */
+       if (pqPutMsgStart('D', false, conn) < 0 ||
+               pqPutc(desc_type, conn) < 0 ||
+               pqPuts(desc_target, conn) < 0 ||
+               pqPutMsgEnd(conn) < 0)
+               goto sendFailed;
+
+       /* construct the Sync message */
+       if (pqPutMsgStart('S', false, conn) < 0 ||
+               pqPutMsgEnd(conn) < 0)
+               goto sendFailed;
+
+       /* remember we are doing a Describe */
+       conn->queryclass = PGQUERY_DESCRIBE;
+
+       /* reset last-query string (not relevant now) */
+       if (conn->last_query)
+       {
+               free(conn->last_query);
+               conn->last_query = NULL;
+       }
+
+       /*
+        * Give the data a push.  In nonblock mode, don't complain if we're unable
+        * to send it all; PQgetResult() will do any additional flushing needed.
+        */
+       if (pqFlush(conn) < 0)
+               goto sendFailed;
+
+       /* OK, it's launched! */
+       conn->asyncStatus = PGASYNC_BUSY;
+       return 1;
+
+sendFailed:
+       pqHandleSendFailure(conn);
+       return 0;
+}
+
 /*
  * PQnotifies
  *       returns a PGnotify* structure of the latest async notification
@@ -1984,6 +2122,22 @@ check_tuple_field_number(const PGresult *res,
        return TRUE;
 }
 
+static int
+check_param_number(const PGresult *res, int param_num)
+{
+       if (!res)
+               return FALSE;                   /* no way to display error message... */
+       if (param_num < 0 || param_num >= res->numParameters)
+       {
+               pqInternalNotice(&res->noticeHooks,
+                                                "parameter number %d is out of range 0..%d",
+                                                param_num, res->numParameters - 1);
+               return FALSE;
+       }
+       
+       return TRUE;
+}
+
 /*
  * returns NULL if the field_num is invalid
  */
@@ -2307,6 +2461,32 @@ PQgetisnull(const PGresult *res, int tup_num, int field_num)
                return 0;
 }
 
+/* PQnparams:
+ *     returns the number of input parameters of a prepared statement.
+ */
+int
+PQnparams(const PGresult *res)
+{
+       if (!res)
+               return 0;
+       return res->numParameters;
+}
+
+/* PQparamtype:
+ *     returns type Oid of the specified statement parameter.
+ */
+Oid
+PQparamtype(const PGresult *res, int param_num)
+{
+       if (!check_param_number(res, param_num))
+               return InvalidOid;
+       if (res->paramDescs)
+               return res->paramDescs[param_num].typid;
+       else
+               return InvalidOid;
+}
+
+
 /* PQsetnonblocking:
  *     sets the PGconn's database connection non-blocking if the arg is TRUE
  *     or makes it non-blocking if the arg is FALSE, this will not protect
index 35f015ecce60f2b484f45d22c749340aafec7daa..a6abb062858322e22b663099498a560c53371c99 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.26 2006/03/14 22:48:23 tgl Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.27 2006/08/18 19:52:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,6 +45,7 @@
 
 static void handleSyncLoss(PGconn *conn, char id, int msgLength);
 static int     getRowDescriptions(PGconn *conn);
+static int     getParamDescriptions(PGconn *conn);
 static int     getAnotherTuple(PGconn *conn, int msgLength);
 static int     getParameterStatus(PGconn *conn);
 static int     getNotify(PGconn *conn);
@@ -263,11 +264,18 @@ pqParseInput3(PGconn *conn)
                                                return;
                                        break;
                                case 'T':               /* Row Description */
-                                       if (conn->result == NULL)
+                                       if (conn->result == NULL ||
+                                               conn->queryclass == PGQUERY_DESCRIBE)
                                        {
                                                /* First 'T' in a query sequence */
                                                if (getRowDescriptions(conn))
                                                        return;
+                                               /*
+                                                * If we're doing a Describe, we're ready to pass
+                                                * the result back to the client.
+                                                */
+                                               if (conn->queryclass == PGQUERY_DESCRIBE)
+                                                       conn->asyncStatus = PGASYNC_READY;
                                        }
                                        else
                                        {
@@ -293,6 +301,16 @@ pqParseInput3(PGconn *conn)
                                        if (conn->result == NULL)
                                                conn->result = PQmakeEmptyPGresult(conn,
                                                                                                                   PGRES_COMMAND_OK);
+                                       /*
+                                        * If we're doing a Describe, we're ready to pass
+                                        * the result back to the client.
+                                        */
+                                       if (conn->queryclass == PGQUERY_DESCRIBE)
+                                               conn->asyncStatus = PGASYNC_READY;
+                                       break;
+                               case 't':               /* Parameter Description */
+                                       if (getParamDescriptions(conn))
+                                               return;
                                        break;
                                case 'D':               /* Data Row */
                                        if (conn->result != NULL &&
@@ -409,7 +427,8 @@ handleSyncLoss(PGconn *conn, char id, int msgLength)
 
 /*
  * parseInput subroutine to read a 'T' (row descriptions) message.
- * We build a PGresult structure containing the attribute data.
+ * We'll build a new PGresult structure (unless called for a Describe
+ * command for a prepared statement) containing the attribute data.
  * Returns: 0 if completed message, EOF if not enough data yet.
  *
  * Note that if we run out of data, we have to release the partially
@@ -423,12 +442,25 @@ getRowDescriptions(PGconn *conn)
        int                     nfields;
        int                     i;
 
-       result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
+       /*
+        * When doing Describe for a prepared statement, there'll already be
+        * a PGresult created by getParamDescriptions, and we should fill
+        * data into that.  Otherwise, create a new, empty PGresult.
+        */
+       if (conn->queryclass == PGQUERY_DESCRIBE)
+       {
+               if (conn->result)
+                       result = conn->result;
+               else
+                       result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
+       }
+       else
+               result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
        if (!result)
                goto failure;
 
        /* parseInput already read the 'T' label and message length. */
-       /* the next two bytes are the number of fields  */
+       /* the next two bytes are the number of fields */
        if (pqGetInt(&(result->numAttributes), 2, conn))
                goto failure;
        nfields = result->numAttributes;
@@ -494,6 +526,71 @@ getRowDescriptions(PGconn *conn)
        conn->result = result;
        return 0;
 
+failure:
+       /*
+        * Discard incomplete result, unless it's from getParamDescriptions.
+        *
+        * Note that if we hit a bufferload boundary while handling the
+        * describe-statement case, we'll forget any PGresult space we just
+        * allocated, and then reallocate it on next try.  This will bloat
+        * the PGresult a little bit but the space will be freed at PQclear,
+        * so it doesn't seem worth trying to be smarter.
+        */
+       if (result != conn->result)
+               PQclear(result);
+       return EOF;
+}
+
+/*
+ * parseInput subroutine to read a 't' (ParameterDescription) message.
+ * We'll build a new PGresult structure containing the parameter data.
+ * Returns: 0 if completed message, EOF if not enough data yet.
+ *
+ * Note that if we run out of data, we have to release the partially
+ * constructed PGresult, and rebuild it again next time.  Fortunately,
+ * that shouldn't happen often, since 't' messages usually fit in a packet.
+ */
+static int
+getParamDescriptions(PGconn *conn)
+{
+       PGresult        *result;
+       int                      nparams;
+       int                      i;
+       
+       result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
+       if (!result)
+               goto failure;
+
+       /* parseInput already read the 't' label and message length. */
+       /* the next two bytes are the number of parameters */
+       if (pqGetInt(&(result->numParameters), 2, conn))
+               goto failure;
+       nparams = result->numParameters;
+
+       /* allocate space for the parameter descriptors */
+       if (nparams > 0)
+       {
+               result->paramDescs = (PGresParamDesc *)
+                       pqResultAlloc(result, nparams * sizeof(PGresParamDesc), TRUE);
+               if (!result->paramDescs)
+                       goto failure;
+               MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc));
+       }
+
+       /* get parameter info */
+       for (i = 0; i < nparams; i++)
+       {
+               int             typid;
+               
+               if (pqGetInt(&typid, 4, conn))
+                       goto failure;
+               result->paramDescs[i].typid = typid;
+       }
+
+       /* Success! */
+       conn->result = result;
+       return 0;
+
 failure:
        PQclear(result);
        return EOF;
index e2542c3a05ea74d9297463713ef89f70335326fb..26c0a104fb5d1250ab16eeba9221996286ef8ef2 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.131 2006/07/04 13:22:15 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.132 2006/08/18 19:52:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -406,6 +406,14 @@ extern char *PQcmdTuples(PGresult *res);
 extern char *PQgetvalue(const PGresult *res, int tup_num, int field_num);
 extern int     PQgetlength(const PGresult *res, int tup_num, int field_num);
 extern int     PQgetisnull(const PGresult *res, int tup_num, int field_num);
+extern int     PQnparams(const PGresult *res);
+extern Oid     PQparamtype(const PGresult *res, int param_num);
+
+/* Describe prepared statements and portals */
+extern PGresult        *PQdescribePrepared(PGconn *conn, const char *stmt);
+extern PGresult        *PQdescribePortal(PGconn *conn, const char *portal);
+extern int     PQsendDescribePrepared(PGconn *conn, const char *stmt);
+extern int     PQsendDescribePortal(PGconn *conn, const char *portal);
 
 /* Delete a PGresult */
 extern void PQclear(PGresult *res);
index 2c5f3f288bb2b6ac3fdc2a5fa31554e12ea90c4c..e3532fbf6f1f9f6eb4ab6c0a1b174e7268b1e7dc 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.114 2006/08/04 18:58:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.115 2006/08/18 19:52:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -94,6 +94,12 @@ typedef struct pgresAttDesc
        int                     atttypmod;              /* type-specific modifier info */
 } PGresAttDesc;
 
+/* Data about a single parameter of a prepared statement */
+typedef struct pgresParamDesc
+{
+       Oid                     typid;                  /* type id */
+} PGresParamDesc;
+
 /*
  * Data for a single attribute of a single tuple
  *
@@ -145,6 +151,8 @@ struct pg_result
        PGresAttValue **tuples;         /* each PGresTuple is an array of
                                                                 * PGresAttValue's */
        int                     tupArrSize;             /* allocated size of tuples array */
+       int                     numParameters;
+       PGresParamDesc *paramDescs;
        ExecStatusType resultStatus;
        char            cmdStatus[CMDSTATUS_LEN];               /* cmd status from the query */
        int                     binary;                 /* binary tuple values if binary == 1,
@@ -193,7 +201,8 @@ typedef enum
 {
        PGQUERY_SIMPLE,                         /* simple Query protocol (PQexec) */
        PGQUERY_EXTENDED,                       /* full Extended protocol (PQexecParams) */
-       PGQUERY_PREPARE                         /* Parse only (PQprepare) */
+       PGQUERY_PREPARE,                        /* Parse only (PQprepare) */
+       PGQUERY_DESCRIBE                        /* Describe Statement or Portal */
 } PGQueryClass;
 
 /* PGSetenvStatusType defines the state of the PQSetenv state machine */