mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Add PQprepare/PQsendPrepared functions to libpq to support preparing
statements without necessarily specifying the datatypes of their parameters. Abhijit Menon-Sen with some help from Tom Lane.
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.2 2004/10/18 22:00:42 tgl Exp $
|
||||
# Functions to be exported by libpq DLLs
|
||||
PQconnectdb 1
|
||||
PQsetdbLogin 2
|
||||
@ -116,3 +117,5 @@ PQgetssl 114
|
||||
pg_char_to_encoding 115
|
||||
pg_valid_server_encoding 116
|
||||
pqsignal 117
|
||||
PQprepare 118
|
||||
PQsendPrepare 119
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.163 2004/10/16 22:52:53 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.164 2004/10/18 22:00:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -664,7 +664,7 @@ PQsendQuery(PGconn *conn, const char *query)
|
||||
}
|
||||
|
||||
/* remember we are using simple query protocol */
|
||||
conn->ext_query = false;
|
||||
conn->queryclass = PGQUERY_SIMPLE;
|
||||
|
||||
/*
|
||||
* Give the data a push. In nonblock mode, don't complain if we're
|
||||
@ -717,6 +717,94 @@ PQsendQueryParams(PGconn *conn,
|
||||
resultFormat);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (!PQsendQueryStart(conn))
|
||||
return 0;
|
||||
|
||||
if (!stmtName)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("statement name is a null pointer\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!query)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("command string is a null pointer\n"));
|
||||
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 Parse message */
|
||||
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;
|
||||
|
||||
/* construct the Sync message */
|
||||
if (pqPutMsgStart('S', false, conn) < 0 ||
|
||||
pqPutMsgEnd(conn) < 0)
|
||||
goto sendFailed;
|
||||
|
||||
/* remember we are doing just a Parse */
|
||||
conn->queryclass = PGQUERY_PREPARE;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* PQsendQueryPrepared
|
||||
* Like PQsendQuery, but execute a previously prepared statement,
|
||||
@ -921,7 +1009,7 @@ PQsendQueryGuts(PGconn *conn,
|
||||
goto sendFailed;
|
||||
|
||||
/* remember we are using extended query protocol */
|
||||
conn->ext_query = true;
|
||||
conn->queryclass = PGQUERY_EXTENDED;
|
||||
|
||||
/*
|
||||
* Give the data a push. In nonblock mode, don't complain if we're
|
||||
@ -1134,7 +1222,6 @@ PQgetResult(PGconn *conn)
|
||||
* The user is responsible for freeing the PGresult via PQclear()
|
||||
* when done with it.
|
||||
*/
|
||||
|
||||
PGresult *
|
||||
PQexec(PGconn *conn, const char *query)
|
||||
{
|
||||
@ -1168,6 +1255,29 @@ PQexecParams(PGconn *conn,
|
||||
return PQexecFinish(conn);
|
||||
}
|
||||
|
||||
/*
|
||||
* PQprepare
|
||||
* Creates a prepared statement by issuing a v3.0 parse message.
|
||||
*
|
||||
* 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).
|
||||
* The user is responsible for freeing the PGresult via PQclear()
|
||||
* when done with it.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* PQexecPrepared
|
||||
* Like PQexec, but execute a previously prepared statement,
|
||||
@ -1451,7 +1561,7 @@ PQputCopyEnd(PGconn *conn, const char *errormsg)
|
||||
* If we sent the COPY command in extended-query mode, we must
|
||||
* issue a Sync as well.
|
||||
*/
|
||||
if (conn->ext_query)
|
||||
if (conn->queryclass != PGQUERY_SIMPLE)
|
||||
{
|
||||
if (pqPutMsgStart('S', false, conn) < 0 ||
|
||||
pqPutMsgEnd(conn) < 0)
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.18 2004/10/16 22:52:54 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.19 2004/10/18 22:00:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -220,6 +220,15 @@ pqParseInput3(PGconn *conn)
|
||||
conn->asyncStatus = PGASYNC_READY;
|
||||
break;
|
||||
case '1': /* Parse Complete */
|
||||
/* If we're doing PQprepare, we're done; else ignore */
|
||||
if (conn->queryclass == PGQUERY_PREPARE)
|
||||
{
|
||||
if (conn->result == NULL)
|
||||
conn->result = PQmakeEmptyPGresult(conn,
|
||||
PGRES_COMMAND_OK);
|
||||
conn->asyncStatus = PGASYNC_READY;
|
||||
}
|
||||
break;
|
||||
case '2': /* Bind Complete */
|
||||
case '3': /* Close Complete */
|
||||
/* Nothing to do for these message types */
|
||||
@ -1118,7 +1127,7 @@ pqEndcopy3(PGconn *conn)
|
||||
* If we sent the COPY command in extended-query mode, we must
|
||||
* issue a Sync as well.
|
||||
*/
|
||||
if (conn->ext_query)
|
||||
if (conn->queryclass != PGQUERY_SIMPLE)
|
||||
{
|
||||
if (pqPutMsgStart('S', false, conn) < 0 ||
|
||||
pqPutMsgEnd(conn) < 0)
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.111 2004/10/16 22:52:55 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.112 2004/10/18 22:00:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -304,6 +304,9 @@ extern PGresult *PQexecParams(PGconn *conn,
|
||||
const int *paramLengths,
|
||||
const int *paramFormats,
|
||||
int resultFormat);
|
||||
extern PGresult *PQprepare(PGconn *conn, const char *stmtName,
|
||||
const char *query, int nParams,
|
||||
const Oid *paramTypes);
|
||||
extern PGresult *PQexecPrepared(PGconn *conn,
|
||||
const char *stmtName,
|
||||
int nParams,
|
||||
@ -322,6 +325,9 @@ extern int PQsendQueryParams(PGconn *conn,
|
||||
const int *paramLengths,
|
||||
const int *paramFormats,
|
||||
int resultFormat);
|
||||
extern int PQsendPrepare(PGconn *conn, const char *stmtName,
|
||||
const char *query, int nParams,
|
||||
const Oid *paramTypes);
|
||||
extern int PQsendQueryPrepared(PGconn *conn,
|
||||
const char *stmtName,
|
||||
int nParams,
|
||||
|
@ -12,7 +12,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.94 2004/10/16 22:52:55 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.95 2004/10/18 22:00:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -185,6 +185,14 @@ typedef enum
|
||||
PGASYNC_COPY_OUT /* Copy Out data transfer in progress */
|
||||
} PGAsyncStatusType;
|
||||
|
||||
/* PGQueryClass tracks which query protocol we are now executing */
|
||||
typedef enum
|
||||
{
|
||||
PGQUERY_SIMPLE, /* simple Query protocol (PQexec) */
|
||||
PGQUERY_EXTENDED, /* full Extended protocol (PQexecParams) */
|
||||
PGQUERY_PREPARE /* Parse only (PQprepare) */
|
||||
} PGQueryClass;
|
||||
|
||||
/* PGSetenvStatusType defines the state of the PQSetenv state machine */
|
||||
/* (this is used only for 2.0-protocol connections) */
|
||||
typedef enum
|
||||
@ -264,10 +272,9 @@ struct pg_conn
|
||||
PGAsyncStatusType asyncStatus;
|
||||
PGTransactionStatusType xactStatus;
|
||||
/* note: xactStatus never changes to ACTIVE */
|
||||
PGQueryClass queryclass;
|
||||
bool nonblocking; /* whether this connection is using
|
||||
* nonblock sending semantics */
|
||||
bool ext_query; /* was our last query sent with extended
|
||||
* query protocol? */
|
||||
char copy_is_binary; /* 1 = copy binary, 0 = copy text */
|
||||
int copy_already_done; /* # bytes already returned in
|
||||
* COPY OUT */
|
||||
|
Reference in New Issue
Block a user