Return-Path: Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: (qmail 46886 invoked from network); 4 May 2007 16:33:06 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 4 May 2007 16:33:06 -0000 Received: (qmail 59071 invoked by uid 500); 4 May 2007 16:33:12 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 59042 invoked by uid 500); 4 May 2007 16:33:12 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" List-Id: Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 59031 invoked by uid 99); 4 May 2007 16:33:12 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 04 May 2007 09:33:12 -0700 X-ASF-Spam-Status: No, hits=-99.5 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 04 May 2007 09:33:04 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 38C9A1A9838; Fri, 4 May 2007 09:32:44 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r535319 - in /db/derby/code/trunk/java/client/org/apache/derby/client: am/Clob.java am/ClobLocatorInputStream.java am/ClobLocatorOutputStream.java am/ClobLocatorReader.java am/ClobLocatorWriter.java net/NetCursor.java Date: Fri, 04 May 2007 16:32:43 -0000 To: derby-commits@db.apache.org From: rhillegas@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20070504163244.38C9A1A9838@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: rhillegas Date: Fri May 4 09:32:39 2007 New Revision: 535319 URL: http://svn.apache.org/viewvc?view=rev&rev=535319 Log: DERBY-2604: Commit Naryayan's ClobLocatorWork_v1.diff, adding locator support to clobs. Added: db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorInputStream.java (with props) db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorOutputStream.java (with props) db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorReader.java (with props) db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorWriter.java (with props) Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java?view=diff&rev=535319&r1=535318&r2=535319 ============================================================================== --- db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java (original) +++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java Fri May 4 09:32:39 2007 @@ -169,6 +169,20 @@ characterStream_ = reader; dataType_ |= CHARACTER_STREAM; } + + /** + * Create a Clob object for a Clob value stored + * on the server and indentified by locator. + * @param agent context for this Clob + * object (incl. connection). + * @param locator reference id to Clob value on server. + */ + public Clob(Agent agent, int locator) + { + super(agent, false); + locator_ = locator; + dataType_ |= LOCATOR; + } /** * Create a Clob of unknown length. @@ -307,7 +321,18 @@ // actual length is the lesser of the length requested // and the number of characters available from pos to the end long actualLength = Math.min(this.sqlLength() - pos + 1, (long) length); - return string_.substring((int) pos - 1, (int) (pos - 1 + actualLength)); + //Check to see if the Clob object is locator enabled. + if (isLocator()) { + //The Clob object is locator enabled. Hence call the stored + //procedure CLOBGETLENGTH to determine the length of the Clob. + return agent_.connection_.locatorProcedureCall() + .clobGetSubString(locator_, pos, (int)actualLength); + } + else { + //The Clob object is not locator enabled. + return string_.substring + ((int) pos - 1, (int) (pos - 1 + actualLength)); + } } public java.io.Reader getCharacterStream() throws SQLException { @@ -339,7 +364,13 @@ private java.io.Reader getCharacterStreamX() throws SqlException { checkForClosedConnection(); - if (isCharacterStream()) // this Lob is used for input + //check is this Lob is locator enabled + if (isLocator()) { + //The Lob is locator enabled. Return an instance of the Locator + //enabled Writer implementation + return new ClobLocatorReader(agent_.connection_, this); + } + else if (isCharacterStream()) // this Lob is used for input { return characterStream_; } @@ -380,8 +411,15 @@ { return asciiStream_; } - - return new AsciiStream(string_, new java.io.StringReader(string_)); + else if(isLocator()) { // Check to see if this Lob is locator enabled + //The Lob is locator enabled. Return an instance + //of the Locator enabled Clob specific InputStream + //implementation. + return new ClobLocatorInputStream(agent_.connection_,this); + } + else { + return new AsciiStream(string_, new java.io.StringReader(string_)); + } } public long position(String searchstr, long start) throws SQLException { @@ -425,18 +463,28 @@ private long positionX(String searchstr, long start) throws SqlException { checkForClosedConnection(); - + long index = -1; if (start <= 0) { throw new SqlException(agent_.logWriter_, new ClientMessageId(SQLState.INVALID_API_PARAMETER), new Long(start), "start", "Clob.position()"); } - - int index = string_.indexOf(searchstr, (int) start - 1); - if (index != -1) { - index++; // api index starts at 1 + + //Check is locator support is available for this LOB. + if (isLocator()) { + //Locator support is available. Hence call + //CLOBGETPOSITIONFROMSTRING to determine the position + //of the given substring inside the LOB. + index = agent_.connection_.locatorProcedureCall() + .clobGetPositionFromString(locator_, searchstr, start); + } else { + //Locator support is not available. + index = string_.indexOf(searchstr, (int) start - 1); + if (index != -1) { + index++; // api index starts at 1 + } } - return (long) index; + return index; } public long position(java.sql.Clob searchstr, long start) throws SQLException { @@ -586,12 +634,26 @@ int length = 0; length = Math.min((str.length() - offset), len); - String newString = string_.substring(0, (int) pos - 1); - string_ = newString.concat(str.substring(offset, offset + length)); - asciiStream_ = new java.io.StringBufferInputStream(string_); - unicodeStream_ = new java.io.StringBufferInputStream(string_); - characterStream_ = new java.io.StringReader(string_); - setSqlLength(string_.length()); + //check if the Clob object is locator enabled + if (isLocator()) { + //The Clob is locator enabled. Call the CLOBSETSTRING + //stored procedure to set the given string in the Clob. + agent_.connection_.locatorProcedureCall().clobSetString + (locator_, pos, length, str.substring(offset, offset + length)); + if (pos+length-1 > sqlLength()) { // Wrote beyond the old end + // Update length + setSqlLength(pos + length - 1); + } + } + else { + //The Clob is not locator enabled. + String newString = string_.substring(0, (int) pos - 1); + string_ = newString.concat(str.substring(offset, offset + length)); + asciiStream_ = new java.io.StringBufferInputStream(string_); + unicodeStream_ = new java.io.StringBufferInputStream(string_); + characterStream_ = new java.io.StringReader(string_); + setSqlLength(string_.length()); + } return length; } @@ -607,8 +669,19 @@ if (agent_.loggingEnabled()) { agent_.logWriter_.traceEntry(this, "setAsciiStream", (int) pos); } - ClobOutputStream outStream = new ClobOutputStream(this, pos); - + java.io.OutputStream outStream = null; + + if(isLocator()) { // Check to see if the Lob is locator enabled + //The Lob is locator enabled. Return an instance of the + //Locator enabled Clob specific OutputStream implementation. + outStream = new ClobLocatorOutputStream + (agent_.connection_, this, pos); + } + else { + //The Lob is not locator enabled. + outStream = new + ClobOutputStream(this, pos); + } if (agent_.loggingEnabled()) { agent_.logWriter_.traceExit(this, "setAsciiStream", outStream); } @@ -633,7 +706,16 @@ if (agent_.loggingEnabled()) { agent_.logWriter_.traceEntry(this, "setCharacterStream", (int) pos); } - ClobWriter writer = new ClobWriter(this, pos); + java.io.Writer writer = null; + //Check to see if this Clob is locator enabled. + if (isLocator()) { + //return an instance of the locator enabled implementation + //of the writer interface + writer = new ClobLocatorWriter(agent_.connection_, this, pos); + } + else {//The Lob is not locator enabled. + writer = new ClobWriter(this, pos); + } if (agent_.loggingEnabled()) { agent_.logWriter_.traceExit(this, "setCharacterStream", writer); @@ -674,12 +756,23 @@ if (len == sqlLength()) { return; } - String newstr = string_.substring(0, (int) len); - string_ = newstr; - asciiStream_ = new java.io.StringBufferInputStream(string_); - unicodeStream_ = new java.io.StringBufferInputStream(string_); - characterStream_ = new java.io.StringReader(string_); - setSqlLength(string_.length()); + + //check whether the Lob is locator enabled. + if (isLocator()) { + //The Lob is locator enabled then call the stored + //procedure CLOBTRUNCATE to truncate this Lob. + agent_.connection_.locatorProcedureCall(). + clobTruncate(locator_, len); + } + else { + //The Lob is not locator enabled. + String newstr = string_.substring(0, (int) len); + string_ = newstr; + asciiStream_ = new java.io.StringBufferInputStream(string_); + unicodeStream_ = new java.io.StringBufferInputStream(string_); + characterStream_ = new java.io.StringReader(string_); + setSqlLength(string_.length()); + } } } catch ( SqlException se ) @@ -778,16 +871,27 @@ (int) pos, length); } checkPosAndLength(pos, length); - String retVal_str = null; - try { - retVal_str = getSubStringX(pos, (int)length); - } - catch(SqlException sqle) { - throw sqle.getSQLException(); - } - Reader retVal = new java.io.StringReader(retVal_str); - if (agent_.loggingEnabled()) { - agent_.logWriter_.traceExit(this, "getCharacterStream", retVal); + Reader retVal = null; + //check if the Lob is locator enabled. + if(isLocator()) { + //The Lob is locator enabled. Return the locator enabled + //Implementation of a Clob Reader. + retVal = new ClobLocatorReader(agent_.connection_, this, + pos, length); + } + else { + //The Lob is not locator enabled. + String retVal_str = null; + try { + retVal_str = getSubStringX(pos, (int)length); + } + catch(SqlException sqle) { + throw sqle.getSQLException(); + } + retVal = new java.io.StringReader(retVal_str); + if (agent_.loggingEnabled()) { + agent_.logWriter_.traceExit(this, "getCharacterStream", retVal); + } } return retVal; } @@ -906,4 +1010,21 @@ dataType_ = UNICODE_STREAM; } + /*--------------------------------------------------------------------- + Methods used in the locator implementation. + ----------------------------------------------------------------------*/ + + /** + * Get the length in bytes of the Clob value represented by + * this locator based Clob object. + * + * A stored procedure call will be made to get it from the server. + * @throws org.apache.derby.client.am.SqlException + * @return length of Clob in bytes + */ + long getLocatorLength() throws SqlException + { + return agent_.connection_.locatorProcedureCall() + .clobGetLength(locator_); + } } Added: db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorInputStream.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorInputStream.java?view=auto&rev=535319 ============================================================================== --- db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorInputStream.java (added) +++ db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorInputStream.java Fri May 4 09:32:39 2007 @@ -0,0 +1,139 @@ +/* + + Derby - Class org.apache.derby.client.am.ClobLocatorInputStream + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +package org.apache.derby.client.am; + +import java.sql.CallableStatement; +import java.sql.SQLException; + +import java.io.IOException; + +import org.apache.derby.iapi.services.sanity.SanityManager; + +/** + * An InputStream that will use an locator to fetch the + * Clob value from the server. + *

+ * Closing a ByteArrayInputStream has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an IOException. + *

+ * This InputStream implementation is pretty basic. No + * buffering of data is done. Hence, for efficieny #read(byte[]) + * should be used instead of #read(). Marks are not supported, but it + * should be pretty simple to extend the implementation to support + * this. A more efficient skip implementation should also be + * straight-forward. + */ + +public class ClobLocatorInputStream extends java.io.InputStream { + + /** + * Connection used to read Clob from server. + */ + private Connection connection; + + /** + * The Clob to be accessed. + */ + private Clob clob; + + /** + * Current position in the underlying Clob. + * Clobs are indexed from 1 + */ + private long currentPos = 1; + + /** + * Create an InputStream for reading the + * Clob value represented by the given locator based + * Clob object. + * @param connection connection to be used to read the + * Clob value from the server + * @param clob Clob object that contains locator for + * the Clob value on the server. + */ + public ClobLocatorInputStream(Connection connection, Clob clob) { + SanityManager.ASSERT(clob.isLocator()); + + this.connection = connection; + this.clob = clob; + } + + /** + * @see java.io.InputStream#read() + * + * This method fetches one byte at a time from the server. For more + * efficient retrieval, use #read(byte[]). + */ + public int read() throws IOException { + byte[] bytes = readBytes(1); + if (bytes.length == 0) { // EOF + return -1; + } else { + return bytes[0]; + } + } + + /** + * @see java.io.InputStream#read(byte[], int, int) + */ + public int read(byte[] b, int off, int len) throws IOException { + if (len == 0) return 0; + if ((off < 0) || (len < 0) || (off+len > b.length)) { + throw new IndexOutOfBoundsException(); + } + + byte[] bytes = readBytes(len); + if (bytes.length == 0) { // EOF + return -1; + } else { + System.arraycopy(bytes, 0, b, off, bytes.length); + return bytes.length; + } + } + + /** + * Read the next len bytes of the Clob + * value from the server. + * + * @param len number of bytes to read + * @throws java.io.IOException Wrapped SqlException if reading + * from server fails. + * @return byte[] containing the read bytes + */ + private byte[] readBytes(int len) throws IOException { + try { + int actualLength + = (int )Math.min(len, clob.sqlLength() - currentPos + 1); + String resultStr = connection.locatorProcedureCall(). + clobGetSubString(clob.getLocator(), + currentPos, actualLength); + byte[] result = resultStr.getBytes(); + currentPos += result.length; + return result; + } catch (SqlException ex) { + IOException ioEx = new IOException(); + ioEx.initCause(ex); + throw ioEx; + } + } +} Propchange: db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorInputStream.java ------------------------------------------------------------------------------ svn:eol-style = native Added: db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorOutputStream.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorOutputStream.java?view=auto&rev=535319 ============================================================================== --- db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorOutputStream.java (added) +++ db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorOutputStream.java Fri May 4 09:32:39 2007 @@ -0,0 +1,149 @@ +/* + + Derby - Class org.apache.derby.client.am.ClobLocatorOutputStream + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +package org.apache.derby.client.am; + +import java.io.IOException; + +/** + * An OutputStream that will use an locator to write + * bytes to the Clob value on the server. + *

+ * Closing a ByteArrayInputStream has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an IOException. + *

+ * This OutputStream implementation is pretty basic. No + * buffering of data is done. Hence, for efficieny #write(byte[]) + * should be used instead of #write(int). + */ +public class ClobLocatorOutputStream extends java.io.OutputStream { + + /** + * Connection used to read Clob from server. + */ + private Connection connection; + + /** + * The Clob to be accessed. + */ + private Clob clob; + + /** + * Current position in the underlying Clob. + * Clobs are indexed from 1 + */ + private long currentPos; + + + /** + * Create an OutputStream for writing to the + * Clob value represented by the given locator based + * Clob object. + * @param connection connection to be used to write to the + * Clob value on the server + * @param clob Clob object that contains locator for + * the Clob value on the server. + * @param pos the position in the CLOB value at which + * to start writing; the first position is 1 + * @throws org.apache.derby.client.am.SqlException + */ + public ClobLocatorOutputStream(Connection connection, Clob clob, long pos) + throws SqlException { + if (pos-1 > clob.sqlLength()) { + throw new IndexOutOfBoundsException(); + } + + this.connection = connection; + this.clob = clob; + this.currentPos = pos; + } + + /** + * @see java.io.OutputStream#write(int) + * + * This method writes one byte at a time to the server. For more + * efficient writing, use #write(byte[]). + */ + public void write(int b) throws IOException { + byte[] ba = {(byte )b}; + writeBytes(ba); + } + + /** + * @see java.io.OutputStream#write(byte[]) + */ + public void write(byte[] b) throws IOException { + writeBytes(b); + } + + /** + * @see java.io.OutputStream#write(byte[], int, int) + */ + public void write(byte[] b, int off, int len) throws IOException { + if (len == 0) return; + if ((off < 0) || (off > b.length) || (len < 0) || + (off+len > b.length) || (off+len < 0)) { + throw new IndexOutOfBoundsException(); + } + + byte[] ba = b; + if ((off > 0) || (len < b.length)) { // Copy the part we will use + ba = new byte[len]; + System.arraycopy(b, off, ba, 0, len); + } + writeBytes(ba); + } + + /** + * @see java.io.OutputStream#flush() + */ + public void flush() { + //There is no necessity to flush since each write + //automatically calls the stored procedure to write + //the Bytes to the locator on the server. + } + + /** + * Write the byte[] to the Clob value on + * the server; starting from the current position of this stream. + * + * @param b The byte array containing the bytes to be written + * @throws java.io.IOException Wrapped SqlException if writing + * to server fails. + */ + private void writeBytes(byte[] b) throws IOException { + try { + String clobStr = new String(b); + connection.locatorProcedureCall().clobSetString + (clob.locator_, currentPos, b.length, clobStr); + currentPos += b.length; + if (currentPos-1 > clob.sqlLength()) { + // Wrote past the old end of the Clob value, update length + clob.setSqlLength(currentPos - 1); + } + } catch (SqlException ex) { + IOException ioEx= new IOException(); + ioEx.initCause(ex); + throw ioEx; + } + } +} Propchange: db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorOutputStream.java ------------------------------------------------------------------------------ svn:eol-style = native Added: db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorReader.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorReader.java?view=auto&rev=535319 ============================================================================== --- db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorReader.java (added) +++ db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorReader.java Fri May 4 09:32:39 2007 @@ -0,0 +1,216 @@ +/* + + Derby - Class org.apache.derby.client.am.ClobLocatorReader + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +package org.apache.derby.client.am; + +import java.io.IOException; + +import org.apache.derby.iapi.services.sanity.SanityManager; + +/** + * An Reader that will use an locator to fetch the + * Clob value from the server. + *

+ * This Reader implementation is pretty basic. No + * buffering of data is done. Hence, for efficieny #read(char[]) + * should be used instead of #read(). Marks are not supported, but it + * should be pretty simple to extend the implementation to support + * this. A more efficient skip implementation should also be + * straight-forward. + */ +public class ClobLocatorReader extends java.io.Reader { + /** + * Connection used to read Clob from server. + */ + private Connection connection; + + /** + * The Clob to be accessed. + */ + private Clob clob; + + /** + * Current position in the underlying Clob. + * Clobs are indexed from 1 + */ + private long currentPos = 1; + + /** + * The length in characters of the partial value to be retrieved. + */ + private long length = -1; + + /** + * Stores the information to whether this Reader has been + * closed or not. Is set to true if close() has been + * called. Is false otherwise. + */ + private boolean isClosed = false; + + /** + * Create an Reader for reading the + * Clob value represented by the given locator based + * Clob object. + * @param connection connection to be used to read the + * Clob value from the server + * @param clob Clob object that contains locator for + * the Clob value on the server. + */ + public ClobLocatorReader(Connection connection, Clob clob) { + SanityManager.ASSERT(clob.isLocator()); + + this.connection = connection; + this.clob = clob; + } + + /** + * Create an Reader for reading the + * Clob value represented by the given locator based + * Clob object. + * @param connection connection to be used to read the + * Clob value from the server + * @param clob Clob object that contains locator for + * the Clob value on the server. + * @param pos The offset to the first character of the partial value to be + * retrieved. + * @param len The length in characters of the partial value to be retrieved. + */ + public ClobLocatorReader(Connection connection, Clob clob, + long pos, long len) { + this(connection, clob); + currentPos = pos; + length = len; + } + + /** + * @see java.io.Reader#read() + * + * This method fetches one character at a time from the server. For more + * efficient retrieval, use #read(char[]). + */ + public int read() throws IOException { + checkClosed(); + char[] chars = readCharacters(1); + if (chars.length == 0) { // EOF + return -1; + } else { + return chars[0]; + } + } + + /** + * @see java.io.Reader#read(char[], int, int) + */ + public int read(char[] c, int off, int len) throws IOException { + checkClosed(); + if (len == 0) return 0; + if ((off < 0) || (len < 0) || (off+len > c.length)) { + throw new IndexOutOfBoundsException(); + } + + char[] chars = readCharacters(len); + if (chars.length == 0) { // EOF + return -1; + } else { + System.arraycopy(chars, 0, c, off, chars.length); + return chars.length; + } + } + + /** + * @see java.io.Reader#close() + */ + public void close() throws IOException { + if (isClosed) { + return; + } + isClosed = true; + connection = null; + clob = null; + } + + /** + * Check to see if this Reader is closed. If it + * is closed throw an IOException that states that + * the stream is closed. + * + * @throws IOException if isClosed = true. + */ + private void checkClosed() throws IOException { + //if isClosed=true this means that close() has + //been called on this Reader already. + if(isClosed) { + //since this method would be used from the read method + //implementations throw an IOException that states that + //these operations cannot be done once close has been + //called. + throw new IOException("This operation is not " + + "permitted because the" + + "Reader has been closed"); + } + } + + /** + * Read the next len characters of the Clob + * value from the server. + * + * @param len number of characters to read. + * @throws java.io.IOException Wrapped SqlException if reading + * from server fails. + * @return char[] containing the read characters. + */ + private char[] readCharacters(int len) throws IOException { + try { + int actualLength + = (int )Math.min(len, getStreamLength() - currentPos + 1); + String resultStr = connection.locatorProcedureCall(). + clobGetSubString(clob.getLocator(), + currentPos, actualLength); + char[] result = resultStr.toCharArray(); + currentPos += result.length; + return result; + } catch (SqlException ex) { + IOException ioEx = new IOException(); + ioEx.initCause(ex); + throw ioEx; + } + } + + /** + * Return the length of the stream. + * + * @return the length of the stream. + */ + private long getStreamLength() throws SqlException { + //check to see if the length of the stream has been set + //during initialization + if(length != -1) { + //The length has been set. Hence return this as the + //length + return length; + } + else { + //The length has not been set. Obtain the length from + //the Clob. + return clob.sqlLength(); + } + } +} Propchange: db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorReader.java ------------------------------------------------------------------------------ svn:eol-style = native Added: db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorWriter.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorWriter.java?view=auto&rev=535319 ============================================================================== --- db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorWriter.java (added) +++ db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorWriter.java Fri May 4 09:32:39 2007 @@ -0,0 +1,181 @@ +/* + + Derby - Class org.apache.derby.client.am.ClobLocatorWriter + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +package org.apache.derby.client.am; + +import java.io.IOException; + +/** + * An Writer that will use an locator to write the + * Clob value into the server. + *

+ * This Writer implementation is pretty basic. No + * buffering of data is done. Hence, for efficieny #write(char[]) + * should be used instead of #write(int). + */ +public class ClobLocatorWriter extends java.io.Writer { + /** + * Connection used to read Clob from server. + */ + private Connection connection; + + /** + * The Clob to be accessed. + */ + private Clob clob; + + /** + * Current position in the underlying Clob. + * Clobs are indexed from 1 + */ + private long currentPos; + + /** + * Stores the information to whether this Writer has been + * closed or not. Is set to true if close() has been + * called. Is false otherwise. + */ + private boolean isClosed = false; + + /** + * Create a Writer for writing to the + * Clob value represented by the given locator based + * Clob object. + * @param connection connection to be used to write to the + * Clob value on the server + * @param clob Clob object that contains locator for + * the Clob value on the server. + * @param pos the position in the CLOB value at which + * to start writing; the first position is 1 + * @throws org.apache.derby.client.am.SqlException + */ + public ClobLocatorWriter(Connection connection, Clob clob, long pos) + throws SqlException { + if (pos-1 > clob.sqlLength()) { + throw new IndexOutOfBoundsException(); + } + + this.connection = connection; + this.clob = clob; + this.currentPos = pos; + } + + /** + * @see java.io.Writer#close() + */ + public void close() throws IOException { + if (isClosed) { + return; + } + isClosed = true; + connection = null; + clob = null; + } + + /** + * Check to see if this Writer is closed. If it + * is closed throw an IOException that states that + * the stream is closed. + * + * @throws IOException if isClosed = true. + */ + private void checkClosed() throws IOException { + //if isClosed=true this means that close() has + //been called on this Writer already. + if(isClosed) { + //since this method would be used from the write method + //implementations throw an IOException that states that + //these operations cannot be done once close has been + //called. + throw new IOException("This operation is not " + + "permitted because the" + + "Writer has been closed"); + } + } + + /** + * @see java.io.Writer#write(int) + * + * This method writes one Character at a time to the server. For more + * efficient writing, use #write(char[]). + */ + public void write(int c) throws IOException { + char[] ca = {(char )c}; + writeCharacters(ca, 0, ca.length); + } + + /** + * @see java.io.Writer#write(char[]) + */ + public void write(char[] c) throws IOException { + checkClosed(); + writeCharacters(c, 0, c.length); + } + + /** + * @see java.io.Writer#flush() + */ + public void flush() { + //There is no necessity to flush since each write + //automatically calls the stored procedure to write + //the characters to the locator on the server. + } + + + /** + * @see java.io.Writer#write(char[], int, int) + */ + public void write(char[] c, int off, int len) throws IOException { + checkClosed(); + if (len == 0) return; + if ((off < 0) || (off > c.length) || (len < 0) || + (off+len > c.length) || (off+len < 0)) { + throw new IndexOutOfBoundsException(); + } + writeCharacters(c, off, len); + } + + /** + * Write the char[] to the Clob value on + * the server; starting from the current position of this stream. + * + * @param c The character array containing the chars to be written + * @throws java.io.IOException Wrapped SqlException if writing + * to server fails. + */ + private void writeCharacters(char[] c, int off, int len) + throws IOException { + try { + connection.locatorProcedureCall().clobSetString + (clob.locator_, currentPos, c.length, + new String(c, off, len)); + currentPos += c.length; + if (currentPos-1 > clob.sqlLength()) { + // Wrote past the old end of the Clob value, update length + clob.setSqlLength(currentPos - 1); + } + } catch (SqlException ex) { + IOException ioEx= new IOException(); + ioEx.initCause(ex); + throw ioEx; + } + } +} Propchange: db/derby/code/trunk/java/client/org/apache/derby/client/am/ClobLocatorWriter.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java?view=diff&rev=535319&r1=535318&r2=535319 ============================================================================== --- db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java (original) +++ db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java Fri May 4 09:32:39 2007 @@ -1103,6 +1103,13 @@ public Clob getClobColumn_(int column, Agent agent) throws SqlException { + // Check for locator + int locator = locator(column); + if (locator > 0) { // Create locator-based LOB object + return new Clob(agent, locator); + } + + // The Clob value has been sent instead of locator int index = column - 1; int dataOffset; byte[] data;