Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/derby/iapi/types/SQLBinary.java


1   /*
2   
3      Derby - Class org.apache.derby.iapi.types.SQLBinary
4   
5      Copyright 2004 The Apache Software Foundation or its licensors, as applicable.
6   
7      Licensed under the Apache License, Version 2.0 (the "License");
8      you may not use this file except in compliance with the License.
9      You may obtain a copy of the License at
10  
11        http://www.apache.org/licenses/LICENSE-2.0
12  
13     Unless required by applicable law or agreed to in writing, software
14     distributed under the License is distributed on an "AS IS" BASIS,
15     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16     See the License for the specific language governing permissions and
17     limitations under the License.
18  
19   */
20  
21  package org.apache.derby.iapi.types;
22  
23  import org.apache.derby.iapi.reference.SQLState;
24  
25  import org.apache.derby.iapi.services.io.ArrayInputStream;
26  import org.apache.derby.iapi.services.io.FormatableBitSet;
27  import org.apache.derby.iapi.services.io.NewByteArrayInputStream;
28  
29  import org.apache.derby.iapi.types.DataTypeDescriptor;
30  import org.apache.derby.iapi.types.DataValueDescriptor;
31  import org.apache.derby.iapi.types.TypeId;
32  import org.apache.derby.iapi.types.BitDataValue;
33  import org.apache.derby.iapi.types.DataValueDescriptor;
34  import org.apache.derby.iapi.types.ConcatableDataValue;
35  import org.apache.derby.iapi.types.VariableSizeDataValue;
36  import org.apache.derby.iapi.error.StandardException;
37  
38  import org.apache.derby.iapi.services.io.FormatIdUtil;
39  import org.apache.derby.iapi.services.io.StoredFormatIds;
40  import org.apache.derby.iapi.services.io.StreamStorable;
41  import org.apache.derby.iapi.services.io.FormatIdInputStream;
42  
43  import org.apache.derby.iapi.services.sanity.SanityManager;
44  
45  import org.apache.derby.iapi.types.BooleanDataValue;
46  import org.apache.derby.iapi.types.StringDataValue;
47  import org.apache.derby.iapi.types.NumberDataValue;
48  
49  import org.apache.derby.iapi.services.cache.ClassSize;
50  import org.apache.derby.iapi.util.StringUtil;
51  
52  import org.apache.derby.iapi.types.SQLInteger;
53  
54  import java.io.ObjectOutput;
55  import java.io.ObjectInput;
56  import java.io.IOException;
57  import java.io.InputStream;
58  
59  import java.sql.ResultSet;
60  import java.sql.SQLException;
61  import java.sql.PreparedStatement;
62  
63  /**
64   * SQLBinary satisfies the DataValueDescriptor
65   * interfaces (i.e., DataType). It implements a String holder,
66   * e.g. for storing a column value; it can be specified
67   * when constructed to not allow nulls. Nullability cannot be changed
68   * after construction.
69   * <p>
70   * Because DataType is a subclass of DataType,
71   * SQLBit can play a role in either a DataType/Value
72   * or a DataType/KeyRow, interchangeably.
73  
74    <P>
75    Format : <encoded length><raw data>
76    <BR>
77    Length is encoded to support 5.x databases where the length was stored as the number of bits.
78    The first bit of the first byte indicates if the format is an old (5.x) style or a new 8.1 style.
79    8.1 then uses the next two bits to indicate how the length is encoded.
80    <BR>
81    <encoded length> is one of N styles.
82    <UL>
83    <LI> (5.x format) 4 byte Java format integer value 0 - either <raw data> is 0 bytes/bits  or an unknown number of bytes.
84    <LI> (5.x format) 4 byte Java format integer value >0 (positive) - number of bits in <raw data>, number of bytes in <raw data>
85    is the minimum number of bytes required to store the number of bits.
86    <LI> (8.1 format) 1 byte encoded length (0 <= L <= 31) - number of bytes of <raw data> - encoded = 0x80 & L
87    <LI> (8.1 format) 3 byte encoded length (32 <= L < 64k) - number of bytes of <raw data> - encoded = 0xA0 <L as Java format unsigned short>
88    <LI> (8.1 format) 5 byte encoded length (64k <= L < 2G) - number of bytes of <raw data> - encoded = 0xC0 <L as Java format integer>
89    <LI> (future) to be determined L >= 2G - encoded 0xE0 <encoding of L to be determined>
90    (0xE0 is an esacape to allow any number of arbitary encodings in the future).
91    </UL>
92   */
93  public abstract class SQLBinary
94    extends DataType implements BitDataValue
95  {
96  
97    static final byte PAD = (byte) 0x20;
98  
99      private static final int BASE_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( SQLBinary.class);
100 
101     public int estimateMemoryUsage()
102     {
103         int sz = BASE_MEMORY_USAGE;
104         if( null != dataValue)
105             sz += dataValue.length;
106         return sz;
107     } // end of estimateMemoryUsage
108 
109     
110     
111    /*
112    * object state
113    */
114   byte[] dataValue;
115 
116   /*
117    * stream state
118    */
119   InputStream stream;
120 
121   /**
122     Length of the stream in units relevant to the type,
123     in this case bytes.
124   */
125   int streamLength;
126 
127   /**
128     no-arg constructor, required by Formattable.
129   */
130   SQLBinary()
131   {
132   }
133 
134   SQLBinary(byte[] val)
135   {
136     dataValue = val;
137   }
138 
139 
140   public final void setValue(byte[] theValue)
141   {
142     dataValue = theValue;
143     stream = null;
144     streamLength = -1;
145   }
146 
147   /**
148    * Used by JDBC -- string should not contain
149    * SQL92 formatting.
150    *
151    * @exception StandardException    Thrown on error
152    */
153   public final String  getString() throws StandardException
154   {
155     if (getValue() == null)
156       return null;
157     else if (dataValue.length * 2 < 0)  //if converted to hex, length exceeds max int
158     {
159       throw StandardException.newException(SQLState.LANG_STRING_TRUNCATION, getTypeName(),
160                   "",
161                   String.valueOf(Integer.MAX_VALUE));
162     }
163     else 
164     {
165       return org.apache.derby.iapi.util.StringUtil.toHexString(dataValue, 0, dataValue.length);
166     }
167   }
168 
169 
170   /**
171    * @exception StandardException    Thrown on error
172    */
173   public final InputStream  getStream()
174   {
175     return (stream);
176   }
177 
178   /**
179    *
180    * @exception StandardException    Thrown on error
181    */
182   public final byte[]  getBytes() throws StandardException
183   {
184     return getValue();
185   }
186 
187   byte[] getValue() throws StandardException
188   {
189     try
190     {
191       if ((dataValue == null) && (stream != null)) {
192 
193         if (stream instanceof FormatIdInputStream) {
194           readExternal((FormatIdInputStream) stream);
195         } else if ( stream instanceof NewByteArrayInputStream )
196         {
197           // this piece of code handles the case that a stream has been
198           // opened on the bit value. the stream will have already called
199           // readExternal() on the underlying FormatableBitSet. we just need to
200           // retrieve the byte array from that stream.
201           NewByteArrayInputStream  nbais = (NewByteArrayInputStream) stream;
202           dataValue = nbais.getData();
203         }
204         else {
205           readExternal(new FormatIdInputStream(stream));
206         }
207         stream = null;
208         streamLength = -1;
209 
210       }
211     }
212     catch (IOException ioe)
213     {
214       throw StandardException.newException(SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION, ioe, getTypeName());
215     }
216     return dataValue;
217   }
218   
219   /**
220    * length in bytes
221    *
222    * @exception StandardException    Thrown on error
223    */
224   public final int  getLength() throws StandardException
225   {
226     if (stream != null) {
227 
228       if (streamLength != -1)
229         return streamLength;
230     }
231 
232     return getBytes().length;
233 
234   }
235 
236   /*
237    * Storable interface, implies Externalizable, TypedFormat
238    */
239 
240 
241   /**
242    * see if the Bit value is null.
243    * @see org.apache.derby.iapi.services.io.Storable#isNull
244    */
245   public final boolean isNull()
246   {
247     return (dataValue == null) && (stream == null);
248   }
249 
250   /** 
251     Write the value out from the byte array (not called if null)
252     using the 8.1 encoding.
253 
254    * @exception IOException    io exception
255    */
256   public final void writeExternal(ObjectOutput out) throws IOException
257   {
258 
259     int len = dataValue.length;
260     if (len <= 31)
261     {
262       out.write((byte) (0x80 | (len & 0xff)));
263     }
264     else if (len <= 0xFFFF)
265     {
266       out.write((byte) 0xA0);
267       out.writeShort((short) len);
268     }
269     else
270     {
271       out.write((byte) 0xC0);
272       out.writeInt(len);
273 
274     }
275     out.write(dataValue, 0, dataValue.length);
276   }
277 
278   /** 
279    * delegated to bit 
280    *
281    * @exception IOException      io exception
282    * @exception ClassNotFoundException  class not found
283   */
284   public final void readExternal(ObjectInput in) throws IOException
285   {
286     // need to clear stream first, in case this object is reused, and
287     // stream is set by previous use.  Track 3794.
288     stream = null;
289     streamLength = -1;
290 
291 
292     int len = SQLBinary.readBinaryLength(in);
293 
294     if (len != 0)
295     {
296       dataValue = new byte[len];
297       in.readFully(dataValue);
298     }
299     else
300     {
301       readFromStream((InputStream) in);
302     }
303   }
304   public final void readExternalFromArray(ArrayInputStream in) throws IOException
305   {
306     // need to clear stream first, in case this object is reused, and
307     // stream is set by previous use.  Track 3794.
308     stream = null;
309     streamLength = -1;
310 
311     int len = SQLBinary.readBinaryLength(in);
312 
313     if (len != 0)
314     {
315       dataValue = new byte[len];
316       in.readFully(dataValue);
317     }
318     else
319     {
320       readFromStream(in);
321     }
322   }
323 
324   private static int readBinaryLength(ObjectInput in) throws IOException {
325     int len = 0;
326     int bl = in.read();
327     if (len < 0)
328       throw new java.io.EOFException();
329 
330     if ((bl & 0x80) != 0)
331     {
332       if (bl == 0xC0)
333       {
334         len = in.readInt();
335       }
336       else if (bl == 0xA0)
337       {
338         len = in.readUnsignedShort();
339       }
340       else
341       {
342         len = bl & 0x1F;
343       }
344     }
345     else
346     {
347       // old length in bits
348       int v2 = in.read();
349       int v3 = in.read();
350       int v4 = in.read();
351       if (v2 < 0 || v3 < 0 || v4 < 0)
352         throw new java.io.EOFException();
353             int lenInBits = (((bl & 0xff) << 24) | ((v2 & 0xff) << 16) | ((v3 & 0xff) << 8) | (v4 & 0xff));
354 
355       len = lenInBits / 8;
356       if ((lenInBits % 8) != 0)
357         len++;
358     }
359     return len;
360   }
361 
362   private void readFromStream(InputStream in) throws IOException {
363 
364     dataValue = null;  // allow gc of the old value before the new.
365     byte[] tmpData = new byte[32 * 1024];
366 
367     int off = 0;
368     for (;;) {
369 
370       int len = in.read(tmpData, off, tmpData.length - off);
371       if (len == -1)
372         break;
373       off += len;
374 
375       int available = in.available();
376       int extraSpace = available - (tmpData.length - off);
377       if (extraSpace > 0)
378       {
379         // need to grow the array
380         int size = tmpData.length * 2;
381         if (extraSpace > tmpData.length)
382           size += extraSpace;
383 
384         byte[] grow = new byte[size];
385         System.arraycopy(tmpData, 0, grow, 0, off);
386         tmpData = grow;
387       }
388     }
389 
390     dataValue = new byte[off];
391     System.arraycopy(tmpData, 0, dataValue, 0, off);
392   }
393 
394   /**
395    * @see org.apache.derby.iapi.services.io.Storable#restoreToNull
396    */
397   public final void restoreToNull()
398   {
399     dataValue = null;
400     stream = null;
401     streamLength = -1;
402   }
403 
404   /**
405     @exception StandardException thrown on error
406    */
407   public final boolean compare(int op,
408                DataValueDescriptor other,
409                boolean orderedNulls,
410                boolean unknownRV)
411     throws StandardException
412   {
413     if (!orderedNulls)    // nulls are unordered
414     {
415       if (SanityManager.DEBUG)
416       {
417                 int otherTypeFormatId = other.getTypeFormatId();
418         if (!((StoredFormatIds.SQL_BIT_ID == otherTypeFormatId)
419                       || (StoredFormatIds.SQL_VARBIT_ID == otherTypeFormatId)
420                       || (StoredFormatIds.SQL_LONGVARBIT_ID == otherTypeFormatId)
421 
422                       || (StoredFormatIds.SQL_CHAR_ID == otherTypeFormatId)
423                       || (StoredFormatIds.SQL_VARCHAR_ID == otherTypeFormatId)
424                       || (StoredFormatIds.SQL_LONGVARCHAR_ID == otherTypeFormatId)
425 
426                       || ((StoredFormatIds.SQL_BLOB_ID == otherTypeFormatId)
427                           && (StoredFormatIds.SQL_BLOB_ID == getTypeFormatId()))
428                         ))
429         SanityManager.THROWASSERT(
430                   "Some fool passed in a "+ other.getClass().getName() + ", "
431                                     + otherTypeFormatId  + " to SQLBinary.compare()");
432       }
433       String otherString = other.getString();
434       if (this.getString() == null  || otherString == null)
435         return unknownRV;
436     }
437     /* Do the comparison */
438     return super.compare(op, other, orderedNulls, unknownRV);
439   }
440 
441   /**
442     @exception StandardException thrown on error
443    */
444   public final int compare(DataValueDescriptor other) throws StandardException
445   {
446 
447     /* Use compare method from dominant type, negating result
448      * to reflect flipping of sides.
449      */
450     if (typePrecedence() < other.typePrecedence())
451     {
452       return - (other.compare(this));
453     }
454 
455     /*
456     ** By convention, nulls sort High, and null == null
457     */
458     if (this.isNull() || other.isNull())
459     {
460       if (!isNull())
461         return -1;
462       if (!other.isNull())
463         return 1;
464       return 0;              // both null
465     }
466 
467     return SQLBinary.compare(getBytes(), other.getBytes());
468   }
469 
470   /*
471    * CloneableObject interface
472    */
473 
474   /** From CloneableObject
475    *  Shallow clone a StreamStorable without objectifying.  This is used to avoid
476    *  unnecessary objectifying of a stream object.  The only difference of this method
477    *  from getClone is this method does not objectify a stream.  beetle 4896
478    */
479   public final Object cloneObject()
480   {
481     if (stream == null)
482       return getClone();
483     SQLBinary self = (SQLBinary) getNewNull();
484     self.setStream(stream);
485     return self;
486   }
487 
488   /*
489    * DataValueDescriptor interface
490    */
491 
492   /** @see DataValueDescriptor#getClone */
493   public final DataValueDescriptor getClone()
494   {
495     try
496     {
497       DataValueDescriptor cloneDVD = getNewNull();
498       cloneDVD.setValue(getValue());
499       return cloneDVD;
500     }
501     catch (StandardException se)
502     {
503       if (SanityManager.DEBUG)
504         SanityManager.THROWASSERT("Unexpected exception " + se);
505       return null;
506     }
507   }
508 
509   /*
510    * DataValueDescriptor interface
511    */
512 
513   /*
514    * StreamStorable interface : 
515    */
516   public final InputStream returnStream()
517   {
518     return stream;
519   }
520 
521   public final void setStream(InputStream newStream)
522   {
523     this.dataValue = null;
524     this.stream = newStream;
525     streamLength = -1;
526   }
527 
528   public final void loadStream() throws StandardException
529   {
530     getValue();
531   }
532 
533   /*
534    * class interface
535    */
536 
537     boolean objectNull(Object o) 
538   {
539     if (o == null) 
540     {
541       setToNull();
542       return true;
543     }
544     return false;
545   }
546 
547   /**
548    * @see SQLBit#setValue
549    *
550    */
551   public final void setValue(InputStream theStream, int streamLength)
552   {
553     dataValue = null;
554     stream = theStream;
555     this.streamLength = streamLength;
556   }
557 
558   protected final void setFrom(DataValueDescriptor theValue) throws StandardException {
559 
560     if (theValue instanceof SQLBinary)
561     {
562       SQLBinary theValueBinary = (SQLBinary) theValue;
563       dataValue = theValueBinary.dataValue;
564       stream = theValueBinary.stream;
565       streamLength = theValueBinary.streamLength;
566     }
567     else
568     {
569       setValue(theValue.getBytes());
570     }
571   }
572 
573   /*
574   ** SQL Operators
575   */
576 
577   /**
578    * The = operator as called from the language module, as opposed to
579    * the storage module.
580    *
581    * @param left      The value on the left side of the =
582    * @param right      The value on the right side of the =
583    *            is not.
584    * @return  A SQL boolean value telling whether the two parameters are equal
585    *
586    * @exception StandardException    Thrown on error
587    */
588 
589   public final BooleanDataValue equals(DataValueDescriptor left,
590                DataValueDescriptor right)
591                 throws StandardException
592   {
593     boolean isEqual;
594 
595     if (left.isNull() || right.isNull())
596     {
597       isEqual = false;
598     }
599     else
600     {  
601       isEqual = SQLBinary.compare(left.getBytes(), right.getBytes()) == 0;
602     }
603 
604     return SQLBoolean.truthValue(left,
605                    right,
606                    isEqual);
607   }
608 
609   /**
610    * The <> operator as called from the language module, as opposed to
611    * the storage module.
612    *
613    * @param left      The value on the left side of the <>
614    * @param right      The value on the right side of the <>
615    *
616    * @return  A SQL boolean value telling whether the two parameters
617    * are not equal
618    *
619    * @exception StandardException    Thrown on error
620    */
621 
622   public final BooleanDataValue notEquals(DataValueDescriptor left,
623                DataValueDescriptor right)
624                 throws StandardException
625   {
626     boolean isNotEqual;
627 
628     if (left.isNull() || right.isNull())
629     {
630       isNotEqual = false;
631     }
632     else
633     {  
634       isNotEqual = SQLBinary.compare(left.getBytes(), right.getBytes()) != 0;
635     }
636 
637     return SQLBoolean.truthValue(left,
638                    right,
639                    isNotEqual);
640   }
641 
642   /**
643    * The < operator as called from the language module, as opposed to
644    * the storage module.
645    *
646    * @param left      The value on the left side of the <
647    * @param right      The value on the right side of the <
648    * @param result  The result of a previous call to this method, null
649    *          if not called yet.  NOTE: This is unused in this
650    *          method, because comparison operators always return
651    *          pre-allocated values.
652    *
653    * @return  A SQL boolean value telling whether the first operand is
654    *      less than the second operand
655    *
656    * @exception StandardException    Thrown on error
657    */
658 
659   public final BooleanDataValue lessThan(DataValueDescriptor left,
660                DataValueDescriptor right)
661                 throws StandardException
662   {
663     boolean isLessThan;
664 
665     if (left.isNull() || right.isNull())
666     {
667       isLessThan = false;
668     }
669     else
670     {  
671       isLessThan = SQLBinary.compare(left.getBytes(), right.getBytes()) < 0;
672     }
673 
674     return SQLBoolean.truthValue(left,
675                    right,
676                    isLessThan);
677   }
678 
679   /**
680    * The > operator as called from the language module, as opposed to
681    * the storage module.
682    *
683    * @param left      The value on the left side of the >
684    * @param right      The value on the right side of the >
685    *
686    * @return  A SQL boolean value telling whether the first operand is
687    *      greater than the second operand
688    *
689    * @exception StandardException    Thrown on error
690    */
691 
692   public final BooleanDataValue greaterThan(DataValueDescriptor left,
693                DataValueDescriptor right)
694                 throws StandardException
695   {
696     boolean isGreaterThan = false;
697 
698     if (left.isNull() || right.isNull())
699     {
700       isGreaterThan = false;
701     }
702     else
703     {  
704       isGreaterThan = SQLBinary.compare(left.getBytes(), right.getBytes()) > 0;
705     }
706 
707     return SQLBoolean.truthValue(left,
708                    right,
709                    isGreaterThan);
710   }
711 
712   /**
713    * The <= operator as called from the language module, as opposed to
714    * the storage module.
715    *
716    * @param left      The value on the left side of the <=
717    * @param right      The value on the right side of the <=
718    *
719    * @return  A SQL boolean value telling whether the first operand is
720    *      less than or equal to the second operand
721    *
722    * @exception StandardException    Thrown on error
723    */
724 
725   public final BooleanDataValue lessOrEquals(DataValueDescriptor left,
726                DataValueDescriptor right)
727                 throws StandardException
728   {
729     boolean isLessEquals = false;
730 
731     if (left.isNull() || right.isNull())
732     {
733       isLessEquals = false;
734     }
735     else
736     {  
737       isLessEquals = SQLBinary.compare(left.getBytes(), right.getBytes()) <= 0;
738     }
739 
740     return SQLBoolean.truthValue(left,
741                    right,
742                    isLessEquals);
743   }
744 
745   /**
746    * The >= operator as called from the language module, as opposed to
747    * the storage module.
748    *
749    * @param left      The value on the left side of the >=
750    * @param right      The value on the right side of the >=
751    *
752    * @return  A SQL boolean value telling whether the first operand is
753    *      greater than or equal to the second operand
754    *
755    * @exception StandardException    Thrown on error
756    */
757 
758   public final BooleanDataValue greaterOrEquals(DataValueDescriptor left,
759                DataValueDescriptor right)
760                 throws StandardException
761   {
762     boolean isGreaterEquals = false;
763 
764     if (left.isNull() || right.isNull())
765     {
766       isGreaterEquals = false;
767     }
768     else
769     {  
770       isGreaterEquals = SQLBinary.compare(left.getBytes(), right.getBytes()) >= 0;
771     }
772 
773     return SQLBoolean.truthValue(left,
774                    right,
775                    isGreaterEquals);
776   }
777 
778 
779   /**
780    *
781    * This method implements the char_length function for bit.
782    *
783    * @param result  The result of a previous call to this method, null
784    *          if not called yet
785    *
786    * @return  A SQLInteger containing the length of the char value
787    *
788    * @exception StandardException    Thrown on error
789    *
790    * @see ConcatableDataValue#charLength
791    */
792 
793   public final NumberDataValue charLength(NumberDataValue result)
794               throws StandardException
795   {
796     if (result == null)
797     {
798       result = new SQLInteger();
799     }
800 
801     if (this.isNull())
802     {
803       result.setToNull();
804       return result;
805     }
806 
807 
808     result.setValue(getValue().length);
809     return result;
810   }
811 
812   /**
813    * @see BitDataValue#concatenate
814    *
815    * @exception StandardException    Thrown on error
816    */
817   public final BitDataValue concatenate(
818         BitDataValue left,
819         BitDataValue right,
820         BitDataValue result)
821     throws StandardException
822   {
823     if (left.isNull() || right.isNull())
824     {
825       result.setToNull();
826       return result;
827     }
828 
829     byte[] leftData = left.getBytes();
830     byte[] rightData = right.getBytes();
831 
832     byte[] concatData = new byte[leftData.length + rightData.length];
833 
834     System.arraycopy(leftData, 0, concatData, 0, leftData.length);
835     System.arraycopy(rightData, 0, concatData, leftData.length, rightData.length);
836 
837 
838     result.setValue(concatData);
839     return result;
840   }
841 
842   
843   /**
844    * The SQL substr() function.
845    *
846    * @param start    Start of substr
847    * @param length  Length of substr
848    * @param result  The result of a previous call to this method,
849    *          null if not called yet.
850    * @param maxLen  Maximum length of the result
851    *
852    * @return  A ConcatableDataValue containing the result of the substr()
853    *
854    * @exception StandardException    Thrown on error
855    */
856   public final ConcatableDataValue substring(
857         NumberDataValue start,
858         NumberDataValue length,
859         ConcatableDataValue result,
860         int maxLen)
861     throws StandardException
862   {
863     int startInt;
864     int lengthInt;
865     BitDataValue varbitResult;
866 
867     if (result == null)
868     {
869       result = new SQLVarbit();
870     }
871 
872     varbitResult = (BitDataValue) result;
873 
874     /* The result is null if the receiver (this) is null or if the length is negative.
875      * Oracle docs don't say what happens if the start position or the length is a usernull.
876      * We will return null, which is the only sensible thing to do.
877      * (If the user did not specify a length then length is not a user null.)
878      */
879     if (this.isNull() || start.isNull() || (length != null && length.isNull()))
880     {
881       varbitResult.setToNull();
882       return varbitResult;
883     }
884 
885     startInt = start.getInt();
886 
887     // If length is not specified, make it till end of the string
888     if (length != null)
889     {
890       lengthInt = length.getInt();
891     }
892     else lengthInt = getLength() - startInt + 1;
893 
894     /* DB2 Compatibility: Added these checks to match DB2. We currently enforce these
895      * limits in both modes. We could do these checks in DB2 mode only, if needed, so
896      * leaving earlier code for out of range in for now, though will not be exercised
897      */
898     if ((startInt <= 0 || lengthInt < 0 || startInt > getLength() ||
899         lengthInt > getLength() - startInt + 1))
900       throw StandardException.newException(SQLState.LANG_SUBSTR_START_OR_LEN_OUT_OF_RANGE);
901       
902     // Return null if length is non-positive
903     if (lengthInt < 0)
904     {
905       varbitResult.setToNull();
906       return varbitResult;
907     }
908 
909     /* If startInt < 0 then we count from the right of the string */
910     if (startInt < 0)
911     {
912       startInt += getLength();
913       if (startInt < 0)
914       {
915         lengthInt += startInt;
916         startInt = 0;
917       }
918       if (lengthInt + startInt > 0)
919       {
920         lengthInt += startInt;
921       }
922       else
923       {
924         lengthInt = 0;
925       }
926     }
927     else if (startInt > 0)
928     {
929       /* java substr() is 0 based */
930       startInt--;
931     }
932 
933     /* Oracle docs don't say what happens if the window is to the
934      * left of the string.  Return "" if the window
935      * is to the left or right or if the length is 0.
936      */
937     if (lengthInt == 0 ||
938       lengthInt <= 0 - startInt ||
939       startInt > getLength())
940     {
941       varbitResult.setValue(new byte[0]);
942       return varbitResult;
943     }
944 
945     if (lengthInt >= getLength() - startInt)
946     {
947       byte[] substring = new byte[dataValue.length - startInt];
948       System.arraycopy(dataValue, startInt, substring, 0, substring.length);
949       varbitResult.setValue(substring);
950     }
951     else
952     {
953       byte[] substring = new byte[lengthInt];
954       System.arraycopy(dataValue, startInt, substring, 0, substring.length);
955       varbitResult.setValue(substring);
956     }
957 
958     return varbitResult;
959   }
960 
961   /**
962     Host variables are rejected if their length is
963     bigger than the declared length, regardless of
964     if the trailing bytes are the pad character.
965 
966     @exception StandardException Variable is too big.
967   */
968   public final void checkHostVariable(int declaredLength) throws StandardException
969   {
970     // stream length checking occurs at the JDBC layer
971     int variableLength = -1;
972     if (stream == null)
973     {
974       if (dataValue != null)
975         variableLength = dataValue.length;
976     }
977     else
978     {
979       variableLength = streamLength;
980     }
981 
982     if (variableLength != -1 && variableLength > declaredLength)
983         throw StandardException.newException(SQLState.LANG_STRING_TRUNCATION, getTypeName(), 
984               "XX-RESOLVE-XX",
985               String.valueOf(declaredLength));
986   }
987 
988   /*
989    * String display of value
990    */
991 
992   public final String toString()
993   {
994     if (dataValue == null)
995     {
996       if (stream == null)
997       {
998         return "NULL";
999       }
1000      else
1001      {
1002        if (SanityManager.DEBUG)
1003          SanityManager.THROWASSERT(
1004            "value is null, stream is not null");
1005        return "";
1006      }
1007    }
1008    else
1009    {
1010      return org.apache.derby.iapi.util.StringUtil.toHexString(dataValue, 0, dataValue.length);
1011    }
1012  }
1013
1014  /*
1015   * Hash code
1016   */
1017  public final int hashCode()
1018  {
1019    try {
1020      if (getValue() == null)
1021        {
1022          return 0;
1023        }
1024    }
1025    catch (StandardException se)
1026    {
1027      if (SanityManager.DEBUG)
1028        SanityManager.THROWASSERT("Unexpected exception " + se);
1029      return 0;
1030    }
1031
1032    /* Hash code is simply the sum of all of the bytes */
1033    byte[] bytes = dataValue;
1034    int hashcode = 0;
1035
1036    // Build the hash code
1037    for (int index = 0 ; index < bytes.length; index++)
1038    {
1039      byte bv = bytes[index];
1040      if (bv != SQLBinary.PAD)
1041        hashcode += bytes[index];
1042    }
1043
1044    return hashcode;
1045  }
1046  private static int compare(byte[] left, byte[] right) {
1047
1048    int minLen = left.length;
1049    byte[] longer = right;
1050    if (right.length < minLen) {
1051      minLen = right.length;
1052      longer = left;
1053    }
1054
1055    for (int i = 0; i < minLen; i++) {
1056
1057      int lb = left[i] & 0xff;
1058      int rb = right[i] & 0xff;
1059
1060      if (lb == rb)
1061        continue;
1062
1063      return lb - rb;
1064    }
1065
1066    // complete match on all the bytes for the smallest value.
1067
1068    // if the longer value is all pad characters
1069    // then the values are equal.
1070    for (int i = minLen; i < longer.length; i++) {
1071      byte nb = longer[i];
1072      if (nb == SQLBinary.PAD)
1073        continue;
1074
1075      // longer value is bigger.
1076      if (left == longer)
1077        return 1;
1078      return -1;
1079    }
1080
1081    return 0;
1082
1083  }
1084
1085      /** Adding this method to ensure that super class' setInto method doesn't get called
1086      * that leads to the violation of JDBC spec( untyped nulls ) when batching is turned on.
1087      */
1088     public void setInto(PreparedStatement ps, int position) throws SQLException, StandardException {
1089
1090                  ps.setBytes(position, getBytes());
1091     }
1092}