summaryrefslogtreecommitdiff
path: root/src/interfaces/jdbc/org/postgresql/largeobject
diff options
context:
space:
mode:
authorPeter Mount <peter@retep.org.uk>2001-01-31 08:26:02 +0000
committerPeter Mount <peter@retep.org.uk>2001-01-31 08:26:02 +0000
commit8439a83d84fb159a790ed2b6d14d4151b9890857 (patch)
tree867314ef119cc9a0713548c2ed0e676a124d0aad /src/interfaces/jdbc/org/postgresql/largeobject
parentdca0762efc1b4f84c0185b5464f94f7d66bbe566 (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')
-rw-r--r--src/interfaces/jdbc/org/postgresql/largeobject/BlobInputStream.java156
-rw-r--r--src/interfaces/jdbc/org/postgresql/largeobject/BlobOutputStream.java102
-rw-r--r--src/interfaces/jdbc/org/postgresql/largeobject/LargeObject.java52
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);
}
+
}