Source code: com/mysql/jdbc/Blob.java
1 /*
2 Copyright (C) 2002-2004 MySQL AB
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of version 2 of the GNU General Public License as
6 published by the Free Software Foundation.
7
8
9 There are special exceptions to the terms and conditions of the GPL
10 as it is applied to this software. View the full text of the
11 exception exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
12 software distribution.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23 */
24 package com.mysql.jdbc;
25
26 import java.io.ByteArrayInputStream;
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.sql.SQLException;
30
31
32 /**
33 * The representation (mapping) in the JavaTM programming language of an SQL
34 * BLOB value. An SQL BLOB is a built-in type that stores a Binary Large
35 * Object as a column value in a row of a database table. The driver
36 * implements Blob using an SQL locator(BLOB), which means that a Blob object
37 * contains a logical pointer to the SQL BLOB data rather than the data
38 * itself. A Blob object is valid for the duration of the transaction in
39 * which is was created. Methods in the interfaces ResultSet,
40 * CallableStatement, and PreparedStatement, such as getBlob and setBlob
41 * allow a programmer to access an SQL BLOB value. The Blob interface
42 * provides methods for getting the length of an SQL BLOB (Binary Large
43 * Object) value, for materializing a BLOB value on the client, and for
44 * determining the position of a pattern of bytes within a BLOB value. This
45 * class is new in the JDBC 2.0 API.
46 *
47 * @author Mark Matthews
48 *
49 * @version $Id: Blob.java,v 1.9.2.10 2004/08/09 22:15:12 mmatthew Exp $
50 */
51 public class Blob implements java.sql.Blob, OutputStreamWatcher {
52 //~ Instance fields --------------------------------------------------------
53
54 /** The ResultSet that created this BLOB */
55 private ResultSet creatorResultSet;
56
57 //
58 // This is a real brain-dead implementation of BLOB. Once I add
59 // streamability to the I/O for MySQL this will be more efficiently
60 // implemented (except for the position() method, ugh).
61 //
62
63 /** The binary data that makes up this BLOB */
64 private byte[] binaryData = null;
65
66 /** The column that this BLOB came from */
67 private int columnIndex;
68
69 //~ Constructors -----------------------------------------------------------
70
71 /**
72 * Creates a BLOB encapsulating the given binary data
73 */
74 Blob(byte[] data) {
75 setBinaryData(data);
76 this.creatorResultSet = null;
77 this.columnIndex = 0;
78 }
79
80 /**
81 * Creates an updatable BLOB that can update in-place
82 * (not implemented yet).
83 */
84 Blob(byte[] data, ResultSet creatorResultSet, int columnIndex) {
85 setBinaryData(data);
86 this.creatorResultSet = creatorResultSet;
87 this.columnIndex = columnIndex;
88 }
89
90 //~ Methods ----------------------------------------------------------------
91
92 /**
93 * @see Blob#setBinaryStream(long)
94 */
95 public OutputStream setBinaryStream(long indexToWriteAt)
96 throws SQLException {
97 if (indexToWriteAt < 1) {
98 throw new SQLException("indexToWriteAt must be >= 1", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
99 }
100
101 WatchableOutputStream bytesOut = new WatchableOutputStream();
102 bytesOut.setWatcher(this);
103
104 if (indexToWriteAt > 0) {
105 bytesOut.write(this.binaryData, 0, (int) (indexToWriteAt - 1));
106 }
107
108 return bytesOut;
109 }
110
111 /**
112 * Retrieves the BLOB designated by this Blob instance as a stream.
113 *
114 * @return this BLOB represented as a binary stream of bytes.
115 *
116 * @throws SQLException if a database error occurs
117 */
118 public java.io.InputStream getBinaryStream() throws SQLException {
119 return new ByteArrayInputStream(getBinaryData());
120 }
121
122 /**
123 * @see Blob#setBytes(long, byte[], int, int)
124 */
125 public int setBytes(long writeAt, byte[] bytes, int offset, int length)
126 throws SQLException {
127 OutputStream bytesOut = setBinaryStream(writeAt);
128
129 try {
130 bytesOut.write(bytes, offset, length);
131 } catch (IOException ioEx) {
132 throw new SQLException("IO Error while writing bytes to blob",
133 SQLError.SQL_STATE_GENERAL_ERROR);
134 } finally {
135 try {
136 bytesOut.close();
137 } catch (IOException doNothing) {
138 ; // do nothing
139 }
140 }
141
142 return length;
143 }
144
145 /**
146 * @see Blob#setBytes(long, byte[])
147 */
148 public int setBytes(long writeAt, byte[] bytes) throws SQLException {
149 return setBytes(writeAt, bytes, 0, bytes.length);
150 }
151
152 /**
153 * Returns as an array of bytes, part or all of the BLOB value that this
154 * Blob object designates.
155 *
156 * @param pos where to start the part of the BLOB
157 * @param length the length of the part of the BLOB you want returned.
158 *
159 * @return the bytes stored in the blob starting at position
160 * <code>pos</code> and having a length of <code>length</code>.
161 *
162 * @throws SQLException if a database error occurs
163 */
164 public byte[] getBytes(long pos, int length) throws SQLException {
165 if (pos < 1) {
166 throw new SQLException("Position 'pos' can not be < 1", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
167 }
168
169 byte[] newData = new byte[length];
170 System.arraycopy(getBinaryData(), (int) (pos - 1), newData, 0, length);
171
172 return newData;
173 }
174
175 /**
176 * Returns the number of bytes in the BLOB value designated by this Blob
177 * object.
178 *
179 * @return the length of this blob
180 *
181 * @throws SQLException if a database error occurs
182 */
183 public long length() throws SQLException {
184 return getBinaryData().length;
185 }
186
187 /**
188 * Finds the position of the given pattern in this BLOB.
189 *
190 * @param pattern the pattern to find
191 * @param start where to start finding the pattern
192 *
193 * @return the position where the pattern is found in the BLOB, -1 if not
194 * found
195 *
196 * @throws SQLException if a database error occurs
197 */
198 public long position(java.sql.Blob pattern, long start)
199 throws SQLException {
200 return position(pattern.getBytes(0, (int) pattern.length()), start);
201 }
202
203 /**
204 * @see java.sql.Blob#position(byte[], long)
205 */
206 public long position(byte[] pattern, long start) throws SQLException {
207 throw new SQLException("Not implemented");
208 }
209
210 /**
211 * @see com.mysql.jdbc.OutputStreamWatcher#streamClosed(byte[])
212 */
213 public void streamClosed(WatchableOutputStream out) {
214 int streamSize = out.size();
215
216 if (streamSize < this.binaryData.length) {
217 out.write(this.binaryData, streamSize, this.binaryData.length - streamSize);
218 }
219
220 this.binaryData = out.toByteArray();
221 }
222
223 /**
224 * @see Blob#truncate(long)
225 */
226 public void truncate(long arg0) throws SQLException {
227 throw new NotImplemented();
228 }
229
230 private void setBinaryData(byte[] newBinaryData) {
231 this.binaryData = newBinaryData;
232 }
233
234 private byte[] getBinaryData() {
235 return binaryData;
236 }
237 }