diff options
| author | Peter Mount <peter@retep.org.uk> | 2001-01-31 08:26:02 +0000 |
|---|---|---|
| committer | Peter Mount <peter@retep.org.uk> | 2001-01-31 08:26:02 +0000 |
| commit | 8439a83d84fb159a790ed2b6d14d4151b9890857 (patch) | |
| tree | 867314ef119cc9a0713548c2ed0e676a124d0aad /src/interfaces/jdbc/org/postgresql/largeobject | |
| parent | dca0762efc1b4f84c0185b5464f94f7d66bbe566 (diff) | |
Tue Jan 30 22:24:00 GMT 2001 peter@retep.org.uk
- Fixed bug where Statement.setMaxRows() was a global setting. Now
limited to just itself.
- Changed LargeObject.read(byte[],int,int) to return the actual number
of bytes read (used to be void).
- LargeObject now supports InputStream's!
- PreparedStatement.setBinaryStream() now works!
- ResultSet.getBinaryStream() now returns an InputStream that doesn't
copy the blob into memory first!
- Connection.isClosed() now tests to see if the connection is still alive
rather than if it thinks it's alive.
Diffstat (limited to 'src/interfaces/jdbc/org/postgresql/largeobject')
3 files changed, 287 insertions, 23 deletions
diff --git a/src/interfaces/jdbc/org/postgresql/largeobject/BlobInputStream.java b/src/interfaces/jdbc/org/postgresql/largeobject/BlobInputStream.java new file mode 100644 index 00000000000..646ea970052 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/largeobject/BlobInputStream.java @@ -0,0 +1,156 @@ +package org.postgresql.largeobject; + +import java.io.InputStream; +import java.io.IOException; +import java.sql.SQLException; + +/** + * This is an initial implementation of an InputStream from a large object. + * For now, the bare minimum is implemented. Later (after 7.1) we will overide + * the other read methods to optimise them. + */ +public class BlobInputStream extends InputStream { + /** + * The parent LargeObject + */ + private LargeObject lo; + + /** + * Buffer used to improve performance + */ + private byte[] buffer; + + /** + * Position within buffer + */ + private int bpos; + + /** + * The buffer size + */ + private int bsize; + + /** + * The mark position + */ + private int mpos=0; + + /** + * @param lo LargeObject to read from + */ + public BlobInputStream(LargeObject lo) { + this(lo,1024); + } + + /** + * @param lo LargeObject to read from + * @param bsize buffer size + */ + public BlobInputStream(LargeObject lo,int bsize) { + this.lo=lo; + buffer=null; + bpos=0; + this.bsize=bsize; + } + + /** + * The minimum required to implement input stream + */ + public int read() throws java.io.IOException { + try { + if(buffer==null || bpos>=buffer.length) { + buffer=lo.read(bsize); + bpos=0; + } + + // Handle EOF + if(bpos>=buffer.length) + return -1; + + return (int) buffer[bpos++]; + } catch(SQLException se) { + throw new IOException(se.toString()); + } + } + + + /** + * Closes this input stream and releases any system resources associated + * with the stream. + * + * <p> The <code>close</code> method of <code>InputStream</code> does + * nothing. + * + * @exception IOException if an I/O error occurs. + */ + public void close() throws IOException { + try { + lo.close(); + lo=null; + } catch(SQLException se) { + throw new IOException(se.toString()); + } + } + + /** + * Marks the current position in this input stream. A subsequent call to + * the <code>reset</code> method repositions this stream at the last marked + * position so that subsequent reads re-read the same bytes. + * + * <p> The <code>readlimit</code> arguments tells this input stream to + * allow that many bytes to be read before the mark position gets + * invalidated. + * + * <p> The general contract of <code>mark</code> is that, if the method + * <code>markSupported</code> returns <code>true</code>, the stream somehow + * remembers all the bytes read after the call to <code>mark</code> and + * stands ready to supply those same bytes again if and whenever the method + * <code>reset</code> is called. However, the stream is not required to + * remember any data at all if more than <code>readlimit</code> bytes are + * read from the stream before <code>reset</code> is called. + * + * <p> The <code>mark</code> method of <code>InputStream</code> does + * nothing. + * + * @param readlimit the maximum limit of bytes that can be read before + * the mark position becomes invalid. + * @see java.io.InputStream#reset() + */ + public synchronized void mark(int readlimit) { + try { + mpos=lo.tell(); + } catch(SQLException se) { + //throw new IOException(se.toString()); + } + } + + /** + * Repositions this stream to the position at the time the + * <code>mark</code> method was last called on this input stream. + * NB: If mark is not called we move to the begining. + * @see java.io.InputStream#mark(int) + * @see java.io.IOException + */ + public synchronized void reset() throws IOException { + try { + lo.seek(mpos); + } catch(SQLException se) { + throw new IOException(se.toString()); + } + } + + /** + * Tests if this input stream supports the <code>mark</code> and + * <code>reset</code> methods. The <code>markSupported</code> method of + * <code>InputStream</code> returns <code>false</code>. + * + * @return <code>true</code> if this true type supports the mark and reset + * method; <code>false</code> otherwise. + * @see java.io.InputStream#mark(int) + * @see java.io.InputStream#reset() + */ + public boolean markSupported() { + return true; + } + +}
\ No newline at end of file diff --git a/src/interfaces/jdbc/org/postgresql/largeobject/BlobOutputStream.java b/src/interfaces/jdbc/org/postgresql/largeobject/BlobOutputStream.java new file mode 100644 index 00000000000..0ac435a78fd --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/largeobject/BlobOutputStream.java @@ -0,0 +1,102 @@ +package org.postgresql.largeobject; + +import java.io.IOException; +import java.io.OutputStream; +import java.sql.SQLException; + +/** + * This implements a basic output stream that writes to a LargeObject + */ +public class BlobOutputStream extends OutputStream { + /** + * The parent LargeObject + */ + private LargeObject lo; + + /** + * Buffer + */ + private byte buf[]; + + /** + * Size of the buffer (default 1K) + */ + private int bsize; + + /** + * Position within the buffer + */ + private int bpos; + + /** + * Create an OutputStream to a large object + * @param lo LargeObject + */ + public BlobOutputStream(LargeObject lo) { + this(lo,1024); + } + + /** + * Create an OutputStream to a large object + * @param lo LargeObject + * @param bsize The size of the buffer used to improve performance + */ + public BlobOutputStream(LargeObject lo,int bsize) { + this.lo=lo; + this.bsize=bsize; + buf=new byte[bsize]; + bpos=0; + } + + public void write(int b) throws java.io.IOException { + try { + if(bpos>=bsize) { + lo.write(buf); + bpos=0; + } + buf[bpos++]=(byte)b; + } catch(SQLException se) { + throw new IOException(se.toString()); + } + } + + /** + * Flushes this output stream and forces any buffered output bytes + * to be written out. The general contract of <code>flush</code> is + * that calling it is an indication that, if any bytes previously + * written have been buffered by the implementation of the output + * stream, such bytes should immediately be written to their + * intended destination. + * + * @exception IOException if an I/O error occurs. + */ + public void flush() throws IOException { + try { + if(bpos>0) + lo.write(buf,0,bpos); + bpos=0; + } catch(SQLException se) { + throw new IOException(se.toString()); + } + } + + /** + * Closes this output stream and releases any system resources + * associated with this stream. The general contract of <code>close</code> + * is that it closes the output stream. A closed stream cannot perform + * output operations and cannot be reopened. + * <p> + * The <code>close</code> method of <code>OutputStream</code> does nothing. + * + * @exception IOException if an I/O error occurs. + */ + public void close() throws IOException { + try { + lo.close(); + lo=null; + } catch(SQLException se) { + throw new IOException(se.toString()); + } + } + +}
\ No newline at end of file diff --git a/src/interfaces/jdbc/org/postgresql/largeobject/LargeObject.java b/src/interfaces/jdbc/org/postgresql/largeobject/LargeObject.java index 5cfd1383ffb..c73301d1318 100644 --- a/src/interfaces/jdbc/org/postgresql/largeobject/LargeObject.java +++ b/src/interfaces/jdbc/org/postgresql/largeobject/LargeObject.java @@ -16,7 +16,7 @@ import org.postgresql.fastpath.*; * for this object. * * <p>Normally, client code would use the getAsciiStream, getBinaryStream, - * or getUnicodeStream methods in ResultSet, or setAsciiStream, + * or getUnicodeStream methods in ResultSet, or setAsciiStream, * setBinaryStream, or setUnicodeStream methods in PreparedStatement to * access Large Objects. * @@ -47,21 +47,21 @@ public class LargeObject * Indicates a seek from the begining of a file */ public static final int SEEK_SET = 0; - + /** * Indicates a seek from the current position */ public static final int SEEK_CUR = 1; - + /** * Indicates a seek from the end of a file */ public static final int SEEK_END = 2; - + private Fastpath fp; // Fastpath API to use private int oid; // OID of this object private int fd; // the descriptor of the open large object - + /** * This opens a large object. * @@ -78,13 +78,13 @@ public class LargeObject { this.fp = fp; this.oid = oid; - + FastpathArg args[] = new FastpathArg[2]; args[0] = new FastpathArg(oid); args[1] = new FastpathArg(mode); this.fd = fp.getInteger("lo_open",args); } - + /** * @return the OID of this LargeObject */ @@ -92,7 +92,7 @@ public class LargeObject { return oid; } - + /** * This method closes the object. You must not call methods in this * object after this is called. @@ -104,7 +104,7 @@ public class LargeObject args[0] = new FastpathArg(fd); fp.fastpath("lo_close",false,args); // true here as we dont care!! } - + /** * Reads some data from the object, and return as a byte[] array * @@ -120,7 +120,7 @@ public class LargeObject args[0] = new FastpathArg(fd); args[1] = new FastpathArg(len); return fp.getData("loread",args); - + // This version allows us to break this down into 4k blocks //if(len<=4048) { //// handle as before, return the whole block in one go @@ -145,20 +145,25 @@ public class LargeObject //return buf; //} } - + /** * Reads some data from the object into an existing array * * @param buf destination array * @param off offset within array * @param len number of bytes to read + * @return the number of bytes actually read * @exception SQLException if a database-access error occurs. */ - public void read(byte buf[],int off,int len) throws SQLException + public int read(byte buf[],int off,int len) throws SQLException { - System.arraycopy(read(len),0,buf,off,len); + byte b[] = read(len); + if(b.length<len) + len=b.length; + System.arraycopy(b,0,buf,off,len); + return len; } - + /** * Writes an array to the object * @@ -172,7 +177,7 @@ public class LargeObject args[1] = new FastpathArg(buf); fp.fastpath("lowrite",false,args); } - + /** * Writes some data from an array to the object * @@ -187,7 +192,7 @@ public class LargeObject System.arraycopy(buf,off,data,0,len); write(data); } - + /** * Sets the current position within the object. * @@ -206,7 +211,7 @@ public class LargeObject args[2] = new FastpathArg(ref); fp.fastpath("lo_lseek",false,args); } - + /** * Sets the current position within the object. * @@ -220,7 +225,7 @@ public class LargeObject { seek(pos,SEEK_SET); } - + /** * @return the current position within the object * @exception SQLException if a database-access error occurs. @@ -231,7 +236,7 @@ public class LargeObject args[0] = new FastpathArg(fd); return fp.getInteger("lo_tell",args); } - + /** * This method is inefficient, as the only way to find out the size of * the object is to seek to the end, record the current position, then @@ -250,7 +255,7 @@ public class LargeObject seek(cp,SEEK_SET); return sz; } - + /** * Returns an InputStream from this object. * @@ -261,9 +266,9 @@ public class LargeObject */ public InputStream getInputStream() throws SQLException { - throw org.postgresql.Driver.notImplemented(); + return new BlobInputStream(this); } - + /** * Returns an OutputStream to this object * @@ -274,6 +279,7 @@ public class LargeObject */ public OutputStream getOutputStream() throws SQLException { - throw org.postgresql.Driver.notImplemented(); + return new BlobOutputStream(this); } + } |
