KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > iapi > types > SQLBinary


1 /*
2
3    Derby - Class org.apache.derby.iapi.types.SQLBinary
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.iapi.types;
23
24 import org.apache.derby.iapi.reference.SQLState;
25
26 import org.apache.derby.iapi.services.io.ArrayInputStream;
27 import org.apache.derby.iapi.services.io.FormatableBitSet;
28 import org.apache.derby.iapi.services.io.NewByteArrayInputStream;
29
30 import org.apache.derby.iapi.types.DataTypeDescriptor;
31 import org.apache.derby.iapi.types.DataValueDescriptor;
32 import org.apache.derby.iapi.types.TypeId;
33 import org.apache.derby.iapi.types.BitDataValue;
34 import org.apache.derby.iapi.types.DataValueDescriptor;
35 import org.apache.derby.iapi.types.ConcatableDataValue;
36 import org.apache.derby.iapi.types.VariableSizeDataValue;
37 import org.apache.derby.iapi.error.StandardException;
38
39 import org.apache.derby.iapi.services.io.FormatIdUtil;
40 import org.apache.derby.iapi.services.io.StoredFormatIds;
41 import org.apache.derby.iapi.services.io.StreamStorable;
42 import org.apache.derby.iapi.services.io.FormatIdInputStream;
43
44 import org.apache.derby.iapi.services.sanity.SanityManager;
45
46 import org.apache.derby.iapi.types.BooleanDataValue;
47 import org.apache.derby.iapi.types.StringDataValue;
48 import org.apache.derby.iapi.types.NumberDataValue;
49
50 import org.apache.derby.iapi.services.cache.ClassSize;
51 import org.apache.derby.iapi.util.StringUtil;
52
53 import org.apache.derby.iapi.types.SQLInteger;
54
55 import java.io.ObjectOutput JavaDoc;
56 import java.io.ObjectInput JavaDoc;
57 import java.io.IOException JavaDoc;
58 import java.io.InputStream JavaDoc;
59
60 import java.sql.ResultSet JavaDoc;
61 import java.sql.SQLException JavaDoc;
62 import java.sql.PreparedStatement JavaDoc;
63
64 /**
65  * SQLBinary is the abstract class for the binary datatypes.
66  * <UL>
67  * <LI> CHAR FOR BIT DATA
68  * <LI> VARCHAR FOR BIT DATA
69  * <LI> LONG VARCHAR
70  * <LI> BLOB
71  * </UL>
72
73   <P>
74   Format : <encoded length><raw data>
75   <BR>
76   Length is encoded to support Cloudscape 5.x databases where the length was stored as the number of bits.
77   The first bit of the first byte indicates if the format is an old (Cloudscape 5.x) style or a new Derby style.
78   Derby then uses the next two bits to indicate how the length is encoded.
79   <BR>
80   <encoded length> is one of N styles.
81   <UL>
82   <LI> (5.x format zero) 4 byte Java format integer value 0 - either <raw data> is 0 bytes/bits or an unknown number of bytes.
83   <LI> (5.x format bits) 4 byte Java format integer value >0 (positive) - number of bits in <raw data>, number of bytes in <raw data>
84   is the minimum number of bytes required to store the number of bits.
85   <LI> (Derby format) 1 byte encoded length (0 <= L <= 31) - number of bytes of <raw data> - encoded = 0x80 & L
86   <LI> (Derby format) 3 byte encoded length (32 <= L < 64k) - number of bytes of <raw data> - encoded = 0xA0 <L as Java format unsigned short>
87   <LI> (Derby format) 5 byte encoded length (64k <= L < 2G) - number of bytes of <raw data> - encoded = 0xC0 <L as Java format integer>
88   <LI> (future) to be determined L >= 2G - encoded 0xE0 <encoding of L to be determined>
89   (0xE0 is an esacape to allow any number of arbitary encodings in the future).
90   </UL>
91   <BR>
92   When the value was written from a byte array the Derby encoded byte
93   length format was always used from Derby 10.0 onwards (ie. all open
94   source versions).
95   <BR>
96   When the value was written from a stream (e.g. PreparedStatement.setBinaryStream)
97   then the Cloudscape '5.x format zero' was used by 10.0 and 10.1.
98   The was due to the class RawToBinaryFormatStream always writing
99   four zero bytes for the length before the data.
100   <BR>
101   The Cloudscape '5.x format bits' format I think was never used by Derby.
102  */

103 abstract class SQLBinary
104     extends DataType implements BitDataValue
105 {
106
107     static final byte PAD = (byte) 0x20;
108
109     private static final int BASE_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( SQLBinary.class);
110
111     public int estimateMemoryUsage()
112     {
113         if (dataValue == null) {
114             if (streamValueLength>=0) {
115                 return BASE_MEMORY_USAGE + streamValueLength;
116             } else {
117                 return getMaxMemoryUsage();
118             }
119         } else {
120             return BASE_MEMORY_USAGE + dataValue.length;
121         }
122     } // end of estimateMemoryUsage
123

124       
125     /**
126      * Return max memory usage for a SQL Binary
127      */

128     abstract int getMaxMemoryUsage();
129
130      /*
131      * object state
132      */

133     byte[] dataValue;
134
135     /**
136      * Value as a stream, this stream represents the on-disk
137      * format of the value. That is it has length information
138      * encoded in the first fe bytes.
139      */

140     InputStream stream;
141
142     /**
143         Length of the value in bytes when this value
144         is set as a stream. Represents the length of the
145         value itself and not the length of the stream
146         which contains this length encoded as the first
147         few bytes. If the value of the stream is unknown
148         then this will be set to -1. If this value is
149         not set as a stream then this value should be ignored.
150     */

151     int streamValueLength;
152
153     /**
154         no-arg constructor, required by Formattable.
155     */

156     SQLBinary()
157     {
158     }
159
160     SQLBinary(byte[] val)
161     {
162         dataValue = val;
163     }
164
165
166     public final void setValue(byte[] theValue)
167     {
168         dataValue = theValue;
169         stream = null;
170         streamValueLength = -1;
171     }
172
173     /**
174      * Used by JDBC -- string should not contain
175      * SQL92 formatting.
176      *
177      * @exception StandardException Thrown on error
178      */

179     public final String JavaDoc getString() throws StandardException
180     {
181         if (getValue() == null)
182             return null;
183         else if (dataValue.length * 2 < 0) //if converted to hex, length exceeds max int
184
{
185             throw StandardException.newException(SQLState.LANG_STRING_TRUNCATION, getTypeName(),
186                                     "",
187                                     String.valueOf(Integer.MAX_VALUE));
188         }
189         else
190         {
191             return org.apache.derby.iapi.util.StringUtil.toHexString(dataValue, 0, dataValue.length);
192         }
193     }
194
195
196     /**
197      * @exception StandardException Thrown on error
198      */

199     public final InputStream getStream()
200     {
201         return (stream);
202     }
203
204     /**
205      *
206      * @exception StandardException Thrown on error
207      */

208     public final byte[] getBytes() throws StandardException
209     {
210         return getValue();
211     }
212
213     byte[] getValue() throws StandardException
214     {
215         try
216         {
217             if ((dataValue == null) && (stream != null)) {
218         
219                 if (stream instanceof FormatIdInputStream) {
220                     readExternal((FormatIdInputStream) stream);
221                 }
222                 else {
223                     readExternal(new FormatIdInputStream(stream));
224                 }
225                 stream = null;
226                 streamValueLength = -1;
227
228             }
229         }
230         catch (IOException JavaDoc ioe)
231         {
232             throw StandardException.newException(SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION, ioe, getTypeName());
233         }
234         return dataValue;
235     }
236     
237     /**
238      * length in bytes
239      *
240      * @exception StandardException Thrown on error
241      */

242     public final int getLength() throws StandardException
243     {
244         if (stream != null) {
245
246             if (streamValueLength != -1)
247                 return streamValueLength;
248         }
249
250         return (getBytes() == null) ? 0 : getBytes().length;
251     }
252
253     /*
254      * Storable interface, implies Externalizable, TypedFormat
255      */

256
257
258     /**
259      * see if the Bit value is null.
260      * @see org.apache.derby.iapi.services.io.Storable#isNull
261      */

262     public final boolean isNull()
263     {
264         return (dataValue == null) && (stream == null);
265     }
266
267     /**
268         Write the value out from the byte array (not called if null)
269         using the 8.1 encoding.
270
271      * @exception IOException io exception
272      */

273     public final void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc
274     {
275
276         int len = dataValue.length;
277         if (len <= 31)
278         {
279             out.write((byte) (0x80 | (len & 0xff)));
280         }
281         else if (len <= 0xFFFF)
282         {
283             out.write((byte) 0xA0);
284             out.writeShort((short) len);
285         }
286         else
287         {
288             out.write((byte) 0xC0);
289             out.writeInt(len);
290
291         }
292         out.write(dataValue, 0, dataValue.length);
293     }
294
295     /**
296      * delegated to bit
297      *
298      * @exception IOException io exception
299      * @exception ClassNotFoundException class not found
300     */

301     public final void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc
302     {
303         // need to clear stream first, in case this object is reused, and
304
// stream is set by previous use. Track 3794.
305
stream = null;
306         streamValueLength = -1;
307
308
309         int len = SQLBinary.readBinaryLength(in);
310
311         if (len != 0)
312         {
313             dataValue = new byte[len];
314             in.readFully(dataValue);
315         }
316         else
317         {
318             readFromStream((InputStream) in);
319         }
320     }
321     public final void readExternalFromArray(ArrayInputStream in) throws IOException JavaDoc
322     {
323         // need to clear stream first, in case this object is reused, and
324
// stream is set by previous use. Track 3794.
325
stream = null;
326         streamValueLength = -1;
327
328         int len = SQLBinary.readBinaryLength(in);
329
330         if (len != 0)
331         {
332             dataValue = new byte[len];
333             in.readFully(dataValue);
334         }
335         else
336         {
337             readFromStream(in);
338         }
339     }
340
341     /**
342      * Read the encoded length of the value from the on-disk format.
343      *
344      * @see SQLBinary
345     */

346     private static int readBinaryLength(ObjectInput JavaDoc in) throws IOException JavaDoc {
347         
348         int bl = in.read();
349         if (bl == -1)
350             throw new java.io.EOFException JavaDoc();
351         
352         byte li = (byte) bl;
353
354         int len;
355         if ((li & ((byte) 0x80)) != 0)
356         {
357             if (li == ((byte) 0xC0))
358             {
359                 len = in.readInt();
360             }
361             else if (li == ((byte) 0xA0))
362             {
363                 len = in.readUnsignedShort();
364             }
365             else
366             {
367                 len = li & 0x1F;
368             }
369         }
370         else
371         {
372             
373             // old length in bits
374
int v2 = in.read();
375             int v3 = in.read();
376             int v4 = in.read();
377             if (v2 == -1 || v3 == -1 || v4 == -1)
378                 throw new java.io.EOFException JavaDoc();
379             int lenInBits = (((bl & 0xff) << 24) | ((v2 & 0xff) << 16) | ((v3 & 0xff) << 8) | (v4 & 0xff));
380
381             len = lenInBits / 8;
382             if ((lenInBits % 8) != 0)
383                 len++;
384         }
385         return len;
386     }
387
388     /**
389      * Read the value from an input stream. The length
390      * encoded in the input stream has already been read
391      * and determined to be unknown.
392      */

393     private void readFromStream(InputStream in) throws IOException JavaDoc {
394
395         dataValue = null; // allow gc of the old value before the new.
396
byte[] tmpData = new byte[32 * 1024];
397
398         int off = 0;
399         for (;;) {
400
401             int len = in.read(tmpData, off, tmpData.length - off);
402             if (len == -1)
403                 break;
404             off += len;
405
406             int available = Math.max(1, in.available());
407             int extraSpace = available - (tmpData.length - off);
408             if (extraSpace > 0)
409             {
410                 // need to grow the array
411
int size = tmpData.length * 2;
412                 if (extraSpace > tmpData.length)
413                     size += extraSpace;
414
415                 byte[] grow = new byte[size];
416                 System.arraycopy(tmpData, 0, grow, 0, off);
417                 tmpData = grow;
418             }
419         }
420
421         dataValue = new byte[off];
422         System.arraycopy(tmpData, 0, dataValue, 0, off);
423     }
424
425     /**
426      * @see org.apache.derby.iapi.services.io.Storable#restoreToNull
427      */

428     public final void restoreToNull()
429     {
430         dataValue = null;
431         stream = null;
432         streamValueLength = -1;
433     }
434
435     /**
436         @exception StandardException thrown on error
437      */

438     public final boolean compare(int op,
439                            DataValueDescriptor other,
440                            boolean orderedNulls,
441                            boolean unknownRV)
442         throws StandardException
443     {
444         if (!orderedNulls) // nulls are unordered
445
{
446             if (SanityManager.DEBUG)
447             {
448                 int otherTypeFormatId = other.getTypeFormatId();
449                 if (!((StoredFormatIds.SQL_BIT_ID == otherTypeFormatId)
450                       || (StoredFormatIds.SQL_VARBIT_ID == otherTypeFormatId)
451                       || (StoredFormatIds.SQL_LONGVARBIT_ID == otherTypeFormatId)
452
453                       || (StoredFormatIds.SQL_CHAR_ID == otherTypeFormatId)
454                       || (StoredFormatIds.SQL_VARCHAR_ID == otherTypeFormatId)
455                       || (StoredFormatIds.SQL_LONGVARCHAR_ID == otherTypeFormatId)
456
457                       || ((StoredFormatIds.SQL_BLOB_ID == otherTypeFormatId)
458                           && (StoredFormatIds.SQL_BLOB_ID == getTypeFormatId()))
459                         ))
460                 SanityManager.THROWASSERT(
461                                     "Some fool passed in a "+ other.getClass().getName() + ", "
462                                     + otherTypeFormatId + " to SQLBinary.compare()");
463             }
464             String JavaDoc otherString = other.getString();
465             if (this.getString() == null || otherString == null)
466                 return unknownRV;
467         }
468         /* Do the comparison */
469         return super.compare(op, other, orderedNulls, unknownRV);
470     }
471
472     /**
473         @exception StandardException thrown on error
474      */

475     public final int compare(DataValueDescriptor other) throws StandardException
476     {
477
478         /* Use compare method from dominant type, negating result
479          * to reflect flipping of sides.
480          */

481         if (typePrecedence() < other.typePrecedence())
482         {
483             return - (other.compare(this));
484         }
485
486         /*
487         ** By convention, nulls sort High, and null == null
488         */

489         if (this.isNull() || other.isNull())
490         {
491             if (!isNull())
492                 return -1;
493             if (!other.isNull())
494                 return 1;
495             return 0; // both null
496
}
497
498         return SQLBinary.compare(getBytes(), other.getBytes());
499     }
500
501     /*
502      * CloneableObject interface
503      */

504
505     /** From CloneableObject
506      * Shallow clone a StreamStorable without objectifying. This is used to avoid
507      * unnecessary objectifying of a stream object. The only difference of this method
508      * from getClone is this method does not objectify a stream. beetle 4896
509      */

510     public final Object JavaDoc cloneObject()
511     {
512         if (stream == null)
513             return getClone();
514         SQLBinary self = (SQLBinary) getNewNull();
515         self.setValue(stream, streamValueLength);
516         return self;
517     }
518
519     /*
520      * DataValueDescriptor interface
521      */

522
523     /** @see DataValueDescriptor#getClone */
524     public final DataValueDescriptor getClone()
525     {
526         try
527         {
528             DataValueDescriptor cloneDVD = getNewNull();
529             cloneDVD.setValue(getValue());
530             return cloneDVD;
531         }
532         catch (StandardException se)
533         {
534             if (SanityManager.DEBUG)
535                 SanityManager.THROWASSERT("Unexpected exception " + se);
536             return null;
537         }
538     }
539
540     /*
541      * DataValueDescriptor interface
542      */

543
544     /*
545      * StreamStorable interface :
546      */

547     public final InputStream returnStream()
548     {
549         return stream;
550     }
551
552     /**
553      * Set me to the value represented by this stream.
554      * The format of the stream is the on-disk format
555      * described in this class's javadoc. That is the
556      * length is encoded in the first few bytes of the
557      * stream.
558      */

559     public final void setStream(InputStream newStream)
560     {
561         this.dataValue = null;
562         this.stream = newStream;
563         streamValueLength = -1;
564     }
565
566     public final void loadStream() throws StandardException
567     {
568         getValue();
569     }
570
571     /*
572      * class interface
573      */

574
575     boolean objectNull(Object JavaDoc o)
576     {
577         if (o == null)
578         {
579             setToNull();
580             return true;
581         }
582         return false;
583     }
584
585     /**
586      * Set the value from the stream which is in the on-disk format.
587      * @param theStream On disk format of the stream
588      * @param valueLength length of the logical value in bytes.
589      */

590     public final void setValue(InputStream theStream, int valueLength)
591     {
592         dataValue = null;
593         stream = theStream;
594         this.streamValueLength = valueLength;
595     }
596
597     protected final void setFrom(DataValueDescriptor theValue) throws StandardException {
598
599         if (theValue instanceof SQLBinary)
600         {
601             SQLBinary theValueBinary = (SQLBinary) theValue;
602             dataValue = theValueBinary.dataValue;
603             stream = theValueBinary.stream;
604             streamValueLength = theValueBinary.streamValueLength;
605         }
606         else
607         {
608             setValue(theValue.getBytes());
609         }
610     }
611
612     /*
613     ** SQL Operators
614     */

615
616     /**
617      * The = operator as called from the language module, as opposed to
618      * the storage module.
619      *
620      * @param left The value on the left side of the =
621      * @param right The value on the right side of the =
622      * is not.
623      * @return A SQL boolean value telling whether the two parameters are equal
624      *
625      * @exception StandardException Thrown on error
626      */

627
628     public final BooleanDataValue equals(DataValueDescriptor left,
629                              DataValueDescriptor right)
630                                 throws StandardException
631     {
632         boolean isEqual;
633
634         if (left.isNull() || right.isNull())
635         {
636             isEqual = false;
637         }
638         else
639         {
640             isEqual = SQLBinary.compare(left.getBytes(), right.getBytes()) == 0;
641         }
642
643         return SQLBoolean.truthValue(left,
644                                      right,
645                                      isEqual);
646     }
647
648     /**
649      * The <> operator as called from the language module, as opposed to
650      * the storage module.
651      *
652      * @param left The value on the left side of the <>
653      * @param right The value on the right side of the <>
654      *
655      * @return A SQL boolean value telling whether the two parameters
656      * are not equal
657      *
658      * @exception StandardException Thrown on error
659      */

660
661     public final BooleanDataValue notEquals(DataValueDescriptor left,
662                              DataValueDescriptor right)
663                                 throws StandardException
664     {
665         boolean isNotEqual;
666
667         if (left.isNull() || right.isNull())
668         {
669             isNotEqual = false;
670         }
671         else
672         {
673             isNotEqual = SQLBinary.compare(left.getBytes(), right.getBytes()) != 0;
674         }
675
676         return SQLBoolean.truthValue(left,
677                                      right,
678                                      isNotEqual);
679     }
680
681     /**
682      * The < operator as called from the language module, as opposed to
683      * the storage module.
684      *
685      * @param left The value on the left side of the <
686      * @param right The value on the right side of the <
687      *
688      * @return A SQL boolean value telling whether the first operand is
689      * less than the second operand
690      *
691      * @exception StandardException Thrown on error
692      */

693
694     public final BooleanDataValue lessThan(DataValueDescriptor left,
695                              DataValueDescriptor right)
696                                 throws StandardException
697     {
698         boolean isLessThan;
699
700         if (left.isNull() || right.isNull())
701         {
702             isLessThan = false;
703         }
704         else
705         {
706             isLessThan = SQLBinary.compare(left.getBytes(), right.getBytes()) < 0;
707         }
708
709         return SQLBoolean.truthValue(left,
710                                      right,
711                                      isLessThan);
712     }
713
714     /**
715      * The > operator as called from the language module, as opposed to
716      * the storage module.
717      *
718      * @param left The value on the left side of the >
719      * @param right The value on the right side of the >
720      *
721      * @return A SQL boolean value telling whether the first operand is
722      * greater than the second operand
723      *
724      * @exception StandardException Thrown on error
725      */

726
727     public final BooleanDataValue greaterThan(DataValueDescriptor left,
728                              DataValueDescriptor right)
729                                 throws StandardException
730     {
731         boolean isGreaterThan = false;
732
733         if (left.isNull() || right.isNull())
734         {
735             isGreaterThan = false;
736         }
737         else
738         {
739             isGreaterThan = SQLBinary.compare(left.getBytes(), right.getBytes()) > 0;
740         }
741
742         return SQLBoolean.truthValue(left,
743                                      right,
744                                      isGreaterThan);
745     }
746
747     /**
748      * The <= operator as called from the language module, as opposed to
749      * the storage module.
750      *
751      * @param left The value on the left side of the <=
752      * @param right The value on the right side of the <=
753      *
754      * @return A SQL boolean value telling whether the first operand is
755      * less than or equal to the second operand
756      *
757      * @exception StandardException Thrown on error
758      */

759
760     public final BooleanDataValue lessOrEquals(DataValueDescriptor left,
761                              DataValueDescriptor right)
762                                 throws StandardException
763     {
764         boolean isLessEquals = false;
765
766         if (left.isNull() || right.isNull())
767         {
768             isLessEquals = false;
769         }
770         else
771         {
772             isLessEquals = SQLBinary.compare(left.getBytes(), right.getBytes()) <= 0;
773         }
774
775         return SQLBoolean.truthValue(left,
776                                      right,
777                                      isLessEquals);
778     }
779
780     /**
781      * The >= operator as called from the language module, as opposed to
782      * the storage module.
783      *
784      * @param left The value on the left side of the >=
785      * @param right The value on the right side of the >=
786      *
787      * @return A SQL boolean value telling whether the first operand is
788      * greater than or equal to the second operand
789      *
790      * @exception StandardException Thrown on error
791      */

792
793     public final BooleanDataValue greaterOrEquals(DataValueDescriptor left,
794                              DataValueDescriptor right)
795                                 throws StandardException
796     {
797         boolean isGreaterEquals = false;
798
799         if (left.isNull() || right.isNull())
800         {
801             isGreaterEquals = false;
802         }
803         else
804         {
805             isGreaterEquals = SQLBinary.compare(left.getBytes(), right.getBytes()) >= 0;
806         }
807
808         return SQLBoolean.truthValue(left,
809                                      right,
810                                      isGreaterEquals);
811     }
812
813
814     /**
815      *
816      * This method implements the char_length function for bit.
817      *
818      * @param result The result of a previous call to this method, null
819      * if not called yet
820      *
821      * @return A SQLInteger containing the length of the char value
822      *
823      * @exception StandardException Thrown on error
824      *
825      * @see ConcatableDataValue#charLength
826      */

827
828     public final NumberDataValue charLength(NumberDataValue result)
829                             throws StandardException
830     {
831         if (result == null)
832         {
833             result = new SQLInteger();
834         }
835
836         if (this.isNull())
837         {
838             result.setToNull();
839             return result;
840         }
841
842
843         result.setValue(getValue().length);
844         return result;
845     }
846
847     /**
848      * @see BitDataValue#concatenate
849      *
850      * @exception StandardException Thrown on error
851      */

852     public final BitDataValue concatenate(
853                 BitDataValue left,
854                 BitDataValue right,
855                 BitDataValue result)
856         throws StandardException
857     {
858         if (left.isNull() || right.isNull())
859         {
860             result.setToNull();
861             return result;
862         }
863
864         byte[] leftData = left.getBytes();
865         byte[] rightData = right.getBytes();
866
867         byte[] concatData = new byte[leftData.length + rightData.length];
868
869         System.arraycopy(leftData, 0, concatData, 0, leftData.length);
870         System.arraycopy(rightData, 0, concatData, leftData.length, rightData.length);
871
872
873         result.setValue(concatData);
874         return result;
875     }
876
877   
878     /**
879      * The SQL substr() function.
880      *
881      * @param start Start of substr
882      * @param length Length of substr
883      * @param result The result of a previous call to this method,
884      * null if not called yet.
885      * @param maxLen Maximum length of the result
886      *
887      * @return A ConcatableDataValue containing the result of the substr()
888      *
889      * @exception StandardException Thrown on error
890      */

891     public final ConcatableDataValue substring(
892                 NumberDataValue start,
893                 NumberDataValue length,
894                 ConcatableDataValue result,
895                 int maxLen)
896         throws StandardException
897     {
898         int startInt;
899         int lengthInt;
900         BitDataValue varbitResult;
901
902         if (result == null)
903         {
904             result = new SQLVarbit();
905         }
906
907         varbitResult = (BitDataValue) result;
908
909         /* The result is null if the receiver (this) is null or if the length is negative.
910          * Oracle docs don't say what happens if the start position or the length is a usernull.
911          * We will return null, which is the only sensible thing to do.
912          * (If the user did not specify a length then length is not a user null.)
913          */

914         if (this.isNull() || start.isNull() || (length != null && length.isNull()))
915         {
916             varbitResult.setToNull();
917             return varbitResult;
918         }
919
920         startInt = start.getInt();
921
922         // If length is not specified, make it till end of the string
923
if (length != null)
924         {
925             lengthInt = length.getInt();
926         }
927         else lengthInt = getLength() - startInt + 1;
928
929         /* DB2 Compatibility: Added these checks to match DB2. We currently enforce these
930          * limits in both modes. We could do these checks in DB2 mode only, if needed, so
931          * leaving earlier code for out of range in for now, though will not be exercised
932          */

933         if ((startInt <= 0 || lengthInt < 0 || startInt > getLength() ||
934                 lengthInt > getLength() - startInt + 1))
935             throw StandardException.newException(SQLState.LANG_SUBSTR_START_OR_LEN_OUT_OF_RANGE);
936             
937         // Return null if length is non-positive
938
if (lengthInt < 0)
939         {
940             varbitResult.setToNull();
941             return varbitResult;
942         }
943
944         /* If startInt < 0 then we count from the right of the string */
945         if (startInt < 0)
946         {
947             startInt += getLength();
948             if (startInt < 0)
949             {
950                 lengthInt += startInt;
951                 startInt = 0;
952             }
953             if (lengthInt + startInt > 0)
954             {
955                 lengthInt += startInt;
956             }
957             else
958             {
959                 lengthInt = 0;
960             }
961         }
962         else if (startInt > 0)
963         {
964             /* java substr() is 0 based */
965             startInt--;
966         }
967
968         /* Oracle docs don't say what happens if the window is to the
969          * left of the string. Return "" if the window
970          * is to the left or right or if the length is 0.
971          */

972         if (lengthInt == 0 ||
973             lengthInt <= 0 - startInt ||
974             startInt > getLength())
975         {
976             varbitResult.setValue(new byte[0]);
977             return varbitResult;
978         }
979
980         if (lengthInt >= getLength() - startInt)
981         {
982             byte[] substring = new byte[dataValue.length - startInt];
983             System.arraycopy(dataValue, startInt, substring, 0, substring.length);
984             varbitResult.setValue(substring);
985         }
986         else
987         {
988             byte[] substring = new byte[lengthInt];
989             System.arraycopy(dataValue, startInt, substring, 0, substring.length);
990             varbitResult.setValue(substring);
991         }
992
993         return varbitResult;
994     }
995
996     /**
997         Host variables are rejected if their length is
998         bigger than the declared length, regardless of
999         if the trailing bytes are the pad character.
1000
1001        @exception StandardException Variable is too big.
1002    */

1003    public final void checkHostVariable(int declaredLength) throws StandardException
1004    {
1005        // stream length checking occurs at the JDBC layer
1006
int variableLength = -1;
1007        if (stream == null)
1008        {
1009            if (dataValue != null)
1010                variableLength = dataValue.length;
1011        }
1012        else
1013        {
1014            variableLength = streamValueLength;
1015        }
1016
1017        if (variableLength != -1 && variableLength > declaredLength)
1018                throw StandardException.newException(SQLState.LANG_STRING_TRUNCATION, getTypeName(),
1019                            "XX-RESOLVE-XX",
1020                            String.valueOf(declaredLength));
1021    }
1022
1023    /*
1024     * String display of value
1025     */

1026
1027    public final String JavaDoc toString()
1028    {
1029        if (dataValue == null)
1030        {
1031            if (stream == null)
1032            {
1033                return "NULL";
1034            }
1035            else
1036            {
1037                if (SanityManager.DEBUG)
1038                    SanityManager.THROWASSERT(
1039                        "value is null, stream is not null");
1040                return "";
1041            }
1042        }
1043        else
1044        {
1045            return org.apache.derby.iapi.util.StringUtil.toHexString(dataValue, 0, dataValue.length);
1046        }
1047    }
1048
1049    /*
1050     * Hash code
1051     */

1052    public final int hashCode()
1053    {
1054        try {
1055            if (getValue() == null)
1056                {
1057                    return 0;
1058                }
1059        }
1060        catch (StandardException se)
1061        {
1062            if (SanityManager.DEBUG)
1063                SanityManager.THROWASSERT("Unexpected exception " + se);
1064            return 0;
1065        }
1066
1067        /* Hash code is simply the sum of all of the bytes */
1068        byte[] bytes = dataValue;
1069        int hashcode = 0;
1070
1071        // Build the hash code
1072
for (int index = 0 ; index < bytes.length; index++)
1073        {
1074            byte bv = bytes[index];
1075            if (bv != SQLBinary.PAD)
1076                hashcode += bytes[index];
1077        }
1078
1079        return hashcode;
1080    }
1081    private static int compare(byte[] left, byte[] right) {
1082
1083        int minLen = left.length;
1084        byte[] longer = right;
1085        if (right.length < minLen) {
1086            minLen = right.length;
1087            longer = left;
1088        }
1089
1090        for (int i = 0; i < minLen; i++) {
1091
1092            int lb = left[i] & 0xff;
1093            int rb = right[i] & 0xff;
1094
1095            if (lb == rb)
1096                continue;
1097
1098            return lb - rb;
1099        }
1100
1101        // complete match on all the bytes for the smallest value.
1102

1103        // if the longer value is all pad characters
1104
// then the values are equal.
1105
for (int i = minLen; i < longer.length; i++) {
1106            byte nb = longer[i];
1107            if (nb == SQLBinary.PAD)
1108                continue;
1109
1110            // longer value is bigger.
1111
if (left == longer)
1112                return 1;
1113            return -1;
1114        }
1115
1116        return 0;
1117
1118    }
1119
1120      /** Adding this method to ensure that super class' setInto method doesn't get called
1121      * that leads to the violation of JDBC spec( untyped nulls ) when batching is turned on.
1122      */

1123     public void setInto(PreparedStatement JavaDoc ps, int position) throws SQLException JavaDoc, StandardException {
1124
1125                  ps.setBytes(position, getBytes());
1126     }
1127}
1128
Popular Tags