001: // jTDS JDBC Driver for Microsoft SQL Server and Sybase
002: // Copyright (C) 2004 The jTDS Project
003: //
004: // This library is free software; you can redistribute it and/or
005: // modify it under the terms of the GNU Lesser General Public
006: // License as published by the Free Software Foundation; either
007: // version 2.1 of the License, or (at your option) any later version.
008: //
009: // This library is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: // Lesser General Public License for more details.
013: //
014: // You should have received a copy of the GNU Lesser General Public
015: // License along with this library; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: //
018: package net.sourceforge.jtds.jdbc;
019:
020: import java.io.*;
021: import java.sql.Clob;
022: import java.sql.SQLException;
023:
024: import net.sourceforge.jtds.util.BlobBuffer;
025:
026: /**
027: * An in-memory or disk based representation of character data.
028: * <p/>
029: * Implementation note:
030: * <ol>
031: * <li>This implementation stores the CLOB data in a byte array managed by
032: * the <code>BlobBuffer</code> class. Each character is stored in 2
033: * sequential bytes using UTF-16LE encoding.
034: * <li>As a consequence of using UTF-16LE, Unicode 3.1 supplementary
035: * characters may require an additional 2 bytes of storage. This
036: * implementation assumes that character position parameters supplied to
037: * <code>getSubstring</code>, <code>position</code> and the
038: * <code>set</code> methods refer to 16 bit characters only. The presence
039: * of supplementary characters will cause the wrong characters to be
040: * accessed.
041: * <li>For the same reasons although the position method will return the
042: * correct start position for any given pattern in the array, the returned
043: * value may be different to that expected if supplementary characters
044: * exist in the text preceding the pattern.
045: * </ol>
046: *
047: * @author Brian Heineman
048: * @author Mike Hutchinson
049: * @version $Id: ClobImpl.java,v 1.36 2007/07/08 21:38:13 bheineman Exp $
050: */
051:
052: public class ClobImpl implements Clob {
053: /**
054: * 0 length <code>String</code> as initial value for empty
055: * <code>Clob</code>s.
056: */
057: private static final String EMPTY_CLOB = "";
058:
059: /** The underlying <code>BlobBuffer</code>. */
060: private final BlobBuffer blobBuffer;
061:
062: /**
063: * Constructs a new empty <code>Clob</code> instance.
064: *
065: * @param connection a reference to the parent connection object
066: */
067: ClobImpl(ConnectionJDBC2 connection) {
068: this (connection, EMPTY_CLOB);
069: }
070:
071: /**
072: * Constructs a new initialized <code>Clob</code> instance.
073: *
074: * @param connection a reference to the parent connection object
075: * @param str the <code>String</code> object to encapsulate
076: */
077: ClobImpl(ConnectionJDBC2 connection, String str) {
078: if (str == null) {
079: throw new IllegalArgumentException("str cannot be null");
080: }
081: blobBuffer = new BlobBuffer(connection.getBufferDir(),
082: connection.getLobBuffer());
083: try {
084: byte[] data = str.getBytes("UTF-16LE");
085: blobBuffer.setBuffer(data, false);
086: } catch (UnsupportedEncodingException e) {
087: // This should never happen!
088: throw new IllegalStateException(
089: "UTF-16LE encoding is not supported.");
090: }
091: }
092:
093: /**
094: * Obtain this object's backing <code>BlobBuffer</code> object.
095: *
096: * @return the underlying <code>BlobBuffer</code>
097: */
098: BlobBuffer getBlobBuffer() {
099: return this .blobBuffer;
100: }
101:
102: //
103: // ---- java.sql.Blob interface methods from here ----
104: //
105:
106: public InputStream getAsciiStream() throws SQLException {
107: return blobBuffer.getBinaryStream(true);
108: }
109:
110: public Reader getCharacterStream() throws SQLException {
111: try {
112: return new BufferedReader(new InputStreamReader(blobBuffer
113: .getBinaryStream(false), "UTF-16LE"));
114: } catch (UnsupportedEncodingException e) {
115: // This should never happen!
116: throw new IllegalStateException(
117: "UTF-16LE encoding is not supported.");
118: }
119: }
120:
121: public String getSubString(long pos, int length)
122: throws SQLException {
123: if (length == 0) {
124: return EMPTY_CLOB;
125: }
126: try {
127: byte data[] = blobBuffer.getBytes((pos - 1) * 2 + 1,
128: length * 2);
129: return new String(data, "UTF-16LE");
130: } catch (IOException e) {
131: throw new SQLException(Messages.get(
132: "error.generic.ioerror", e.getMessage()), "HY000");
133: }
134: }
135:
136: public long length() throws SQLException {
137: return blobBuffer.getLength() / 2;
138: }
139:
140: public long position(String searchStr, long start)
141: throws SQLException {
142: if (searchStr == null) {
143: throw new SQLException(Messages
144: .get("error.clob.searchnull"), "HY009");
145: }
146: try {
147: byte[] pattern = searchStr.getBytes("UTF-16LE");
148: int pos = blobBuffer.position(pattern, (start - 1) * 2 + 1);
149: return (pos < 0) ? pos : (pos - 1) / 2 + 1;
150: } catch (UnsupportedEncodingException e) {
151: // This should never happen!
152: throw new IllegalStateException(
153: "UTF-16LE encoding is not supported.");
154: }
155: }
156:
157: public long position(Clob searchStr, long start)
158: throws SQLException {
159: if (searchStr == null) {
160: throw new SQLException(Messages
161: .get("error.clob.searchnull"), "HY009");
162: }
163: BlobBuffer bbuf = ((ClobImpl) searchStr).getBlobBuffer();
164: byte[] pattern = bbuf.getBytes(1, (int) bbuf.getLength());
165: int pos = blobBuffer.position(pattern, (start - 1) * 2 + 1);
166: return (pos < 0) ? pos : (pos - 1) / 2 + 1;
167: }
168:
169: public OutputStream setAsciiStream(final long pos)
170: throws SQLException {
171: return blobBuffer.setBinaryStream((pos - 1) * 2 + 1, true);
172: }
173:
174: public Writer setCharacterStream(final long pos)
175: throws SQLException {
176: try {
177: return new BufferedWriter(new OutputStreamWriter(blobBuffer
178: .setBinaryStream((pos - 1) * 2 + 1, false),
179: "UTF-16LE"));
180: } catch (UnsupportedEncodingException e) {
181: // Should never happen
182: throw new IllegalStateException(
183: "UTF-16LE encoding is not supported.");
184: }
185: }
186:
187: public int setString(long pos, String str) throws SQLException {
188: if (str == null) {
189: throw new SQLException(Messages.get("error.clob.strnull"),
190: "HY009");
191: }
192: return setString(pos, str, 0, str.length());
193: }
194:
195: public int setString(long pos, String str, int offset, int len)
196: throws SQLException {
197: if (offset < 0 || offset > str.length()) {
198: throw new SQLException(Messages
199: .get("error.blobclob.badoffset"), "HY090");
200: }
201: if (len < 0 || offset + len > str.length()) {
202: throw new SQLException(Messages
203: .get("error.blobclob.badlen"), "HY090");
204: }
205: try {
206: byte[] data = str.substring(offset, offset + len).getBytes(
207: "UTF-16LE");
208: // No need to force BlobBuffer to copy the bytes as this is a local
209: // buffer and cannot be corrupted by the user.
210: return blobBuffer.setBytes((pos - 1) * 2 + 1, data, 0,
211: data.length, false);
212: } catch (UnsupportedEncodingException e) {
213: // This should never happen!
214: throw new IllegalStateException(
215: "UTF-16LE encoding is not supported.");
216: }
217: }
218:
219: public void truncate(long len) throws SQLException {
220: blobBuffer.truncate(len * 2);
221: }
222: }
|