Thread: plpythonu and bytea

plpythonu and bytea

From
Greg Steffensen
Date:
Hey, I'm trying to write some plpython procedures that read binary data from images on the disk and store it in bytea fields.  I'm basically trying to write a plpython procedure that accepts a varchar and returns a bytea, with these procedure contents:

data = file(args[0]).read()
return data

(The actual procedure will have more in it, but that's the tricky part).  But the returned data is always severely truncated.  Is returning a bytea from plpython impossible, or is there some way I should escape the data string?  I've tried using the built in encode and decode functions, but they don't seem to help.  If worse comes to worse, I can store the base64 encoded version, of course, but I'd rather not do that.  Any ideas?

Greg

Re: plpythonu and bytea

From
Michael Fuhr
Date:
On Sat, Jul 02, 2005 at 04:49:23PM -0400, Greg Steffensen wrote:
>
> Hey, I'm trying to write some plpython procedures that read binary data from
> images on the disk and store it in bytea fields. I'm basically trying to
> write a plpython procedure that accepts a varchar and returns a bytea, with
> these procedure contents:
>
> data = file(args[0]).read()
> return data
>
> (The actual procedure will have more in it, but that's the tricky part). But
> the returned data is always severely truncated. Is returning a bytea from
> plpython impossible, or is there some way I should escape the data string?

I think the return value is a cstring that's cast to whatever type
the function is declared to return; I'd guess it's being truncated
because it contains NUL (\000) values.  Example:

CREATE FUNCTION foo() RETURNS bytea AS $$
data = '\001\002\000\003\004'
return data
$$ LANGUAGE plpythonu;

SELECT foo(), length(foo());
   foo    | length
----------+--------
 \001\002 |      2
(1 row)

The function should work if the data is escaped.  I don't know the
best Python way to do that, but the following appears to work:

CREATE FUNCTION foo() RETURNS bytea AS $$
data = '\001\002\000\003\004'
return ''.join(['\\%03o' % ord(x) for x in data])
$$ LANGUAGE plpythonu;

SELECT foo(), length(foo());
         foo          | length
----------------------+--------
 \001\002\000\003\004 |      5
(1 row)

It seems like there ought to be a better way than the list comprehension
shown; maybe you or somebody else with better Python skills can improve
on it.

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/