001: /*
002:
003: Derby - Class org.apache.derby.iapi.types.SQLBlob
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.iapi.types;
023:
024: import org.apache.derby.iapi.types.DataTypeDescriptor;
025: import org.apache.derby.iapi.types.DataValueDescriptor;
026: import org.apache.derby.iapi.types.TypeId;
027: import org.apache.derby.iapi.types.BitDataValue;
028: import org.apache.derby.iapi.types.DataValueDescriptor;
029: import org.apache.derby.iapi.reference.SQLState;
030: import org.apache.derby.iapi.reference.Limits;
031: import org.apache.derby.iapi.error.StandardException;
032:
033: import org.apache.derby.iapi.types.Orderable;
034:
035: import org.apache.derby.iapi.services.io.FormatIdUtil;
036: import org.apache.derby.iapi.services.io.StoredFormatIds;
037:
038: import org.apache.derby.iapi.services.sanity.SanityManager;
039:
040: import org.apache.derby.iapi.types.BooleanDataValue;
041: import org.apache.derby.iapi.types.StringDataValue;
042: import org.apache.derby.iapi.types.NumberDataValue;
043:
044: import org.apache.derby.iapi.services.io.FormatableBitSet;
045:
046: import java.io.ObjectOutput;
047: import java.io.ObjectInput;
048: import java.io.IOException;
049: import java.sql.Blob;
050: import java.sql.ResultSet;
051: import java.sql.SQLException;
052: import java.sql.PreparedStatement;
053:
054: /**
055: * SQLBlob satisfies the DataValueDescriptor,
056: * interfaces (i.e., OrderableDataType).
057: * It uses the SQLLongVarbit implementation, which implements a String holder,
058: * e.g. for storing a column value; it can be specified
059: * when constructed to not allow nulls. Nullability cannot be changed
060: * after construction.
061: * <p>
062: * Because LOB types are not orderable, we'll override those
063: * methods...
064: *
065: */
066: public class SQLBlob extends SQLBinary {
067:
068: /*
069: * constructors
070: */
071: public SQLBlob() {
072: }
073:
074: public SQLBlob(byte[] val) {
075: super (val);
076: }
077:
078: public String getTypeName() {
079: return TypeId.BLOB_NAME;
080: }
081:
082: /**
083: * Return max memory usage for a SQL Blob
084: */
085: int getMaxMemoryUsage() {
086: return Limits.DB2_LOB_MAXWIDTH;
087: }
088:
089: /**
090: * @see DataValueDescriptor#getNewNull
091: */
092: public DataValueDescriptor getNewNull() {
093: return new SQLBlob();
094: }
095:
096: /**
097: * Normalization method - this method may be called when putting
098: * a value into a SQLBit, for example, when inserting into a SQLBit
099: * column. See NormalizeResultSet in execution.
100: *
101: * @param desiredType The type to normalize the source column to
102: * @param source The value to normalize
103: *
104: * @exception StandardException Thrown for null into
105: * non-nullable column, and for
106: * truncation error
107: */
108:
109: public void normalize(DataTypeDescriptor desiredType,
110: DataValueDescriptor source) throws StandardException {
111: setValue(source);
112: setWidth(desiredType.getMaximumWidth(), 0, true);
113: }
114:
115: // The method setWidth is only(?) used to adopt the value
116: // to the casted domain/size. BLOBs behave different
117: // from the BIT types in that a (CAST (X'01' TO BLOB(1024)))
118: // does NOT pad the value to the maximal allowed datasize.
119: // That it is done for BIT is understandable, however,
120: // for BIT VARYING it is a bit confusing. Could be inheritence bug.
121: // Anyhow, here we just ignore the call, since there is no padding to be done.
122: // We do detect truncation, if the errorOnTrunc flag is set.
123: // DB2 does return a WARNING on CAST and ERROR on INSERT.
124: public void setWidth(int desiredWidth, // ignored!
125: int desiredScale, // Ignored
126: boolean errorOnTrunc) throws StandardException {
127:
128: // Input is null, so there's nothing to do.
129: if (isNull())
130: return;
131:
132: // Input is a stream with unknown length. The length will be checked
133: // while reading the stream.
134: if (isLengthLess()) {
135: return;
136: }
137:
138: int sourceWidth = getLength();
139:
140: // need to truncate?
141: if (sourceWidth > desiredWidth) {
142: if (errorOnTrunc)
143: throw StandardException.newException(
144: SQLState.LANG_STRING_TRUNCATION, getTypeName(),
145: "XXXX", String.valueOf(desiredWidth));
146: else {
147: /*
148: * Truncate to the desired width.
149: */
150:
151: byte[] shrunkData = new byte[desiredWidth];
152: System.arraycopy(getBytes(), 0, shrunkData, 0,
153: desiredWidth);
154: dataValue = shrunkData;
155: }
156: }
157: }
158:
159: /**
160: * Gets a trace representation of the BLOB for debugging.
161: *
162: * @return a trace representation of the BLOB.
163: */
164: public final String getTraceString() throws StandardException {
165: // Check if the value is SQL NULL.
166: if (isNull()) {
167: return "NULL";
168: }
169:
170: // Check if we have a stream.
171: if (getStream() != null) {
172: return ("BLOB(" + getStream().toString() + ")");
173: }
174:
175: return ("BLOB(" + getLength() + ")");
176: }
177:
178: /**
179: Return my format identifier.
180:
181: @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
182: */
183: public int getTypeFormatId() {
184: return StoredFormatIds.SQL_BLOB_ID;
185: }
186:
187: /**
188: * @see DataValueDescriptor#setValueFromResultSet
189: *
190: * @exception SQLException Thrown on error
191: * @throws StandardException
192: */
193: public void setValueFromResultSet(ResultSet resultSet,
194: int colNumber, boolean isNullable) throws SQLException,
195: StandardException {
196: Blob blob = resultSet.getBlob(colNumber);
197: if (blob == null)
198: setToNull();
199: else
200: setObject(blob);
201: }
202:
203: /*
204: * DataValueDescriptor interface
205: */
206:
207: /** @see DataValueDescriptor#typePrecedence */
208: public int typePrecedence() {
209: return TypeId.BLOB_PRECEDENCE; // not really used
210: }
211:
212: public void setInto(PreparedStatement ps, int position)
213: throws SQLException, StandardException {
214: if (isNull()) {
215: ps.setBlob(position, null);
216: return;
217: }
218:
219: // This may cause problems for streaming blobs, by materializing the whole blob.
220: ps.setBytes(position, getBytes());
221: }
222:
223: /**
224: * Set the value from an non-null object.
225: */
226: final void setObject(Object theValue) throws StandardException {
227: Blob vb = (Blob) theValue;
228:
229: try {
230: long vbl = vb.length();
231: if (vbl < 0L || vbl > Integer.MAX_VALUE)
232: throw this .outOfRange();
233:
234: setValue(new RawToBinaryFormatStream(vb.getBinaryStream(),
235: (int) vbl), (int) vbl);
236:
237: } catch (SQLException e) {
238: throw dataTypeConversion("DAN-438-tmp");
239: }
240: }
241:
242: /**
243: * Tell if this blob is length less.
244: *
245: * @return <code>true</code> if the length of the blob is not known,
246: * <code>false</code> otherwise
247: */
248: private final boolean isLengthLess() {
249: return (stream != null && streamValueLength < 0);
250: }
251: }
|