Re: problem with bytea and undecorated literals

Daniele Varrazzo <[email protected]> Thu, 29 Apr 2010 11:09:54 +0100
Newsgroups gmane.comp.python.db.psycopg.devel
Message-ID <[email protected]>
On Thu, Apr 29, 2010 at 9:33 AM, Peter Eisentraut <[email protected]> wrote:

[...]
a = Binary('abc')
> print cursor.mogrify('SELECT bar1(%s)', [a])
> cursor.execute('SELECT bar1(%s)', [a])
> print cursor.fetchall()
>
>
> Output:
>
> SELECT bar1(E'abc')
> [('text version',)]   # WRONG

[...]
> PostgreSQL is going to
> default unknown literals to text, so adding an explicit type decoration
> is advisable.

I agree. I just want to point out (in order to help people finding the
same problem: you obviously know this) that an explicit cast can be
added in the query. So, in order to call the correct function with the
current psycopg version, the following query can be used:

In [12]: cursor.execute('SELECT bar1(%s::bytea)', [a])

In [13]: print cursor.fetchall()
[('bytea version',)]

This will not break if psycopg starts adding its own cast, as the
query produced (using an explicit cast plus psycopg one) would be
"SELECT bar1(E'abc'::bytea::bytea)", which is redundant but correct
(unless there are operators binding stronger than the cast, which I
doubt but it can easily be checked).

> Another instance of this problem is that array support with types like
> these is broken:

> b = [Binary('abc\000\123'), Binary('def')]
> cursor.execute('SELECT foo (%s)', [b])
> print cursor.fetchall()
>
> psycopg2.ProgrammingError: function foo(text[]) does not exist

This can be fixed too casting the query placeholder to 'bytea[]':

In [23]: cursor.execute('SELECT foo (%s::bytea[])', [b])

In [24]: print cursor.fetchall()
[(123,)]

This is actually a shortcoming in the PostgreSQL casting algorithm, as
the same problem would appear issuing the query directly in psql:

test=> SELECT foo (ARRAY[E'abc\\\\000S', E'def']);
ERROR:  function foo(text[]) does not exist
LINE 1: SELECT foo (ARRAY[E'abc\\\\000S', E'def']);
               ^
HINT:  No function matches the given name and argument types. You
might need to add explicit type casts.
test=> SELECT foo (ARRAY[E'abc\\\\000S', E'def']::bytea[]);
 foo
-----
 123
(1 row)

-- Daniele