Prepared select

Lists: pgsql-hackers
From: "Robert Turnbull" <rturnbull(at)strategicmind(dot)com>
To: <pgsql-hackers(at)postgresql(dot)org>
Subject: Prepared select
Date: 2004-04-02 17:43:38
Message-ID: 005101c418da$07e0b2c0$6f64a8c0@robert
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

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 documented or there is some other libpq API to make this happen.

Thanks


From: Christoph Haller <ch(at)rodos(dot)fzk(dot)de>
To: rturnbull(at)strategicmind(dot)com
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: Prepared select
Date: 2004-04-14 11:16:47
Message-ID: 200404140916.LAA20164@rodos
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

>
>
> 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


From: "Robert Turnbull" <rturnbull(at)strategicmind(dot)com>
To: "Christoph Haller" <ch(at)rodos(dot)fzk(dot)de>
Cc: <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Prepared select
Date: 2004-04-19 00:48:16
Message-ID: 002b01c425a8$009d78b0$7e02a8c0@robert
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

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
>
>
>


From: "Cyril VELTER" <cyril(dot)velter(at)metadys(dot)com>
To: "Robert Turnbull" <rturnbull(at)strategicmind(dot)com>
Cc: <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Prepared select
Date: 2004-04-20 15:01:38
Message-ID: 062c01c426e8$62255b20$f901a8c0@cvfixe
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: 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"));
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 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
{
/* text parameter, 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 any additional
* 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 any additional
* 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 any additional
* 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(at)strategicmind(dot)com>
To: "Christoph Haller" <ch(at)rodos(dot)fzk(dot)de>
Cc: <pgsql-hackers(at)postgresql(dot)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
>