Thread: JDBC Blob helper class & streaming uploaded data into PG

JDBC Blob helper class & streaming uploaded data into PG

From
David Wall
Date:
Does anybody have a JDBC Blob helper class so we can use the
setBlob()/getBlob() calls in JDBC for PG 8.3?  It would be a class that
implements the java.sql.Blob interface.

Does anybody have any code samples of how I'd go about reading a file in
blocks, compressing the block and then streaming that block into a Blob
(LO)?  We are starting to process very large files uploaded in a web app
and so it's no longer possible to keep it all in memory before it's
stored in PG.

The pseudo-code is something like:

while ( hasMoreHttpPostData )
{
  read chunk from HTTP POST
  compress chunk
  write chunk to DB
}

If possible, we'd like to use a streaming cipher (for encryption) and
GZIP to write the compressed data and a Blob to store to the database.

Do these APIs support writing chunks, or must we actually loop through
each byte (which seems painfully slow).

Thanks,
David

Re: JDBC Blob helper class & streaming uploaded data into PG

From
Kris Jurka
Date:

On Wed, 4 Feb 2009, David Wall wrote:

> Does anybody have a JDBC Blob helper class so we can use the
> setBlob()/getBlob() calls in JDBC for PG 8.3?  It would be a class that
> implements the java.sql.Blob interface.

You really ought to use the driver's Blob implementation.  Right now
creating a new Blob isn't terribly straightforward.  In theory the JDBC 4
method Connection.createBlob should be used, but that has not been
implemented in the postgresql driver yet.

The best way to do this at the moment is to insert a row with an empty
blob, retrieve that blob and then write data into it.

CREATE TABLE test (id int, bigdata oid);

INSERT INTO test VALUES (1, lo_creat(-1));

ResultSet rs = stmt.executeQuery("SELECT bigdata FROM test WHERE id = 1");
rs.next();
Blob blob = rs.getBlob(1);
OutputStream out = blob.setBinaryStream(1);
// from java.util.zip. to compress the data.
GZIPOutputStream gz = new GZIPOutputStream(out);
while (!done) {
     gz.write(your data);
}
gz.close();
rs.close();

Kris Jurka

Re: JDBC Blob helper class & streaming uploaded data into PG

From
David Wall
Date:
>
>> Does anybody have a JDBC Blob helper class so we can use the
>> setBlob()/getBlob() calls in JDBC for PG 8.3?  It would be a class
>> that implements the java.sql.Blob interface.
>
> You really ought to use the driver's Blob implementation.  Right now
> creating a new Blob isn't terribly straightforward.  In theory the
> JDBC 4 method Connection.createBlob should be used, but that has not
> been implemented in the postgresql driver yet.
>
> The best way to do this at the moment is to insert a row with an empty
> blob, retrieve that blob and then write data into it.
>
> CREATE TABLE test (id int, bigdata oid);
>
> INSERT INTO test VALUES (1, lo_creat(-1));
>
> ResultSet rs = stmt.executeQuery("SELECT bigdata FROM test WHERE id =
> 1");
> rs.next();
> Blob blob = rs.getBlob(1);
> OutputStream out = blob.setBinaryStream(1);
> // from java.util.zip. to compress the data.
> GZIPOutputStream gz = new GZIPOutputStream(out);
> while (!done) {
>     gz.write(your data);
> }
> gz.close();
> rs.close();
>
> Kris Jurka

Thanks, Kris.  Interesting the create empty blob and then update is used
since Oracle seems to require something similar, though we don't do much
with Oracle any more, I do recall using the EMPTY_BLOB() function and
then updating it after getting an Oracle specific Blob class.

Yeah, that's why we need a Blob class that implements streaming through
the java.sql.Blob interface.  We have our own and use simple code like
the following to INSERT (and it works for UPDATE, too):

            YoByteBlob ybb = new YoByteBlob(encryptedCompressedData);
            stmt.setBlob(1, ybb);

When SELECTING, we can use:
            java.sql.Blob dbBlob = rs.getBlob(1);
            YoByteBlob ybb = new YoByteBlob(dbBlob);

These work for us now, but our version only supports "all in memory"
byte arrays and no streaming.  I could share YoByteBlob if anybody was
interested, but we'll need to do more work to make it all work so we can
stream the data in and out.

David