diff --git a/src/interfaces/jdbc/CHANGELOG b/src/interfaces/jdbc/CHANGELOG
index 56d450d9ebb..ffc0ce9efb3 100644
--- a/src/interfaces/jdbc/CHANGELOG
+++ b/src/interfaces/jdbc/CHANGELOG
@@ -1,3 +1,14 @@
+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.
Thu Jan 25 09:11:00 GMT 2001 peter@retep.org.uk
- Added an alternative constructor to PGSQLException so that debugging
some more osteric bugs is easier. If only 1 arg is supplied and it's
diff --git a/src/interfaces/jdbc/example/basic.java b/src/interfaces/jdbc/example/basic.java
index 41302200ec1..5e382538747 100644
--- a/src/interfaces/jdbc/example/basic.java
+++ b/src/interfaces/jdbc/example/basic.java
@@ -6,7 +6,7 @@ import java.text.*;
/**
*
- * $Id: basic.java,v 1.5 2000/06/06 11:05:57 peter Exp $
+ * $Id: basic.java,v 1.6 2001/01/31 08:26:01 peter Exp $
*
* This example tests the basic components of the JDBC driver, and shows
* how even the simplest of queries can be implemented.
@@ -22,40 +22,40 @@ public class basic
{
Connection db; // The connection to the database
Statement st; // Our statement to run queries with
-
+
public basic(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
{
String url = args[0];
String usr = args[1];
String pwd = args[2];
-
+
// Load the driver
Class.forName("org.postgresql.Driver");
-
+
// Connect to database
System.out.println("Connecting to Database URL = " + url);
db = DriverManager.getConnection(url, usr, pwd);
-
+
System.out.println("Connected...Now creating a statement");
st = db.createStatement();
-
+
// Clean up the database (in case we failed earlier) then initialise
cleanup();
-
+
// Now run tests using JDBC methods
doexample();
-
+
// Clean up the database
cleanup();
-
+
// Finally close the database
System.out.println("Now closing the connection");
st.close();
db.close();
-
+
//throw postgresql.Driver.notImplemented();
}
-
+
/**
* This drops the table (if it existed). No errors are reported.
*/
@@ -67,35 +67,36 @@ public class basic
// We ignore any errors here
}
}
-
+
/**
* This performs the example
*/
public void doexample() throws SQLException
{
System.out.println("\nRunning tests:");
-
+
// First we need a table to store data in
st.executeUpdate("create table basic (a int2, b int2)");
-
+
// Now insert some data, using the Statement
st.executeUpdate("insert into basic values (1,1)");
st.executeUpdate("insert into basic values (2,1)");
st.executeUpdate("insert into basic values (3,1)");
-
+
// This shows how to get the oid of a just inserted row
+ // updated for 7.1
st.executeUpdate("insert into basic values (4,1)");
- int insertedOID = ((org.postgresql.ResultSet)st.getResultSet()).getInsertedOID();
+ int insertedOID = ((org.postgresql.jdbc2.Statement)st).getInsertedOID();
System.out.println("Inserted row with oid "+insertedOID);
-
+
// Now change the value of b from 1 to 8
st.executeUpdate("update basic set b=8");
System.out.println("Updated "+st.getUpdateCount()+" rows");
-
+
// Now delete 2 rows
st.executeUpdate("delete from basic where a<3");
System.out.println("deleted "+st.getUpdateCount()+" rows");
-
+
// For large inserts, a PreparedStatement is more efficient, because it
// supports the idea of precompiling the SQL statement, and to store
// directly, a Java object into any column. PostgreSQL doesnt support
@@ -112,7 +113,7 @@ public class basic
ps.executeUpdate(); // executeUpdate because insert returns no data
}
ps.close(); // Always close when we are done with it
-
+
// Finally perform a query on the table
System.out.println("performing a query");
ResultSet rs = st.executeQuery("select a, b from basic");
@@ -126,7 +127,7 @@ public class basic
}
rs.close(); // again, you must close the result when done
}
-
+
// Now run the query again, showing a more efficient way of getting the
// result if you don't know what column number a value is in
System.out.println("performing another query");
@@ -140,7 +141,7 @@ public class basic
//
int col_a = rs.findColumn("a");
int col_b = rs.findColumn("b");
-
+
// Now we run through the result set, printing out the result.
// Again, we must call .next() before attempting to read any results
while(rs.next()) {
@@ -150,11 +151,22 @@ public class basic
}
rs.close(); // again, you must close the result when done
}
-
+
+ // Now test maxrows by setting it to 3 rows
+ st.setMaxRows(3);
+ System.out.println("performing a query limited to "+st.getMaxRows());
+ rs = st.executeQuery("select a, b from basic");
+ while(rs.next()) {
+ int a = rs.getInt("a"); // This shows how to get the value by name
+ int b = rs.getInt(2); // This shows how to get the value by column
+ System.out.println(" a="+a+" b="+b);
+ }
+ rs.close(); // again, you must close the result when done
+
// The last thing to do is to drop the table. This is done in the
// cleanup() method.
}
-
+
/**
* Display some instructions on how to run the example
*/
@@ -164,22 +176,22 @@ public class basic
System.out.println("Useage:\n java example.basic jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
System.exit(1);
}
-
+
/**
* This little lot starts the test
*/
public static void main(String args[])
{
System.out.println("PostgreSQL basic test v6.3 rev 1\n");
-
+
if(args.length<3)
instructions();
-
+
// This line outputs debug information to stderr. To enable this, simply
// add an extra parameter to the command line
if(args.length>3)
DriverManager.setLogStream(System.err);
-
+
// Now run the tests
try {
basic test = new basic(args);
diff --git a/src/interfaces/jdbc/jdbc.jpx b/src/interfaces/jdbc/jdbc.jpx
index abe4c8f86a4..2f8a779a6e6 100644
--- a/src/interfaces/jdbc/jdbc.jpx
+++ b/src/interfaces/jdbc/jdbc.jpx
@@ -9,7 +9,7 @@
If arbitrary parameter type conversions are required, then the setObject + *
If arbitrary parameter type conversions are required, then the setObject * method should be used with a target SQL type. * * @see ResultSet * @see java.sql.PreparedStatement */ -public class PreparedStatement extends Statement implements java.sql.PreparedStatement +public class PreparedStatement extends Statement implements java.sql.PreparedStatement { String sql; String[] templateStrings; @@ -124,7 +124,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta } s.append(templateStrings[inStrings.length]); return super.executeUpdate(s.toString()); // in Statement class - } + } /** * Set a parameter to SQL NULL @@ -264,7 +264,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta else { StringBuffer b = new StringBuffer(); int i; - + b.append('\''); for (i = 0 ; i < x.length() ; ++i) { @@ -327,7 +327,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta // //set(parameterIndex, df.format(new java.util.Date(x.getTime()+86400000))); } - + /** * Set a parameter to a java.sql.Time value. The driver converts * this to a SQL TIME value when it sends it to the database. @@ -406,7 +406,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta * When a very large binary value is input to a LONGVARBINARY parameter, * it may be more practical to send it via a java.io.InputStream. * JDBC will read the data from the stream as needed, until it reaches - * end-of-file. + * end-of-file. * *
Note: This stream object can either be a standard Java * stream object or your own subclass that implements the standard @@ -418,7 +418,25 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta */ public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { - throw new PSQLException("postgresql.prep.is"); + LargeObjectManager lom = connection.getLargeObjectAPI(); + int oid = lom.create(); + LargeObject lob = lom.open(oid); + OutputStream los = lob.getOutputStream(); + try { + // could be buffered, but then the OutputStream returned by LargeObject + // is buffered internally anyhow, so there would be no performance + // boost gained, if anything it would be worse! + int c=x.read(); + while(c>-1) { + los.write(c); + c=x.read(); + } + los.close(); + } catch(IOException se) { + throw new PSQLException("postgresql.prep.is",se); + } + // lob is closed by the stream so don't call lob.close() + setInt(parameterIndex,oid); } /** @@ -453,7 +471,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta * @param x the object containing the input parameter value * @param targetSqlType The SQL type to be send to the database * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC - * types this is the number of digits after the decimal. For + * types this is the number of digits after the decimal. For * all other types this value will be ignored. * @exception SQLException if a database access error occurs */ @@ -501,7 +519,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta { setObject(parameterIndex, x, targetSqlType, 0); } - + /** * This stores an Object into a parameter. *
New for 6.4, if the object is not recognised, but it is @@ -542,7 +560,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta /** * Some prepared statements return multiple results; the execute method - * handles these complex statements as well as the simpler form of + * handles these complex statements as well as the simpler form of * statements handled by executeQuery and executeUpdate * * @return true if the next result is a ResultSet; false if it is an @@ -584,11 +602,11 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta s.append(templateStrings[inStrings.length]); return s.toString(); } - + // ************************************************************** - // END OF PUBLIC INTERFACE + // END OF PUBLIC INTERFACE // ************************************************************** - + /** * There are a lot of setXXX classes which all basically do * the same thing. We need a method which actually does the @@ -604,62 +622,62 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta throw new PSQLException("postgresql.prep.range"); inStrings[paramIndex - 1] = s; } - + // ** JDBC 2 Extensions ** - + public void addBatch() throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public java.sql.ResultSetMetaData getMetaData() throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public void setArray(int i,Array x) throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public void setBlob(int i,Blob x) throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public void setCharacterStream(int i,java.io.Reader x,int length) throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public void setClob(int i,Clob x) throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public void setNull(int i,int t,String s) throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public void setRef(int i,Ref x) throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public void setDate(int i,java.sql.Date d,java.util.Calendar cal) throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public void setTime(int i,Time t,java.util.Calendar cal) throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + public void setTimestamp(int i,Timestamp t,java.util.Calendar cal) throws SQLException { throw org.postgresql.Driver.notImplemented(); } - + } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java index 59aef99ad5e..14fe603b69b 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java @@ -581,6 +581,15 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu */ public InputStream getBinaryStream(int columnIndex) throws SQLException { + // New in 7.1 Handle OID's as BLOBS so return the input stream + if(!wasNullFlag) + if( fields[columnIndex - 1].getOID() == 26) { + LargeObjectManager lom = connection.getLargeObjectAPI(); + LargeObject lob = lom.open(getInt(columnIndex)); + return lob.getInputStream(); + } + + // Not an OID so fake the stream byte b[] = getBytes(columnIndex); if (b != null) diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Statement.java index 04315c096a1..a0a40c14695 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/Statement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Statement.java @@ -32,6 +32,7 @@ public class Statement implements java.sql.Statement private Vector batch=null; int resultsettype; // the resultset type to return int concurrency; // is it updateable or not? + int maxrows=0; // the maximum number of rows to return 0=unlimited /** * Constructor for a Statement. It simply sets the connection @@ -134,7 +135,7 @@ public class Statement implements java.sql.Statement */ public int getMaxRows() throws SQLException { - return connection.maxrows; + return maxrows; } /** @@ -146,7 +147,7 @@ public class Statement implements java.sql.Statement */ public void setMaxRows(int max) throws SQLException { - connection.maxrows = max; + maxrows = max; } /** @@ -274,7 +275,8 @@ public class Statement implements java.sql.Statement if(escapeProcessing) sql=connection.EscapeSQL(sql); - result = connection.ExecSQL(sql); + // New in 7.1, pass Statement so that ExecSQL can customise to it + result = connection.ExecSQL(sql,this); // New in 7.1, required for ResultSet.getStatement() to work ((org.postgresql.jdbc2.ResultSet)result).setStatement(this); @@ -388,11 +390,6 @@ public class Statement implements java.sql.Statement throw org.postgresql.Driver.notImplemented(); } - //public int getKeysetSize() throws SQLException - //{ -// throw org.postgresql.Driver.notImplemented(); - //} - public int getResultSetConcurrency() throws SQLException { // new in 7.1 @@ -415,11 +412,6 @@ public class Statement implements java.sql.Statement throw org.postgresql.Driver.notImplemented(); } - //public void setKeysetSize(int keys) throws SQLException - //{ -// throw org.postgresql.Driver.notImplemented(); - //} - public void setResultSetConcurrency(int value) throws SQLException { concurrency=value; @@ -430,4 +422,17 @@ public class Statement implements java.sql.Statement resultsettype=value; } + /** + * New in 7.1: Returns the Last inserted oid. This should be used, rather + * than the old method using getResultSet, which for executeUpdate returns + * null. + * @return OID of last insert + */ + public int getInsertedOID() throws SQLException + { + if(result!=null) + return ((org.postgresql.ResultSet)result).getInsertedOID(); + return 0; + } + } 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. + * + *
The close
method of InputStream
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 reset
method repositions this stream at the last marked
+ * position so that subsequent reads re-read the same bytes.
+ *
+ *
The readlimit
arguments tells this input stream to
+ * allow that many bytes to be read before the mark position gets
+ * invalidated.
+ *
+ *
The general contract of mark
is that, if the method
+ * markSupported
returns true
, the stream somehow
+ * remembers all the bytes read after the call to mark
and
+ * stands ready to supply those same bytes again if and whenever the method
+ * reset
is called. However, the stream is not required to
+ * remember any data at all if more than readlimit
bytes are
+ * read from the stream before reset
is called.
+ *
+ *
The mark
method of InputStream
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
+ * mark
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 mark
and
+ * reset
methods. The markSupported
method of
+ * InputStream
returns false
.
+ *
+ * @return true
if this true type supports the mark and reset
+ * method; false
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 flush
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 close
+ * is that it closes the output stream. A closed stream cannot perform
+ * output operations and cannot be reopened.
+ *
+ * The close
method of OutputStream
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.
*
*
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