Re: Prepared select - Mailing list pgsql-hackers
From | Cyril VELTER |
---|---|
Subject | Re: Prepared select |
Date | |
Msg-id | 062c01c426e8$62255b20$f901a8c0@cvfixe Whole thread Raw |
In response to | Re: Prepared select (Christoph Haller <ch@rodos.fzk.de>) |
List | pgsql-hackers |
libpq doesn't have enought support to allow executing a prepared statement in a named portal (current libpq only works wuth the unnamed portal). But the V3 protocol have it. I solved this problem by adding the following functions. They let you prepare a named statement, execute this statement in a named portal, fetch from it and close it. this is a temporary solution to wait for an official extension of libpq (more call could be added to support completly the V3 protocol). cyril /** PQportalSetup* Setup a portal to execute a prepared statement*/ PGresult * PQportalSetup(PGconn *conn, const char *stmtName, const char *portalName, int nParams, const char *const* paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) {int i; if (!PQexecStart(conn)) return NULL; if (!PQsendQueryStart(conn)) return NULL; if (!stmtName){ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("statement name is a null pointer\n")); returnNULL;} /* 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 Bind message */if (pqPutMsgStart('B', false, conn) < 0 || pqPuts(portalName, conn) < 0 || pqPuts(stmtName,conn) < 0) goto sendFailed;if (nParams > 0 && paramFormats){ if (pqPutInt(nParams, 2, conn) < 0) goto sendFailed;for (i = 0; i < nParams; i++) { if (pqPutInt(paramFormats[i], 2, conn) < 0) goto sendFailed; }}else{ if (pqPutInt(0,2, conn) < 0) goto sendFailed;}if (pqPutInt(nParams, 2, conn) < 0) goto sendFailed;for (i = 0; i < nParams;i++){ if (paramValues && paramValues[i]) { int nbytes; if (paramFormats && paramFormats[i] != 0) { /* binary parameter */ nbytes = paramLengths[i]; } else { /* textparameter, do not use paramLengths */ nbytes = strlen(paramValues[i]); } if (pqPutInt(nbytes, 4, conn) < 0 || pqPutnchar(paramValues[i],nbytes, conn) < 0) goto sendFailed; } else { /* take the param as NULL */ if (pqPutInt(-1,4, conn) < 0) goto sendFailed; }}if (pqPutInt(1, 2, conn) < 0 || pqPutInt(resultFormat, 2, conn)) 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 using extended query protocol */conn->ext_query = true; /* * Give the data a push. In nonblock mode, don't complain if we're * unable to send it all; PQgetResult() will do anyadditional * flushing needed. */if (pqFlush(conn) < 0) goto sendFailed; /* OK, it's launched! */conn->asyncStatus = PGASYNC_BUSY; return PQexecFinish(conn); sendFailed:pqHandleSendFailure(conn);return NULL; } /** PQportalFetch* Fetch next rows*/ PGresult * PQportalFetch(PGconn *conn, const char *portalName, int maxrows) {if (!PQexecStart(conn)) return NULL; if (!PQsendQueryStart(conn)) return NULL; /* 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 Portal message */if (pqPutMsgStart('D', false, conn) < 0 || pqPutc('P', conn) < 0 || pqPuts(portalName,conn) < 0 || pqPutMsgEnd(conn) < 0) goto sendFailed; /* construct the Execute message */if (pqPutMsgStart('E', false, conn) < 0 || pqPuts(portalName, conn) < 0 || pqPutInt(maxrows,4, 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 using extended query protocol */conn->ext_query = true; /* * Give the data a push. In nonblock mode, don't complain if we're * unable to send it all; PQgetResult() will do anyadditional * flushing needed. */if (pqFlush(conn) < 0) goto sendFailed; /* OK, it's launched! */conn->asyncStatus = PGASYNC_BUSY;return PQexecFinish(conn); sendFailed:pqHandleSendFailure(conn);return NULL; } /** PQportalClose* Close a named portal* using protocol 3.0*/ PGresult * PQportalClose(PGconn *conn, const char *portalName) {if (!PQexecStart(conn)) return NULL; if (!PQsendQueryStart(conn)) return NULL; /* 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 Close message */if (pqPutMsgStart('C', false, conn) < 0 || pqPutc('P', conn) < 0 || pqPuts(portalName, 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 using extended query protocol */conn->ext_query = true; /* * Give the data a push. In nonblock mode, don't complain if we're * unable to send it all; PQgetResult() will do anyadditional * flushing needed. */if (pqFlush(conn) < 0) goto sendFailed; /* OK, it's launched! */conn->asyncStatus = PGASYNC_BUSY;return PQexecFinish(conn); sendFailed:pqHandleSendFailure(conn);return NULL; } ----- Original Message ----- From: "Robert Turnbull" <rturnbull@strategicmind.com> To: "Christoph Haller" <ch@rodos.fzk.de> Cc: <pgsql-hackers@postgresql.org> Sent: Monday, April 19, 2004 2:48 AM Subject: Re: [HACKERS] Prepared select > There are several production issues related to the proposed solution. For > example, what happens when the result set exceeds the swap space of the > server or client machine? My original question is how to get a cursor from a > prepared select so a subset of the result can be returned to the client for > processing. For your solution to work the SQL EXECUTE command needs the > functionality of the SQL FETCH command. > > > > > > > > > > > How can I use a prepared select statement as mentioned in the > documentation= > > > on SQL PREPARE. Preparing the statement is easy, the problem is using > the = > > > plan to get a cursor. My assumption is the SQL OPEN command is not > document= > > > ed or there is some other libpq API to make this happen. > > > > > > Thanks > > > > > > > > > > > I'm using libpq and lines like below are working: > > > > res = PQexec(conn, > > "PREPARE plan001 ( integer , double precision , character ) AS SELECT > a,b,d FROM foo WHERE a = $1 OR d > $2 OR b = $3"); > > ... > > res = PQexec(conn, "EXECUTE plan001 ( 3 , 6.66 , 'whatever' ) "); > > > > HTH, pretty late reply - I know (but no one else did as far as I can tell) > > > > Regards, Christoph > > > > > > > > > ---------------------------(end of broadcast)--------------------------- > TIP 8: explain analyze is your friend >
pgsql-hackers by date: