Thread: Executing prepared statements via bind params

Executing prepared statements via bind params

From
Peter Bex
Date:
Hi all,

I'm seeing a bit strange (some might say inconsistent) behaviour,
possibly a bug.

First, I prepare a statement by running the query:

   "PREPARE bar (int) AS (SELECT 1, $1, 3)"

Then I try to use the generic libpq query function PQsendQueryParams
with a query of "EXECUTE bar(2)" and I get back a result set with one
record (1, 2, 3) in it.  This is fine.

But when I try to do the same but pas the 2 as a parameter,
(I do "EXECUTE bar($1)" with $1 bound to "2"), I get an error:

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

This doesn't make much sense to me.  It's the same error you get when
trying to run a nonparameterized query like "SELECT 1" with $1 bound to
anything.

Does the query parser somehow miss the fact that there's a placeholder
in the EXECUTE statement?

I'm attempting to keep my Scheme library's API as small and simple as
possible, so I'd like to avoid having a separate procedure for querying
and one for executing prepared statements, considering there's also an
SQL command for executing prepared statements.  Is there a particular
reason there are separate functions in libpq (aside from historical
accident)?

Cheers,
Peter
--
http://sjamaan.ath.cx
--
"The process of preparing programs for a digital computer
 is especially attractive, not only because it can be economically
 and scientifically rewarding, but also because it can be an aesthetic
 experience much like composing poetry or music."
                            -- Donald Knuth

Re: Executing prepared statements via bind params

From
Tom Lane
Date:
Peter Bex <Peter.Bex@xs4all.nl> writes:
> But when I try to do the same but pas the 2 as a parameter,
> (I do "EXECUTE bar($1)" with $1 bound to "2"), I get an error:

Why would you do that, rather than executing the prepared statement
directly with PQexecPrepared?  Interposing an EXECUTE doesn't do
anything but add parsing overhead.

The reason this particular case doesn't work is that utility statements
(including EXECUTE) don't have any support for $n parameters.

            regards, tom lane

Re: Executing prepared statements via bind params

From
Peter Bex
Date:
On Thu, Jun 16, 2011 at 05:19:41PM -0400, Tom Lane wrote:
> Peter Bex <Peter.Bex@xs4all.nl> writes:
> > But when I try to do the same but pas the 2 as a parameter,
> > (I do "EXECUTE bar($1)" with $1 bound to "2"), I get an error:
>
> Why would you do that, rather than executing the prepared statement
> directly with PQexecPrepared?

I'm writing a Scheme language binding and currently I simply don't have
any bindings for this function, and a user of this library was
experimenting with some optimizations for his code and ran into this.
I was kind of hoping to avoid having too many special-purpose functions
and since there's also an SQL "EXECUTE" function, PQexecPrepared seemed
a bit redundant.

> Interposing an EXECUTE doesn't do anything but add parsing overhead.

Is this parsing overhead of an EXECUTE statement (which should be very
short and simple) *that* significant compared to the savings you get
when preparing a complex SQL statement which is executed many times?

> The reason this particular case doesn't work is that utility statements
> (including EXECUTE) don't have any support for $n parameters.

Why not, is it simply something nobody ever needed?  It seems rather
logical to be able to replace any literal by an equivalent parameter
in any SQL statement.

I should probably add support for PQexecPrepared at some point but
even then, as a user, I'd probably expect this to be possible for
reasons of symmetry and regularity.  It might also make it easier for
certain types of generated SQL.

Cheers,
Peter
--
http://sjamaan.ath.cx
--
"The process of preparing programs for a digital computer
 is especially attractive, not only because it can be economically
 and scientifically rewarding, but also because it can be an aesthetic
 experience much like composing poetry or music."
                            -- Donald Knuth