Unix Technical Forum

BUG #3244: problem with PREPARE

This is a discussion on BUG #3244: problem with PREPARE within the pgsql Bugs forums, part of the PostgreSQL category; --> The following bug has been logged online: Bug reference: 3244 Logged by: William Lawrance Email address: bill.lawrance@bull.com PostgreSQL version: ...


Go Back   Unix Technical Forum > Database Server Software > PostgreSQL > pgsql Bugs

Register FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 04-10-2008, 10:43 AM
William Lawrance
 
Posts: n/a
Default BUG #3244: problem with PREPARE


The following bug has been logged online:

Bug reference: 3244
Logged by: William Lawrance
Email address: bill.lawrance@bull.com
PostgreSQL version: cvs HEAD
Operating system: Linux
Description: problem with PREPARE
Details:

This program that does "PQprepare" and then
"PQexecPrepared" has worked previously, but doesn't
work now. The error message is"

ERROR: bind message supplies 1 parameters, but
prepared statement "stmtopen" requires 0



The table is defined with 1 row of content:

create table tprep ( cola character(3) );
insert into tprep values('aaa');





#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "libpq-fe.h"

int pg_beginTx(PGconn *conn);
int pg_displayResRows(PGresult *res);
int pg_commit(PGconn *conn);

/***********************************************
* main
***********************************************/
int main(int argc, char **argv)
{
PGconn *conn;
PGresult *res;
long resultSts;
const char *conninfo;
char openStmt[100];
const char *paramValues[10];
char p1str[10];

//--- connect to the database
conninfo = "dbname = test";
conn = PQconnectdb(conninfo);
if(PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, "Connection to database failed\n");
fprintf(stderr, " %s\n", PQerrorMessage(conn));
exit(1);
}

//--- begin transaction
pg_beginTx(conn);

//--- prepare the declare/open statement
strcpy(openStmt, "declare C1 cursor for select cola"
" from tprep"
" where cola = $1");
res = PQprepare(conn, "stmtopen", openStmt, 0, 0);
resultSts = PQresultStatus(res);
if(resultSts != PGRES_COMMAND_OK)
{
fprintf(stderr, "**** error preparing stmt, sts = %ld\n",
resultSts);
fprintf(stderr, "prepare OPEN failed: %s\n", PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(1);
}
PQclear(res);

//---- execute the declare/open statement
strcpy(p1str, "aaa"); paramValues[0] = p1str;
res = PQexecPrepared(conn, "stmtopen", 1, paramValues,
NULL, /* don't need param lengths since text */
NULL, /* default to all text params */
0); /* ask for text results */
resultSts = PQresultStatus(res);
if(resultSts != PGRES_COMMAND_OK)
{
fprintf(stderr, "**** error executing prepared statement, sts =
%ld\n", resultSts);
fprintf(stderr, " %s\n", PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(1);
}
PQclear(res);

//---- fetch
res = PQexecParams(conn, "FETCH C1",
0, /* 0 params */
0,
paramValues,
NULL,
NULL,
0);
resultSts = PQresultStatus(res);
if(resultSts != PGRES_TUPLES_OK)
{
fprintf(stderr, "**** error FETCHing\n");
fprintf(stderr, "resultSts = %ld\n", resultSts);
fprintf(stderr, " %s\n", PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(1);
}

pg_displayResRows(res);
PQclear(res);

//---- close cursor
res = PQexecParams(conn, "CLOSE C1",
0, /* 0 params */
0,
paramValues,
NULL,
NULL,
0);
resultSts = PQresultStatus(res);
if(resultSts != PGRES_COMMAND_OK)
{
fprintf(stderr, "**** error CLOSEing\n");
fprintf(stderr, "resultSts = %ld\n", resultSts);
fprintf(stderr, " %s\n", PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(1);
}

//---- commit
pg_commit(conn);

//---- disconnect
PQfinish(conn);

//---- done
exit(0);
}

/***********************************************
* display result rows
***********************************************/
int pg_displayResRows(PGresult *res)
{
int noTuples, rowNo, noCols, colNo, colType, colLeng;
long tblOID, colFormat;
char *colName, *colValue;

noTuples = PQntuples(res);
noCols = PQnfields(res);

for(colNo = 0; colNo < noCols; ++colNo)
{
colName = PQfname(res, colNo);
tblOID = PQftable(res, colNo);
colFormat = PQfformat(res, colNo);
colType = PQftype(res, colNo);
}

for(rowNo = 0; rowNo < noTuples; ++rowNo)
{
printf(" #%d --------\n", rowNo);

for(colNo = 0; colNo < noCols; ++colNo)
{
colValue = PQgetvalue(res, rowNo, colNo);
colLeng = PQgetlength(res, rowNo, colNo);
printf(" name=%s, leng=%d, value='%s'\n", colName, colLeng,
colValue);
}
}
return(0);
}

/***********************************************
* begin transaction
***********************************************/
int pg_beginTx(PGconn *conn)
{
PGresult *res;

res = PQexecParams(conn, "BEGIN",
0, /* no params */
NULL, /* let the backend deduce param
type */
0,
NULL, /* don't need param lengths since
text */
NULL, /* default to all text params */
0); /* ask for text results */
if(PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "BEGIN failed: %s", PQerrorMessage(conn));
PQclear(res);
exit(1);
}
PQclear(res);
return(0);
}

/***********************************************
* commit transaction
***********************************************/
int pg_commit(PGconn *conn)
{
PGresult *res;

res = PQexecParams(conn, "COMMIT",
0, /* no params */
NULL, /* let the backend deduce param
type */
0,
NULL, /* don't need param lengths since
text */
NULL, /* default to all text params */
0); /* ask for text results */
if(PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "COMMIT failed: %s", PQerrorMessage(conn));
PQclear(res);
exit(1);
}
PQclear(res);
return(0);
}

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
choose an index scan if your joining column's datatypes do not
match

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #2 (permalink)  
Old 04-10-2008, 10:44 AM
Tom Lane
 
Posts: n/a
Default Re: BUG #3244: problem with PREPARE

"William Lawrance" <bill.lawrance@bull.com> writes:
> This program that does "PQprepare" and then
> "PQexecPrepared" has worked previously, but doesn't
> work now.
> ...
> strcpy(openStmt, "declare C1 cursor for select cola"
> " from tprep"
> " where cola = $1");
> res = PQprepare(conn, "stmtopen", openStmt, 0, 0);


I looked into this a bit and found that the issue comes from my recent
changes in support of plan caching. To simplify matters, I instituted
a rule that utility statements don't have any interesting
transformations done at parse analysis time; see this new comment in
analyze.c:

* For optimizable statements, we are careful to obtain a suitable lock on
* each referenced table, and other modules of the backend preserve or
* re-obtain these locks before depending on the results. It is therefore
* okay to do significant semantic analysis of these statements. For
* utility commands, no locks are obtained here (and if they were, we could
* not be sure we'd still have them at execution). Hence the general rule
* for utility commands is to just dump them into a Query node untransformed.
* parse_analyze does do some purely syntactic transformations on CREATE TABLE
* and ALTER TABLE, but that's about it. In cases where this module contains
* mechanisms that are useful for utility statements, we provide separate
* subroutines that should be called at the beginning of utility execution;
* an example is analyzeIndexStmt.

This means that "preparing" a DECLARE CURSOR is now effectively a no-op;
it doesn't do much more than detect basic syntax errors that the Bison
grammar can catch. If you run this program without having created
the tprep table, the PQprepare doesn't fail! But the bigger problem,
at least for Bill's complaint, is that we also don't notice, let alone
assign datatypes to, any parameter symbols appearing in the query.

I don't see any particular problem in this for the other command types
that had their analyze-time processing removed; there's no value in a
parameter in CREATE VIEW, for example. But evidently there's some
interest in having parameters in prepared DECLARE CURSOR commands.

The easiest answer I can think of at the moment is to run parse analysis
for a DECLARE CURSOR and then throw away the result. To avoid this
overhead in cases where it's useless, we could probably teach analyze.c
to do it only if p_variableparams is true (which essentially would mean
that the DECLARE CURSOR came in via PQprepare or equivalent, and not as
a simply executable statement).

Plan B would be to promote DECLARE CURSOR to an "optimizable statement"
that is treated under the same rules as SELECT/UPDATE/etc, in particular
that we assume locks obtained at analysis are held through to execution.
This might be a cleaner answer overall, but I have no idea right now
about the effort required or any possible downsides.

Comments, better ideas?

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 7: You can help support the PostgreSQL project by donating at

http://www.postgresql.org/about/donate

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #3 (permalink)  
Old 04-10-2008, 10:45 AM
Michael Meskes
 
Posts: n/a
Default Re: [HACKERS] BUG #3244: problem with PREPARE

On Mon, Apr 23, 2007 at 02:02:04PM -0700, William Lawrance wrote:
> Our first attempt to use the ECPG prepare interface revealed that ECPG
> doesn't use the PQlib prepare function. The ECPG prepare replaces any
> parameters with their values and presents a new SQL statement to the


This is true and should also be documented. The reason for this
behaviour is simply that ECPG prepare feature was added before the
backend had its own prepare feature. And no one changed it so far.

> There are several difficulties to be encountered when attempting to use
> this within a program using the ECPG interface. For example, the
> connection structure for PQlib isn't readily available, and the
> transaction semantics must be synchronized with ECPG's state. This did
> work, but it was fairly clumsy.


Right, that's what makes it non trivial.

> Since we wanted to do this in a cleaner manner, and also wished to avoid
> changing the applications if possible, we used the following approach:
>
> Within the "execute.c" module, we added routines to manage a cache
> of prepared statements. These routines are able to search, insert,
> and delete entries in the cache. The key for these cache entries is
> the text of the SQL statement as passed by ECPG from the application
> program.
>
> Within the same module, we replaced the "ECPGexecute" function.
> This is the function that is called to execute a statement after
> some preliminary housekeeping is done. The original "ECPGexecute"
> function constructs an ASCII string by replacing each host variable
> with its current value and then calling "PQexec". The new
> "ECPGexecute" function does the following:
>
> - build an array of the current values of the host variables.
>
> - search the cache for an entry indicating that this statement
> has already been prepare'd, via "PQprepare"
>
> - If no entry was found in the previous step, call "PQprepare"
> for the statement and then insert an entry for it into the
> cache. If this requires an entry to be re-used, execute a
> "DEALLOCATE PREPARE.." for the previous contents.
>
> - At this point, the SQL statement has been prepare'd by PQlib,
> either when the statement was executed in the past, or in
> the previous step.
>
> - call "PQexecPrepared", using the array of parameters built
> in the first step above.


Does this mean you prepare ALL statements? Or where you only talking
about statements that are prepared in the application?

Michael
--
Michael Meskes
Email: Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
ICQ: 179140304, AIM/Yahoo: michaelmeskes, Jabber: meskes@jabber.org
Go SF 49ers! Go Rhein Fire! Use Debian GNU/Linux! Use PostgreSQL!

---------------------------(end of broadcast)---------------------------
TIP 7: You can help support the PostgreSQL project by donating at

http://www.postgresql.org/about/donate

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #4 (permalink)  
Old 04-10-2008, 10:45 AM
Bruce Momjian
 
Posts: n/a
Default Re: [HACKERS] BUG #3244: problem with PREPARE

Michael Meskes wrote:
> On Mon, Apr 23, 2007 at 02:02:04PM -0700, William Lawrance wrote:
> > Our first attempt to use the ECPG prepare interface revealed that ECPG
> > doesn't use the PQlib prepare function. The ECPG prepare replaces any
> > parameters with their values and presents a new SQL statement to the

>
> This is true and should also be documented. The reason for this
> behaviour is simply that ECPG prepare feature was added before the
> backend had its own prepare feature. And no one changed it so far.


It is in the TODO:

o Use backend PREPARE/EXECUTE facility for ecpg where possible

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://www.enterprisedb.com

+ If your life is a hard drive, Christ can be your backup. +

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

http://www.postgresql.org/docs/faq

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #5 (permalink)  
Old 04-10-2008, 10:46 AM
Tom Lane
 
Posts: n/a
Default Re: BUG #3244: problem with PREPARE

"William Lawrance" <bill.lawrance@bull.com> writes:
> This program that does "PQprepare" and then
> "PQexecPrepared" has worked previously, but doesn't
> work now. The error message is"
> ERROR: bind message supplies 1 parameters, but
> prepared statement "stmtopen" requires 0


I've applied a patch for this. Thanks for the report.

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 01:01 AM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0
www.UnixAdminTalk.com