mirror of
https://github.com/postgres/postgres.git
synced 2025-04-29 13:56:47 +03:00
Add PQdescribePrepared, PQdescribePortal, and related functions to libpq
to allow obtaining information about previously prepared statements and open cursors. Volkan Yazici
This commit is contained in:
parent
46d61eb218
commit
9a8920e1d7
@ -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">
|
<chapter id="libpq">
|
||||||
<title><application>libpq</application> - C Library</title>
|
<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
|
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
|
string. Also, the query may use parameter symbols with numbers higher than
|
||||||
<parameter>nParams</>; data types will be inferred for these symbols as
|
<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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -1255,13 +1256,6 @@ send the command at all.
|
|||||||
Use <function>PQerrorMessage</function> to get more information
|
Use <function>PQerrorMessage</function> to get more information
|
||||||
about such errors.
|
about such errors.
|
||||||
</para>
|
</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>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
@ -1315,6 +1309,72 @@ the prepared statement's parameter types were determined when it was created).
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@ -1707,8 +1767,11 @@ object, just as with a <structname>PGresult</structname> returned by
|
|||||||
These functions are used to extract information from a
|
These functions are used to extract information from a
|
||||||
<structname>PGresult</structname> object that represents a successful
|
<structname>PGresult</structname> object that represents a successful
|
||||||
query result (that is, one that has status
|
query result (that is, one that has status
|
||||||
<literal>PGRES_TUPLES_OK</literal>). For objects with other status
|
<literal>PGRES_TUPLES_OK</literal>). They can also be used to extract
|
||||||
values they will act as though the result has zero rows and zero columns.
|
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>
|
</para>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
@ -2040,6 +2103,43 @@ on <function>PQfsize</function> to obtain the actual data length.
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><function>PQprint</function><indexterm><primary>PQprint</></></term>
|
<term><function>PQprint</function><indexterm><primary>PQprint</></></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -2486,13 +2586,17 @@ underlying functions that <function>PQexec</function> is built from:
|
|||||||
<function>PQsendQuery</function> and <function>PQgetResult</function>.
|
<function>PQsendQuery</function> and <function>PQgetResult</function>.
|
||||||
There are also
|
There are also
|
||||||
<function>PQsendQueryParams</function>,
|
<function>PQsendQueryParams</function>,
|
||||||
<function>PQsendPrepare</function>, and
|
<function>PQsendPrepare</function>,
|
||||||
<function>PQsendQueryPrepared</function>,
|
<function>PQsendQueryPrepared</function>,
|
||||||
|
<function>PQsendDescribePrepared</function>, and
|
||||||
|
<function>PQsendDescribePortal</function>,
|
||||||
which can be used with <function>PQgetResult</function> to duplicate the
|
which can be used with <function>PQgetResult</function> to duplicate the
|
||||||
functionality of
|
functionality of
|
||||||
<function>PQexecParams</function>,
|
<function>PQexecParams</function>,
|
||||||
<function>PQprepare</function>, and
|
<function>PQprepare</function>,
|
||||||
<function>PQexecPrepared</function>
|
<function>PQexecPrepared</function>,
|
||||||
|
<function>PQdescribePrepared</function>, and
|
||||||
|
<function>PQdescribePortal</function>
|
||||||
respectively.
|
respectively.
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
@ -2598,6 +2702,50 @@ int PQsendQueryPrepared(PGconn *conn,
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><function>PQgetResult</function><indexterm><primary>PQgetResult</></></term>
|
<term><function>PQgetResult</function><indexterm><primary>PQgetResult</></></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -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
|
# Functions to be exported by libpq DLLs
|
||||||
PQconnectdb 1
|
PQconnectdb 1
|
||||||
PQsetdbLogin 2
|
PQsetdbLogin 2
|
||||||
@ -130,3 +130,9 @@ PQescapeByteaConn 127
|
|||||||
PQencryptPassword 128
|
PQencryptPassword 128
|
||||||
PQisthreadsafe 129
|
PQisthreadsafe 129
|
||||||
enlargePQExpBuffer 130
|
enlargePQExpBuffer 130
|
||||||
|
PQnparams 131
|
||||||
|
PQparamtype 132
|
||||||
|
PQdescribePrepared 133
|
||||||
|
PQdescribePortal 134
|
||||||
|
PQsendDescribePrepared 135
|
||||||
|
PQsendDescribePortal 136
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 void parseInput(PGconn *conn);
|
||||||
static bool PQexecStart(PGconn *conn);
|
static bool PQexecStart(PGconn *conn);
|
||||||
static PGresult *PQexecFinish(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->attDescs = NULL;
|
||||||
result->tuples = NULL;
|
result->tuples = NULL;
|
||||||
result->tupArrSize = 0;
|
result->tupArrSize = 0;
|
||||||
|
result->numParameters = 0;
|
||||||
|
result->paramDescs = NULL;
|
||||||
result->resultStatus = status;
|
result->resultStatus = status;
|
||||||
result->cmdStatus[0] = '\0';
|
result->cmdStatus[0] = '\0';
|
||||||
result->binary = 0;
|
result->binary = 0;
|
||||||
@ -367,6 +371,7 @@ PQclear(PGresult *res)
|
|||||||
/* zero out the pointer fields to catch programming errors */
|
/* zero out the pointer fields to catch programming errors */
|
||||||
res->attDescs = NULL;
|
res->attDescs = NULL;
|
||||||
res->tuples = NULL;
|
res->tuples = NULL;
|
||||||
|
res->paramDescs = NULL;
|
||||||
res->errFields = NULL;
|
res->errFields = NULL;
|
||||||
/* res->curBlock was zeroed out earlier */
|
/* res->curBlock was zeroed out earlier */
|
||||||
|
|
||||||
@ -1471,6 +1476,139 @@ PQexecFinish(PGconn *conn)
|
|||||||
return lastResult;
|
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
|
* PQnotifies
|
||||||
* returns a PGnotify* structure of the latest async notification
|
* returns a PGnotify* structure of the latest async notification
|
||||||
@ -1984,6 +2122,22 @@ check_tuple_field_number(const PGresult *res,
|
|||||||
return TRUE;
|
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
|
* returns NULL if the field_num is invalid
|
||||||
*/
|
*/
|
||||||
@ -2307,6 +2461,32 @@ PQgetisnull(const PGresult *res, int tup_num, int field_num)
|
|||||||
return 0;
|
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:
|
/* PQsetnonblocking:
|
||||||
* sets the PGconn's database connection non-blocking if the arg is TRUE
|
* 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
|
* or makes it non-blocking if the arg is FALSE, this will not protect
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 void handleSyncLoss(PGconn *conn, char id, int msgLength);
|
||||||
static int getRowDescriptions(PGconn *conn);
|
static int getRowDescriptions(PGconn *conn);
|
||||||
|
static int getParamDescriptions(PGconn *conn);
|
||||||
static int getAnotherTuple(PGconn *conn, int msgLength);
|
static int getAnotherTuple(PGconn *conn, int msgLength);
|
||||||
static int getParameterStatus(PGconn *conn);
|
static int getParameterStatus(PGconn *conn);
|
||||||
static int getNotify(PGconn *conn);
|
static int getNotify(PGconn *conn);
|
||||||
@ -263,11 +264,18 @@ pqParseInput3(PGconn *conn)
|
|||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
case 'T': /* Row Description */
|
case 'T': /* Row Description */
|
||||||
if (conn->result == NULL)
|
if (conn->result == NULL ||
|
||||||
|
conn->queryclass == PGQUERY_DESCRIBE)
|
||||||
{
|
{
|
||||||
/* First 'T' in a query sequence */
|
/* First 'T' in a query sequence */
|
||||||
if (getRowDescriptions(conn))
|
if (getRowDescriptions(conn))
|
||||||
return;
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -293,6 +301,16 @@ pqParseInput3(PGconn *conn)
|
|||||||
if (conn->result == NULL)
|
if (conn->result == NULL)
|
||||||
conn->result = PQmakeEmptyPGresult(conn,
|
conn->result = PQmakeEmptyPGresult(conn,
|
||||||
PGRES_COMMAND_OK);
|
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;
|
break;
|
||||||
case 'D': /* Data Row */
|
case 'D': /* Data Row */
|
||||||
if (conn->result != NULL &&
|
if (conn->result != NULL &&
|
||||||
@ -409,7 +427,8 @@ handleSyncLoss(PGconn *conn, char id, int msgLength)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* parseInput subroutine to read a 'T' (row descriptions) message.
|
* 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.
|
* 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
|
* Note that if we run out of data, we have to release the partially
|
||||||
@ -423,12 +442,25 @@ getRowDescriptions(PGconn *conn)
|
|||||||
int nfields;
|
int nfields;
|
||||||
int i;
|
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)
|
if (!result)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
/* parseInput already read the 'T' label and message length. */
|
/* 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))
|
if (pqGetInt(&(result->numAttributes), 2, conn))
|
||||||
goto failure;
|
goto failure;
|
||||||
nfields = result->numAttributes;
|
nfields = result->numAttributes;
|
||||||
@ -494,6 +526,71 @@ getRowDescriptions(PGconn *conn)
|
|||||||
conn->result = result;
|
conn->result = result;
|
||||||
return 0;
|
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:
|
failure:
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
return EOF;
|
return EOF;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 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 PQgetlength(const PGresult *res, int tup_num, int field_num);
|
||||||
extern int PQgetisnull(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 */
|
/* Delete a PGresult */
|
||||||
extern void PQclear(PGresult *res);
|
extern void PQclear(PGresult *res);
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 */
|
int atttypmod; /* type-specific modifier info */
|
||||||
} PGresAttDesc;
|
} 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
|
* 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 **tuples; /* each PGresTuple is an array of
|
||||||
* PGresAttValue's */
|
* PGresAttValue's */
|
||||||
int tupArrSize; /* allocated size of tuples array */
|
int tupArrSize; /* allocated size of tuples array */
|
||||||
|
int numParameters;
|
||||||
|
PGresParamDesc *paramDescs;
|
||||||
ExecStatusType resultStatus;
|
ExecStatusType resultStatus;
|
||||||
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the query */
|
char cmdStatus[CMDSTATUS_LEN]; /* cmd status from the query */
|
||||||
int binary; /* binary tuple values if binary == 1,
|
int binary; /* binary tuple values if binary == 1,
|
||||||
@ -193,7 +201,8 @@ typedef enum
|
|||||||
{
|
{
|
||||||
PGQUERY_SIMPLE, /* simple Query protocol (PQexec) */
|
PGQUERY_SIMPLE, /* simple Query protocol (PQexec) */
|
||||||
PGQUERY_EXTENDED, /* full Extended protocol (PQexecParams) */
|
PGQUERY_EXTENDED, /* full Extended protocol (PQexecParams) */
|
||||||
PGQUERY_PREPARE /* Parse only (PQprepare) */
|
PGQUERY_PREPARE, /* Parse only (PQprepare) */
|
||||||
|
PGQUERY_DESCRIBE /* Describe Statement or Portal */
|
||||||
} PGQueryClass;
|
} PGQueryClass;
|
||||||
|
|
||||||
/* PGSetenvStatusType defines the state of the PQSetenv state machine */
|
/* PGSetenvStatusType defines the state of the PQSetenv state machine */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user