001: /*
002:
003: Derby - Class org.apache.derby.impl.jdbc.EmbedClob
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.impl.jdbc;
023:
024: import org.apache.derby.iapi.reference.SQLState;
025: import org.apache.derby.iapi.error.StandardException;
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027: import org.apache.derby.iapi.types.DataValueDescriptor;
028: import org.apache.derby.iapi.types.Resetable;
029: import org.apache.derby.impl.jdbc.ConnectionChild;
030: import org.apache.derby.impl.jdbc.EmbedConnection;
031: import org.apache.derby.impl.jdbc.Util;
032: import org.apache.derby.impl.jdbc.UTF8Reader;
033: import org.apache.derby.impl.jdbc.ReaderToAscii;
034:
035: import java.io.InputStream;
036: import java.io.InputStreamReader;
037: import java.io.StringReader;
038: import java.io.Reader;
039: import java.io.IOException;
040: import java.io.EOFException;
041: import java.sql.SQLException;
042: import java.sql.Clob;
043:
044: /**
045: Implements java.sql.Clob (see the JDBC 2.0 spec).
046: A clob sits on top of a CHAR, VARCHAR or LONG VARCHAR column.
047: If its data is small (less than 1 page) it is a byte array taken from
048: the SQLChar class. If it is large (more than 1 page) it is a long column
049: in the database. The long column is accessed as a stream, and is implemented
050: in store as an OverflowInputStream. The Resetable interface allows sending
051: messages to that stream to initialize itself (reopen its container and
052: lock the corresponding row) and to reset itself to the beginning.
053:
054: NOTE: In the case that the data is large, it is represented as a stream.
055: This stream can be returned to the user in the getAsciiStream() method.
056: This means that we have limited control over the state of the stream,
057: since the user can read bytes from it at any time. Thus all methods
058: here reset the stream to the beginning before doing any work.
059: CAVEAT: The methods may not behave correctly if a user sets up
060: multiple threads and sucks data from the stream (returned from
061: getAsciiStream()) at the same time as calling the Clob methods.
062:
063: <P><B>Supports</B>
064: <UL>
065: <LI> JSR169 - no subsetting for java.sql.Clob
066: <LI> JDBC 2.0
067: <LI> JDBC 3.0 - no new dependencies on new JDBC 3.0 or JDK 1.4 classes,
068: new update methods can safely be added into implementation.
069: </UL>
070: */
071: final class EmbedClob extends ConnectionChild implements Clob {
072: // clob is either a string or stream
073: private boolean isString;
074: private InputStream myStream;
075: private String myString;
076:
077: //This boolean variable indicates whether the Clob object has
078: //been invalidated by calling free() on it
079: private boolean isValid = true;
080:
081: /**
082: * This constructor is used to create a empty Clob object. It is used by the
083: * Connection interface method createClob().
084: *
085: * @param clobString A String object containing the data to be stores in the
086: * Clob.
087: *
088: * @param con The Connection object associated with this EmbedClob object.
089: *
090: */
091:
092: EmbedClob(String clobString, EmbedConnection con) {
093: super (con);
094: myString = clobString;
095: isString = true;
096: }
097:
098: /*
099: This constructor should only be called by EmbedResultSet.getClob
100: */
101: protected EmbedClob(DataValueDescriptor dvd, EmbedConnection con)
102: throws StandardException {
103: super (con);
104: // if the underlying column is null, ResultSet.getClob will return null,
105: // never should get this far
106: if (SanityManager.DEBUG)
107: SanityManager.ASSERT(!dvd.isNull(),
108: "clob is created on top of a null column");
109:
110: myStream = dvd.getStream();
111: if (myStream == null) {
112: isString = true;
113: myString = dvd.getString();
114: if (SanityManager.DEBUG)
115: SanityManager.ASSERT(myString != null,
116: "clob has a null value underneath");
117: } else {
118: /*
119: We are expecting this stream to be a FormatIdInputStream with an
120: OverflowInputStream inside. FormatIdInputStream implements
121: Resetable, as does OverflowInputStream. This should be the case
122: when retrieving data from a long column. However, SQLChar, which is
123: the class implementing the getStream() method for dvd.getStream(),
124: does not guarantee this for us. In particular, the logging system
125: (see StoredPage.logColumn) calls setStream with an argument that
126: is sometimes a RememberBytesInputStream on a SQLChar object
127: (e.g. see test repStreaming.sql). However, such a SQLChar
128: object is going to the log buffer, NOT back to the user, so it
129: should not break the ASSERT below.
130: */
131: if (SanityManager.DEBUG)
132: SanityManager.ASSERT(myStream instanceof Resetable);
133:
134: try {
135: ((Resetable) myStream).initStream();
136: } catch (StandardException se) {
137: if (se.getMessageId().equals(
138: SQLState.DATA_CONTAINER_CLOSED)) {
139: throw StandardException
140: .newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);
141: }
142: }
143: }
144: }
145:
146: /**
147: * Returns the number of characters
148: * in the <code>CLOB</code> value
149: * designated by this <code>Clob</code> object.
150: * @return length of the <code>CLOB</code> in characters
151: * @exception SQLException if there is an error accessing the
152: * length of the <code>CLOB</code>
153: */
154:
155: public long length() throws SQLException {
156: //call checkValidity to exit by throwing a SQLException if
157: //the Clob object has been freed by calling free() on it
158: checkValidity();
159: // if we have a string, not a stream
160: if (isString)
161: return myString.length();
162:
163: Object synchronization = getConnectionSynchronization();
164: synchronized (synchronization) {
165: Reader clobReader = null;
166: setupContextStack();
167: try {
168:
169: clobReader = getCharacterStream();
170: long clobLength = 0;
171: for (;;) {
172: long size = clobReader.skip(32 * 1024);
173: if (size == -1)
174: break;
175: clobLength += size;
176: }
177: clobReader.close();
178: clobReader = null;
179:
180: return clobLength;
181: } catch (Throwable t) {
182: throw noStateChangeLOB(t);
183: } finally {
184: if (clobReader != null) {
185: try {
186: clobReader.close();
187: } catch (IOException ioe) {
188: }
189: }
190: restoreContextStack();
191: }
192: }
193: }
194:
195: /**
196: * Returns a copy of the specified substring
197: * in the <code>CLOB</code> value
198: * designated by this <code>Clob</code> object.
199: * The substring begins at position
200: * <code>pos</code> and has up to <code>length</code> consecutive
201: * characters. The starting position must be between 1 and the length
202: * of the CLOB plus 1. This allows for zero-length CLOB values, from
203: * which only zero-length substrings can be returned.
204: * If a larger length is requested than there are characters available,
205: * characters from the start position to the end of the CLOB are returned.
206: * @param pos the first character of the substring to be extracted.
207: * The first character is at position 1.
208: * @param length the number of consecutive characters to be copied
209: * @return a <code>String</code> that is the specified substring in
210: * the <code>CLOB</code> value designated by this <code>Clob</code> object
211: * @exception SQLException if there is an error accessing the
212: * <code>CLOB</code>
213:
214: * NOTE: If the starting position is the length of the CLOB plus 1,
215: * zero characters are returned regardless of the length requested.
216: */
217: public String getSubString(long pos, int length)
218: throws SQLException {
219: //call checkValidity to exit by throwing a SQLException if
220: //the Clob object has been freed by calling free() on it
221: checkValidity();
222:
223: if (pos < 1)
224: throw Util.generateCsSQLException(
225: SQLState.BLOB_BAD_POSITION, new Long(pos));
226: if (length < 0)
227: throw Util.generateCsSQLException(
228: SQLState.BLOB_NONPOSITIVE_LENGTH, new Integer(
229: length));
230:
231: // if we have a string, not a stream
232: if (isString) {
233: int sLength = myString.length();
234: if (sLength + 1 < pos)
235: throw Util
236: .generateCsSQLException(
237: SQLState.BLOB_POSITION_TOO_LARGE,
238: new Long(pos));
239: int endIndex = ((int) pos) + length - 1;
240: // cannot go over length of string
241: return myString.substring(((int) pos) - 1,
242: (sLength > endIndex ? endIndex : sLength));
243: }
244:
245: Object synchronization = getConnectionSynchronization();
246: synchronized (synchronization) {
247: setupContextStack();
248:
249: UTF8Reader clobReader = null;
250: try {
251:
252: clobReader = getCharacterStreamAtPos(pos,
253: synchronization);
254: if (clobReader == null)
255: throw StandardException.newException(
256: SQLState.BLOB_POSITION_TOO_LARGE, new Long(
257: pos));
258:
259: StringBuffer sb = new StringBuffer(length);
260: int remainToRead = length;
261: while (remainToRead > 0) {
262:
263: int read = clobReader.readInto(sb, remainToRead);
264: if (read == -1)
265: break;
266:
267: remainToRead -= read;
268: }
269: clobReader.close();
270: clobReader = null;
271:
272: return sb.toString();
273: } catch (Throwable t) {
274: throw noStateChangeLOB(t);
275: } finally {
276: if (clobReader != null)
277: clobReader.close();
278: restoreContextStack();
279: }
280: }
281: }
282:
283: /**
284: * Gets the <code>Clob</code> contents as a Unicode stream.
285: * @return a Unicode stream containing the <code>CLOB</code> data
286: * @exception SQLException if there is an error accessing the
287: * <code>CLOB</code>
288: */
289:
290: public java.io.Reader getCharacterStream() throws SQLException {
291: //call checkValidity to exit by throwing a SQLException if
292: //the Clob object has been freed by calling free() on it
293: checkValidity();
294:
295: // if we have a string, not a stream
296: if (isString) {
297: return new StringReader(myString);
298: }
299:
300: Object synchronization = getConnectionSynchronization();
301: synchronized (synchronization) {
302: setupContextStack();
303:
304: try {
305: return getCharacterStreamAtPos(1, synchronization);
306: } catch (Throwable t) {
307: throw noStateChangeLOB(t);
308: } finally {
309: restoreContextStack();
310: }
311: }
312: }
313:
314: /**
315: * Gets the <code>CLOB</code> value designated by this <code>Clob</code>
316: * object as a stream of Ascii bytes.
317: * @return an ascii stream containing the <code>CLOB</code> data
318: * @exception SQLException if there is an error accessing the
319: * <code>CLOB</code> value
320: */
321:
322: public java.io.InputStream getAsciiStream() throws SQLException {
323: //call checkValidity to exit by throwing a SQLException if
324: //the Clob object has been freed by calling free() on it
325: checkValidity();
326: return new ReaderToAscii(getCharacterStream());
327: }
328:
329: private UTF8Reader getCharacterStreamAtPos(long position,
330: Object synchronization) throws IOException,
331: StandardException {
332: ((Resetable) myStream).resetStream();
333: UTF8Reader clobReader = new UTF8Reader(myStream, 0, this ,
334: synchronization);
335:
336: // skip to the correct position (pos is one based)
337: long remainToSkip = position - 1;
338: while (remainToSkip > 0) {
339: long skipBy = clobReader.skip(remainToSkip);
340: if (skipBy == -1)
341: return null;
342:
343: remainToSkip -= skipBy;
344: }
345:
346: return clobReader;
347: }
348:
349: /**
350: * Determines the character position at which the specified substring
351: * <code>searchstr</code> appears in the <code>CLOB</code>. The search
352: * begins at position <code>start</code>.
353: * @param searchStr the substring for which to search
354: * @param start the position at which to begin searching; the first position
355: * is 1
356: * @return the position at which the substring appears, else -1; the first
357: * position is 1
358: * @exception SQLException if there is an error accessing the
359: * <code>CLOB</code> value
360: */
361: public long position(String searchStr, long start)
362: throws SQLException {
363: //call checkValidity to exit by throwing a SQLException if
364: //the Clob object has been freed by calling free() on it
365: checkValidity();
366:
367: boolean pushStack = false;
368: try {
369: if (start < 1)
370: throw StandardException.newException(
371: SQLState.BLOB_BAD_POSITION, new Long(start));
372: if (searchStr == null)
373: throw StandardException
374: .newException(SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);
375: if (searchStr == "")
376: return start; // match DB2's SQL LOCATE function
377:
378: // if we have a string, not a stream
379: if (isString) {
380: // avoid truncation errors in the cast of start to an int.
381: if (start > myString.length())
382: return -1;
383:
384: int result = myString.indexOf(searchStr,
385: (int) start - 1);
386: return result < 0 ? -1 : result + 1;
387: } else // we have a stream
388: {
389: Object synchronization = getConnectionSynchronization();
390: synchronized (synchronization) {
391: pushStack = !getEmbedConnection().isClosed();
392: if (pushStack)
393: setupContextStack();
394:
395: char[] tmpClob = new char[256];
396: int patternLength = searchStr.length();
397:
398: restartPattern: for (;;) {
399:
400: //System.out.println("RESET " + start);
401: UTF8Reader clobReader = getCharacterStreamAtPos(
402: start, synchronization);
403: if (clobReader == null)
404: return -1;
405:
406: // start of any match of the complete pattern.
407:
408: int patternIndex = 0;
409: char[] tmpPattern = null;
410: boolean needPattern = true;
411:
412: // how many characters of the patter segment we have matched
413: int matchCount = 0;
414:
415: long currentPosition = start;
416: int clobOffset = -1;
417: int read = -1;
418:
419: // absolute position of a possible match
420: long matchPosition = -1;
421:
422: // absolute position of the next possible match
423: long nextBestMatchPosition = -1;
424: //System.out.println("restartPattern: " + start);
425:
426: search: for (;;) {
427: //System.out.println("search: " + needPattern + " -- " + clobOffset);
428: if (needPattern) {
429:
430: String tmpPatternS;
431: if ((patternLength - patternIndex) > 256)
432: tmpPatternS = searchStr.substring(
433: patternIndex, 256);
434: else
435: tmpPatternS = searchStr;
436:
437: tmpPattern = tmpPatternS.toCharArray();
438: needPattern = false;
439: matchCount = 0;
440:
441: }
442:
443: if (clobOffset == -1) {
444:
445: read = clobReader.read(tmpClob, 0,
446: tmpClob.length);
447: //System.out.println("MORE DATA " + read);
448: if (read == -1)
449: return -1;
450:
451: if (read == 0)
452: continue search;
453:
454: clobOffset = 0;
455: }
456:
457: // find matches within our two temp arrays.
458: compareArrays: for (; clobOffset < read; clobOffset++) {
459:
460: //System.out.println("compareArrays " + clobOffset);
461:
462: char clobC = tmpClob[clobOffset];
463:
464: if (clobC == tmpPattern[matchCount]) {
465: if (matchPosition == -1) {
466: matchPosition = currentPosition
467: + clobOffset;
468: }
469:
470: matchCount++;
471:
472: // have we matched the entire pattern segment
473: if (matchCount == tmpPattern.length) {
474: // move onto the next segment.
475: patternIndex += tmpPattern.length;
476: if (patternIndex == patternLength) {
477: // complete match !!
478: clobReader.close();
479: //System.out.println("COMPLETE@" + matchPosition);
480: return matchPosition;
481: }
482:
483: needPattern = true;
484: continue search;
485:
486: }
487:
488: if (clobC == tmpPattern[0]) {
489:
490: // save the next best start position.
491:
492: // must be the first character of the actual pattern
493: if (patternIndex == 0) {
494:
495: // must not be just a repeat of the match of the first character
496: if (matchCount != 1) {
497:
498: // must not have a previous next best.
499:
500: if (nextBestMatchPosition == -1) {
501: nextBestMatchPosition = currentPosition
502: + clobOffset;
503: }
504:
505: }
506:
507: }
508: }
509:
510: continue compareArrays;
511: } else {
512: // not a match
513: //
514: //
515: if (matchPosition != -1) {
516: // failed after we matched some amount of the pattern
517: matchPosition = -1;
518:
519: // See if we found a next best match
520: if (nextBestMatchPosition == -1) {
521: // NO - just continue on, re-starting at this character
522:
523: if (patternIndex != 0) {
524: needPattern = true;
525: continue search;
526: }
527: } else if (nextBestMatchPosition >= currentPosition) {
528: // restart in the current array
529: clobOffset = (int) (nextBestMatchPosition - currentPosition);
530: nextBestMatchPosition = -1;
531:
532: if (patternIndex != 0) {
533: needPattern = true;
534: continue search;
535: }
536: } else {
537: clobReader.close();
538: start = nextBestMatchPosition;
539: continue restartPattern;
540: }
541:
542: clobOffset--; // since the continue will increment it
543: matchCount = 0;
544: continue compareArrays;
545: }
546:
547: // no current match, just continue
548: }
549: }
550:
551: currentPosition += read;
552:
553: // indicates we need to read more data
554: clobOffset = -1;
555: }
556: }
557: }
558: }
559: } catch (Throwable t) {
560: throw noStateChangeLOB(t);
561: } finally {
562: if (pushStack)
563: restoreContextStack();
564: }
565:
566: }
567:
568: /**
569: * Determines the character position at which the specified
570: * <code>Clob</code> object <code>searchstr</code> appears in this
571: * <code>Clob</code> object. The search begins at position
572: * <code>start</code>.
573: * @param searchClob the <code>Clob</code> object for which to search
574: * @param start the position at which to begin searching; the first
575: * position is 1
576: * @return the position at which the <code>Clob</code> object appears,
577: * else -1; the first position is 1
578: * @exception SQLException if there is an error accessing the
579: * <code>CLOB</code> value
580: */
581:
582: public long position(Clob searchClob, long start)
583: throws SQLException {
584: //call checkValidity to exit by throwing a SQLException if
585: //the Clob object has been freed by calling free() on it
586: checkValidity();
587:
588: boolean pushStack = false;
589: try {
590: if (start < 1)
591: throw StandardException.newException(
592: SQLState.BLOB_BAD_POSITION, new Long(start));
593: if (searchClob == null)
594: throw StandardException
595: .newException(SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);
596:
597: synchronized (getConnectionSynchronization()) {
598: char[] subPatternChar = new char[256];
599:
600: boolean seenOneCharacter = false;
601:
602: //System.out.println("BEGIN CLOB SEARCH @ " + start);
603:
604: restartScan: for (;;) {
605:
606: long firstPosition = -1;
607:
608: Reader patternReader = searchClob
609: .getCharacterStream();
610:
611: //System.out.println("RESTART CLOB SEARCH @ " + start);
612:
613: try {
614:
615: for (;;) {
616:
617: int read = patternReader.read(
618: subPatternChar, 0,
619: subPatternChar.length);
620: if (read == -1) {
621: //empty pattern
622: if (!seenOneCharacter)
623: return start; // matches DB2 SQL LOCATE function
624:
625: return firstPosition;
626: }
627: if (read == 0) {
628: //System.out.println("STUCK IN READ 0 HELL");
629: continue;
630: }
631:
632: seenOneCharacter = true;
633:
634: String subPattern = new String(
635: subPatternChar, 0, read);
636: //System.out.println("START CLOB SEARCH @ " + start + " -- " + subPattern);
637: long position = position(subPattern, start);
638: //System.out.println("DONE SUB CLOB SEARCH @ " + start + " -- " + position);
639: if (position == -1) {
640: // never seen any match
641: if (firstPosition == -1)
642: return -1;
643:
644: start = firstPosition + 1;
645: continue restartScan;
646: }
647:
648: if (firstPosition == -1)
649: firstPosition = position;
650: else if (position != start) {
651: // must match at the first character of the segment
652: start = firstPosition + 1;
653: continue restartScan;
654: }
655:
656: // read is the length of the subPattern string
657: start = position + read;
658: }
659: } finally {
660: patternReader.close();
661: }
662: }
663: }
664: } catch (Throwable t) {
665: throw noStateChangeLOB(t);
666: } finally {
667: if (pushStack)
668: restoreContextStack();
669: }
670:
671: }
672:
673: /*
674: If we have a stream, release the resources associated with it.
675: */
676: protected void finalize() {
677: // System.out.println("finalizer called");
678: if (!isString)
679: ((Resetable) myStream).closeStream();
680: }
681:
682: /**
683: Following methods are for the new JDBC 3.0 methods in java.sql.Clob
684: (see the JDBC 3.0 spec). We have the JDBC 3.0 methods in Local20
685: package, so we don't have to have a new class in Local30.
686: The new JDBC 3.0 methods don't make use of any new JDBC3.0 classes and
687: so this will work fine in jdbc2.0 configuration.
688: */
689:
690: /////////////////////////////////////////////////////////////////////////
691: //
692: // JDBC 3.0 - New public methods
693: //
694: /////////////////////////////////////////////////////////////////////////
695: /**
696: * JDBC 3.0
697: *
698: * Writes the given Java String to the CLOB value that this Clob object designates
699: * at the position pos.
700: *
701: * @param pos - the position at which to start writing to the CLOB value that
702: * this Clob object represents
703: * @return the number of characters written
704: * @exception SQLException Feature not implemented for now.
705: */
706: public int setString(long pos, String parameterName)
707: throws SQLException {
708: throw Util.notImplemented();
709: }
710:
711: /**
712: * JDBC 3.0
713: *
714: * Writes len characters of str, starting at character offset, to the CLOB value
715: * that this Clob represents.
716: *
717: * @param pos - the position at which to start writing to this Clob object
718: * @param str - the string to be written to the CLOB value that this Clob designates
719: * @param offset - the offset into str to start reading the characters to be written
720: * @param len - the number of characters to be written
721: * @return the number of characters written
722: * @exception SQLException Feature not implemented for now.
723: */
724: public int setString(long pos, String str, int offset, int len)
725: throws SQLException {
726: throw Util.notImplemented();
727: }
728:
729: /**
730: * JDBC 3.0
731: *
732: * Retrieves a stream to be used to write Ascii characters to the CLOB
733: * value that this Clob object represents, starting at position pos.
734: *
735: * @param pos - the position at which to start writing to this Clob object
736: * @return the stream to which ASCII encoded characters can be written
737: * @exception SQLException Feature not implemented for now.
738: */
739: public java.io.OutputStream setAsciiStream(long pos)
740: throws SQLException {
741: throw Util.notImplemented();
742: }
743:
744: /**
745: * JDBC 3.0
746: *
747: * Retrieves a stream to be used to write a stream of Unicode characters to the
748: * CLOB value that this Clob object represents, starting at position pos.
749: *
750: * @param pos - the position at which to start writing to this Clob object
751: * @return the stream to which Unicode encoded characters can be written
752: * @exception SQLException Feature not implemented for now.
753: */
754: public java.io.Writer setCharacterStream(long pos)
755: throws SQLException {
756: throw Util.notImplemented();
757: }
758:
759: /**
760: * JDBC 3.0
761: *
762: * Truncates the CLOB value that this Clob designates to have a length of len characters
763: *
764: * @param len - the length, in bytes, to which the CLOB value that this Blob
765: * value should be truncated
766: * @exception SQLException Feature not implemented for now.
767: */
768: public void truncate(long len) throws SQLException {
769: throw Util.notImplemented();
770: }
771:
772: /////////////////////////////////////////////////////////////////////////
773: //
774: // JDBC 4.0 - New public methods
775: //
776: /////////////////////////////////////////////////////////////////////////
777: /**
778: * This method frees the <code>Clob</code> object and releases the resources the resources
779: * that it holds. The object is invalid once the <code>free</code> method
780: * is called. If <code>free</code> is called multiple times, the
781: * subsequent calls to <code>free</code> are treated as a no-op.
782: *
783: * @throws SQLException if an error occurs releasing
784: * the Clob's resources
785: */
786: public void free() throws SQLException {
787: //calling free() on a already freed object is treated as a no-op
788: if (!isValid)
789: return;
790:
791: //now that free has been called the Clob object is no longer
792: //valid
793: isValid = false;
794:
795: if (!isString)
796: ((Resetable) myStream).closeStream();
797: else
798: myString = null;
799: }
800:
801: public java.io.Reader getCharacterStream(long pos, long length)
802: throws SQLException {
803: throw Util.notImplemented();
804: }
805:
806: /*
807: **
808: */
809:
810: static SQLException noStateChangeLOB(Throwable t) {
811: if (t instanceof StandardException) {
812: // container closed means the blob or clob was accessed after commit
813: if (((StandardException) t).getMessageId().equals(
814: SQLState.DATA_CONTAINER_CLOSED)) {
815: t = StandardException
816: .newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);
817: }
818: }
819: return org.apache.derby.impl.jdbc.EmbedResultSet
820: .noStateChangeException(t);
821: }
822:
823: /*
824: * Checks is isValid is true. If it is not true throws
825: * a SQLException stating that a method has been called on
826: * an invalid LOB object
827: *
828: * throws SQLException if isValid is not true.
829: */
830: private void checkValidity() throws SQLException {
831: if (!isValid)
832: throw newSQLException(SQLState.LOB_OBJECT_INVALID);
833: }
834: }
|