KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.iapi.types.SQLChar
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.services.context.ContextService;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27
28 import org.apache.derby.iapi.services.io.Storable;
29 import org.apache.derby.iapi.services.io.StoredFormatIds;
30 import org.apache.derby.iapi.services.io.StreamStorable;
31 import org.apache.derby.iapi.services.io.FormatIdInputStream;
32
33 import org.apache.derby.iapi.types.DataTypeDescriptor;
34 import org.apache.derby.iapi.types.DataValueDescriptor;
35 import org.apache.derby.iapi.types.TypeId;
36 import org.apache.derby.iapi.types.StringDataValue;
37 import org.apache.derby.iapi.types.NumberDataValue;
38 import org.apache.derby.iapi.types.BooleanDataValue;
39 import org.apache.derby.iapi.types.ConcatableDataValue;
40 import org.apache.derby.iapi.reference.SQLState;
41
42 import org.apache.derby.iapi.error.StandardException;
43
44 import org.apache.derby.iapi.services.cache.ClassSize;
45 import org.apache.derby.iapi.services.io.ArrayInputStream;
46 import org.apache.derby.iapi.util.StringUtil;
47 import org.apache.derby.iapi.services.i18n.LocaleFinder;
48
49 import org.apache.derby.iapi.db.DatabaseContext;
50
51 import org.apache.derby.iapi.types.SQLInteger;
52 import org.apache.derby.iapi.types.SQLDate;
53 import org.apache.derby.iapi.types.SQLTime;
54 import org.apache.derby.iapi.types.SQLTimestamp;
55
56 import java.io.InputStream JavaDoc;
57 import java.io.ObjectOutput JavaDoc;
58 import java.io.ObjectInput JavaDoc;
59 import java.io.IOException JavaDoc;
60 import java.io.UTFDataFormatException JavaDoc;
61 import java.io.EOFException JavaDoc;
62 import java.sql.Date JavaDoc;
63 import java.sql.ResultSet JavaDoc;
64 import java.sql.PreparedStatement JavaDoc;
65 import java.sql.SQLException JavaDoc;
66 import java.sql.Time JavaDoc;
67 import java.sql.Timestamp JavaDoc;
68 import java.text.CollationElementIterator JavaDoc;
69 import java.text.RuleBasedCollator JavaDoc;
70 import java.text.CollationKey JavaDoc;
71 import java.text.DateFormat JavaDoc;
72 import java.util.Locale JavaDoc;
73 import java.util.Calendar JavaDoc;
74
75 /**
76  * SQLChar satisfies the DataValueDescriptor
77  * interfaces (i.e., OrderableDataType). It implements an String holder,
78  * e.g. for storing a column value; it can be specified
79  * when constructed to not allow nulls. Nullability cannot be changed
80  * after construction.
81  * <p>
82  * Because OrderableDataType is a subclass of DataType,
83  * SQLChar can play a role in either a DataType/ValueRow
84  * or a OrderableDataType/KeyRow, interchangeably.
85  */

86 public class SQLChar
87     extends DataType implements StringDataValue, StreamStorable
88 {
89
90     /**
91      * threshold, that decides when we return space back to the VM
92      * see getString() where it is used
93      */

94     protected final static int RETURN_SPACE_THRESHOLD = 4096;
95     
96     /**
97      * when we know that the array needs to grow by at least
98      * one byte, it is not performant to grow by just one byte
99      * instead this amount is used to provide a reasonable growby size.
100      */

101     private final static int GROWBY_FOR_CHAR = 64;
102     /**
103         Static array that can be used for blank padding.
104     */

105     private static final char[] BLANKS = new char[40];
106     static {
107         for (int i = 0; i < BLANKS.length; i++) {
108             BLANKS[i] = ' ';
109         }
110     }
111
112     private static void appendBlanks(char[] ca, int offset, int howMany) {
113         while (howMany > 0) {
114
115             int count = howMany > BLANKS.length ? BLANKS.length : howMany;
116
117             System.arraycopy(BLANKS, 0, ca, offset, count);
118             howMany -= count;
119             offset += count;
120         }
121     }
122     /*
123      * DataValueDescriptor interface
124      * (mostly implemented in DataType)
125      * casts to the
126      * numeric and date/time types as well, "for valid strings"
127      */

128
129     /**
130      * @see DataValueDescriptor#getBoolean
131      *
132      * @exception StandardException Thrown on error
133      */

134     public boolean getBoolean()
135         throws StandardException
136     {
137         if (isNull()) return false;
138
139         // match JCC, match only "0" or "false" for false. No case insensitivity.
140
// everything else is true.
141

142         String JavaDoc cleanedValue = getString().trim();
143
144         return !(cleanedValue.equals("0") || cleanedValue.equals("false"));
145     }
146
147     /**
148      * @see DataValueDescriptor#getByte
149      * @exception StandardException thrown on failure to convert
150      */

151     public byte getByte() throws StandardException
152     {
153         if (isNull()) return (byte)0;
154         try {
155             return Byte.parseByte(getString().trim());
156         } catch (NumberFormatException JavaDoc nfe) {
157             throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "byte");
158         }
159     }
160
161     /**
162      * @see DataValueDescriptor#getShort
163      * @exception StandardException thrown on failure to convert
164      */

165     public short getShort() throws StandardException
166     {
167         if (isNull()) return (short)0;
168         try {
169             return Short.parseShort(getString().trim());
170         } catch (NumberFormatException JavaDoc nfe) {
171             throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "short");
172         }
173     }
174
175     /**
176      * @see DataValueDescriptor#getInt
177      * @exception StandardException thrown on failure to convert
178      */

179     public int getInt() throws StandardException
180     {
181         if (isNull()) return 0;
182         try {
183             return Integer.parseInt(getString().trim());
184         } catch (NumberFormatException JavaDoc nfe) {
185             throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "int");
186         }
187     }
188
189     /**
190      * @see DataValueDescriptor#getLong
191      * @exception StandardException thrown on failure to convert
192      */

193     public long getLong() throws StandardException
194     {
195         if (isNull()) return 0;
196         try {
197             return Long.parseLong(getString().trim());
198         } catch (NumberFormatException JavaDoc nfe) {
199             throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "long");
200         }
201     }
202
203     /**
204      * @see DataValueDescriptor#getFloat
205      * @exception StandardException thrown on failure to convert
206      */

207     public float getFloat() throws StandardException
208     {
209         if (isNull()) return 0;
210         try {
211             return new Float JavaDoc(getString().trim()).floatValue();
212         } catch (NumberFormatException JavaDoc nfe) {
213             throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "float");
214         }
215     }
216
217     /**
218      * @see DataValueDescriptor#getDouble
219      * @exception StandardException thrown on failure to convert
220      */

221     public double getDouble() throws StandardException
222     {
223         if (isNull()) return 0;
224         try {
225             return new Double JavaDoc(getString().trim()).doubleValue();
226         } catch (NumberFormatException JavaDoc nfe) {
227             throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "double");
228         }
229     }
230
231     /**
232      * CHAR/VARCHAR/LONG VARCHAR implementation. Convert to a BigDecimal using getString.
233      */

234     public int typeToBigDecimal() throws StandardException
235     {
236         return java.sql.Types.CHAR;
237     }
238     /**
239      * @see DataValueDescriptor#getDate
240      * @exception StandardException thrown on failure to convert
241      */

242     public Date getDate( Calendar JavaDoc cal) throws StandardException
243     {
244         return getDate( cal, getString(), getLocaleFinder());
245     }
246
247     public static Date getDate(java.util.Calendar JavaDoc cal, String JavaDoc str, LocaleFinder localeFinder) throws StandardException
248     {
249         if( str == null)
250             return null;
251         SQLDate internalDate = new SQLDate( str, false, localeFinder);
252         return internalDate.getDate( cal);
253     }
254
255     /**
256      * @see DataValueDescriptor#getTime
257      * @exception StandardException thrown on failure to convert
258      */

259     public Time getTime(Calendar JavaDoc cal) throws StandardException
260     {
261         return getTime( cal, getString(), getLocaleFinder());
262     }
263
264     /**
265      * @exception StandardException thrown on failure to convert
266      */

267     public static Time getTime( Calendar JavaDoc cal, String JavaDoc str, LocaleFinder localeFinder) throws StandardException
268     {
269         if( str == null)
270             return null;
271         SQLTime internalTime = new SQLTime( str, false, localeFinder, cal);
272         return internalTime.getTime( cal);
273     }
274
275     /**
276      * @see DataValueDescriptor#getTimestamp
277      * @exception StandardException thrown on failure to convert
278      */

279     public Timestamp getTimestamp( Calendar JavaDoc cal) throws StandardException
280     {
281         return getTimestamp( cal, getString(), getLocaleFinder());
282     }
283
284     /**
285      * @see DataValueDescriptor#getTimestamp
286      * @exception StandardException thrown on failure to convert
287      */

288     public static Timestamp getTimestamp(java.util.Calendar JavaDoc cal, String JavaDoc str, LocaleFinder localeFinder)
289         throws StandardException
290     {
291         if( str == null)
292             return null;
293         SQLTimestamp internalTimestamp = new SQLTimestamp( str, false, localeFinder, cal);
294         return internalTimestamp.getTimestamp( cal);
295     }
296
297     /**
298      * @exception StandardException Thrown on error
299      */

300     public Object JavaDoc getObject() throws StandardException
301     {
302         return getString();
303     }
304
305     /**
306      * @exception StandardException Thrown on error
307      */

308     public InputStream getStream() throws StandardException
309     {
310         return stream;
311     }
312
313     /**
314      * @exception StandardException Thrown on error
315      */

316     public int getLength() throws StandardException
317     {
318         if (rawLength != -1)
319             return rawLength;
320
321         String JavaDoc tmpString = getString();
322         return (tmpString == null) ?
323             0 : tmpString.length();
324     }
325
326     public String JavaDoc getTypeName()
327     {
328         return TypeId.CHAR_NAME;
329     }
330
331     /**
332      * If possible, use getCharArray() if you don't really
333      * need a string. getString() will cause an extra
334      * char array to be allocated when it calls the the String()
335      * constructor (the first time through), so may be
336      * cheaper to use getCharArray().
337      *
338      * @exception StandardException Thrown on error
339      */

340     public String JavaDoc getString() throws StandardException
341     {
342         if (value == null) {
343
344             int len = rawLength;
345
346             if (len != -1) {
347
348                 // data is stored in the char[] array
349

350                 value = new String JavaDoc(rawData, 0, len);
351                 if (len > RETURN_SPACE_THRESHOLD) {
352                     // free up this char[] array to reduce memory usage
353
rawData = null;
354                     rawLength = -1;
355                     // clear out the int array as well, so it will stay current
356
intArray = null;
357                     intLength = 0;
358                     cKey = null;
359                 }
360
361             } else if (stream != null) {
362
363                 // data stored as a stream
364
try {
365
366                     if (stream instanceof FormatIdInputStream) {
367                         readExternal((FormatIdInputStream) stream);
368                     } else {
369                         readExternal(new FormatIdInputStream(stream));
370                     }
371                     stream = null;
372
373                     // at this point the value is only in the char[]
374
// so call again to convert to a String
375
return getString();
376
377                 } catch (IOException JavaDoc ioe) {
378
379                     throw StandardException.newException(
380                             SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION,
381                             ioe,
382                             "java.sql.String");
383                 }
384             }
385         }
386
387         return value;
388     }
389
390     /**
391      * Get a char array. Typically, this is a simple
392      * getter that is cheaper than getString() because
393      * we always need to create a char array when
394      * doing I/O. Use this instead of getString() where
395      * reasonable.
396      * <p>
397      * <b>WARNING</b>: may return a character array that has spare
398      * characters at the end. MUST be used in conjunction
399      * with getLength() to be safe.
400      *
401      * @exception StandardException Thrown on error
402      */

403     public char[] getCharArray() throws StandardException
404     {
405         if (isNull())
406         {
407             return (char[])null;
408         }
409         else if (rawLength != -1)
410         {
411             return rawData;
412         }
413         else
414         {
415             // this is expensive -- we are getting a
416
// copy of the char array that the
417
// String wrapper uses.
418
getString();
419             rawData = value.toCharArray();
420             rawLength = rawData.length;
421             // clear out the int array as well, so it will stay current
422
intArray = null;
423             intLength = 0;
424             cKey = null;
425             return rawData;
426         }
427     }
428
429     /*
430      * StreamStorable interface :
431      */

432     public InputStream returnStream()
433     {
434         return stream;
435     }
436
437     /**
438      * Set this value to the on-disk format stream.
439      */

440     public final void setStream(InputStream newStream)
441     {
442         this.value = null;
443         this.rawLength = -1;
444         this.stream = newStream;
445         // clear out the int array as well, so it will stay current
446
intArray = null;
447         intLength = 0;
448         cKey = null;
449     }
450
451     public void loadStream() throws StandardException
452     {
453         getString();
454     }
455
456     /*
457      * Storable interface, implies Externalizable, TypedFormat
458      */

459
460     /**
461         Return my format identifier.
462
463         @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
464     */

465     public int getTypeFormatId() {
466         return StoredFormatIds.SQL_CHAR_ID;
467     }
468
469     /**
470      * see if the String value is null.
471      @see Storable#isNull
472     */

473     public boolean isNull()
474     {
475         return ((value == null) && (rawLength == -1) && (stream == null));
476     }
477
478     /**
479         The maximum stored size is based upon the UTF format
480         used to stored the String. The format consists of
481         a two byte length field and a maximum number of three
482         bytes for each character.
483         <BR>
484         This puts an upper limit on the length of a stored
485         String. The maximum stored length is 65535, these leads to
486         the worse case of a maximum string length of 21844 ((65535 - 2) / 3).
487         <BR>
488         Strings with stored length longer than 64K is handled with
489         the following format:
490         (1) 2 byte length: will be assigned 0.
491         (2) UTF formated string data.
492         (3) terminate the string with the following 3 bytes:
493             first byte is:
494             +---+---+---+---+---+---+---+---+
495             | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
496             +---+---+---+---+---+---+---+---+
497             second byte is:
498             +---+---+---+---+---+---+---+---+
499             | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
500             +---+---+---+---+---+---+---+---+
501             third byte is:
502             +---+---+---+---+---+---+---+---+
503             | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
504             +---+---+---+---+---+---+---+---+
505
506
507         The UTF format:
508         Writes a string to the underlying output stream using UTF-8
509         encoding in a machine-independent manner.
510         <p>
511         First, two bytes are written to the output stream as if by the
512         <code>writeShort</code> method giving the number of bytes to
513         follow. This value is the number of bytes actually written out,
514         not the length of the string. Following the length, each character
515         of the string is output, in sequence, using the UTF-8 encoding
516         for the character.
517         @exception IOException if an I/O error occurs.
518         @since JDK1.0
519
520
521       @exception IOException thrown by writeUTF
522
523       @see java.io.DataInputStream
524
525     */

526     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc
527     {
528         // never called when value is null
529
if (SanityManager.DEBUG)
530             SanityManager.ASSERT(!isNull());
531
532         String JavaDoc lvalue = null;
533         char[] data = null;
534
535         int strlen = rawLength;
536         boolean isRaw;
537
538         if (strlen < 0) {
539             lvalue = value;
540             strlen = lvalue.length();
541             isRaw = false;
542         } else {
543             data = rawData;
544             isRaw = true;
545         }
546
547         // byte length will always be at least string length
548
int utflen = strlen;
549
550         for (int i = 0 ; (i < strlen) && (utflen <= 65535); i++)
551         {
552             int c = isRaw ? data[i] : lvalue.charAt(i);
553             if ((c >= 0x0001) && (c <= 0x007F))
554             {
555                 // 1 byte for character
556
}
557             else if (c > 0x07FF)
558             {
559                 utflen += 2; // 3 bytes for character
560
}
561             else
562             {
563                 utflen += 1; // 2 bytes for character
564
}
565         }
566
567         boolean isLongUTF = false;
568         // for length than 64K, see format description above
569
if (utflen > 65535)
570         {
571             isLongUTF = true;
572             utflen = 0;
573         }
574
575         out.write((utflen >>> 8) & 0xFF);
576         out.write((utflen >>> 0) & 0xFF);
577         for (int i = 0 ; i < strlen ; i++)
578         {
579             int c = isRaw ? data[i] : lvalue.charAt(i);
580             if ((c >= 0x0001) && (c <= 0x007F))
581             {
582                 out.write(c);
583             }
584             else if (c > 0x07FF)
585             {
586                 out.write(0xE0 | ((c >> 12) & 0x0F));
587                 out.write(0x80 | ((c >> 6) & 0x3F));
588                 out.write(0x80 | ((c >> 0) & 0x3F));
589             }
590             else
591             {
592                 out.write(0xC0 | ((c >> 6) & 0x1F));
593                 out.write(0x80 | ((c >> 0) & 0x3F));
594             }
595         }
596
597         if (isLongUTF)
598         {
599             // write the following 3 bytes to terminate the string:
600
// (11100000, 00000000, 00000000)
601
out.write(0xE0);
602             out.write(0);
603             out.write(0);
604         }
605     }
606
607     /**
608      * Reads in a string from the specified data input stream. The
609      * string has been encoded using a modified UTF-8 format.
610      * <p>
611      * The first two bytes are read as if by
612      * <code>readUnsignedShort</code>. This value gives the number of
613      * following bytes that are in the encoded string, not
614      * the length of the resulting string. The following bytes are then
615      * interpreted as bytes encoding characters in the UTF-8 format
616      * and are converted into characters.
617      * <p>
618      * This method blocks until all the bytes are read, the end of the
619      * stream is detected, or an exception is thrown.
620      *
621      * @param in a data input stream.
622      * @exception EOFException if the input stream reaches the end
623      * before all the bytes.
624      * @exception IOException if an I/O error occurs.
625      * @exception UTFDataFormatException if the bytes do not represent a
626      * valid UTF-8 encoding of a Unicode string.
627      * @see java.io.DataInputStream#readUnsignedShort()
628      
629      * @see java.io.Externalizable#readExternal
630      */

631     public void readExternalFromArray(ArrayInputStream in)
632         throws IOException JavaDoc
633     {
634         arg_passer[0] = rawData;
635
636         rawLength = in.readCloudscapeUTF(arg_passer);
637
638         rawData = arg_passer[0];
639
640         // restoreToNull();
641
value = null;
642         stream = null;
643
644         // clear out the int array, so it will stay current
645
intArray = null;
646         intLength = 0;
647         cKey = null;
648     }
649     char[][] arg_passer = new char[1][];
650
651     public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc
652     {
653         // if in.available() blocked at 0, use this default string size
654

655         int utflen = in.readUnsignedShort();
656
657         int requiredLength;
658         // minimum amount that is reasonable to grow the array
659
// when we know the array needs to growby at least one
660
// byte but we dont want to grow by one byte as that
661
// is not performant
662
int minGrowBy = growBy();
663         if (utflen != 0)
664         {
665             // the object was not stored as a streaming column
666
// we know exactly how long it is
667
requiredLength = utflen;
668         }
669         else
670         {
671             // the object was stored as a streaming column
672
// and we have a clue how much we can read unblocked
673
// OR
674
// The original string was a 0 length string.
675
requiredLength = in.available();
676             if (requiredLength < minGrowBy)
677                 requiredLength = minGrowBy;
678         }
679
680         char str[];
681         if ((rawData == null) || (requiredLength > rawData.length)) {
682             
683             str = new char[requiredLength];
684         } else {
685             str = rawData;
686         }
687         int arrayLength = str.length;
688
689         // Set these to null to allow GC of the array if required.
690
rawData = null;
691         restoreToNull();
692
693         int count = 0;
694         int strlen = 0;
695
696 readingLoop:
697         while ( ((count < utflen) || (utflen == 0)))
698         {
699             int c;
700
701             try {
702
703                 c = in.readUnsignedByte();
704             } catch (EOFException JavaDoc eof) {
705                 if (utflen != 0)
706                     throw new EOFException JavaDoc();
707
708                 // This is the case for a 0 length string.
709
// OR the string was originally streamed in
710
// which puts a 0 for utflen but no trailing
711
// E0,0,0 markers.
712
break readingLoop;
713             }
714
715             //if (c == -1) // read EOF
716
//{
717
// if (utflen != 0)
718
// throw new EOFException();
719

720             // break;
721
//}
722

723             // change it to an unsigned byte
724
//c &= 0xFF;
725

726             if (strlen >= arrayLength) // the char array needs to be grown
727
{
728                 int growby = in.available();
729                 // We know that the array needs to be grown by at least one.
730
// However, even if the input stream wants to block on every
731
// byte, we don't want to grow by a byte at a time.
732
// Note, for large data (clob > 32k), it is performant
733
// to grow the array by atleast 4k rather than a small amount
734
// Even better maybe to grow by 32k but then may be
735
// a little excess(?) for small data.
736
// hopefully in.available() will give a fair
737
// estimate of how much data can be read to grow the
738
// array by larger and necessary chunks.
739
// This performance issue due to
740
// the slow growth of this array was noticed since inserts
741
// on clobs was taking a really long time as
742
// the array here grew previously by 64 bytes each time
743
// till stream was drained. (Derby-302)
744
// for char, growby 64 seems reasonable, but for varchar
745
// clob 4k or 32k is performant and hence
746
// growBy() is override correctly to ensure this
747
if (growby < minGrowBy)
748                     growby = minGrowBy;
749
750                 int newstrlength = arrayLength + growby;
751                 char oldstr[] = str;
752                 str = new char[newstrlength];
753
754                 System.arraycopy(oldstr, 0, str, 0, arrayLength);
755                 arrayLength = newstrlength;
756             }
757
758             /// top fours bits of the first unsigned byte that maps to a
759
// 1,2 or 3 byte character
760
//
761
// 0000xxxx - 0 - 1 byte char
762
// 0001xxxx - 1 - 1 byte char
763
// 0010xxxx - 2 - 1 byte char
764
// 0011xxxx - 3 - 1 byte char
765
// 0100xxxx - 4 - 1 byte char
766
// 0101xxxx - 5 - 1 byte char
767
// 0110xxxx - 6 - 1 byte char
768
// 0111xxxx - 7 - 1 byte char
769
// 1000xxxx - 8 - error
770
// 1001xxxx - 9 - error
771
// 1010xxxx - 10 - error
772
// 1011xxxx - 11 - error
773
// 1100xxxx - 12 - 2 byte char
774
// 1101xxxx - 13 - 2 byte char
775
// 1110xxxx - 14 - 3 byte char
776
// 1111xxxx - 15 - error
777

778             int char2, char3;
779             char actualChar;
780             if ((c & 0x80) == 0x00)
781             {
782                 // one byte character
783
count++;
784                 actualChar = (char) c;
785             }
786             else if ((c & 0x60) == 0x40) // we know the top bit is set here
787
{
788                 // two byte character
789
count += 2;
790                 if (utflen != 0 && count > utflen)
791                     throw new UTFDataFormatException JavaDoc();
792                 char2 = in.readUnsignedByte();
793                 if ((char2 & 0xC0) != 0x80)
794                     throw new UTFDataFormatException JavaDoc();
795                 actualChar = (char)(((c & 0x1F) << 6) | (char2 & 0x3F));
796             }
797             else if ((c & 0x70) == 0x60) // we know the top bit is set here
798
{
799                 // three byte character
800
count += 3;
801                 if (utflen != 0 && count > utflen)
802                     throw new UTFDataFormatException JavaDoc();
803                 char2 = in.readUnsignedByte();
804                 char3 = in.readUnsignedByte();
805                 if ((c == 0xE0) && (char2 == 0) && (char3 == 0)
806                     && (utflen == 0))
807                 {
808                     // we reached the end of a long string,
809
// that was terminated with
810
// (11100000, 00000000, 00000000)
811
break readingLoop;
812                 }
813
814                 if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
815                     throw new UTFDataFormatException JavaDoc();
816                 
817                 
818                 actualChar = (char)(((c & 0x0F) << 12) |
819                                            ((char2 & 0x3F) << 6) |
820                                            ((char3 & 0x3F) << 0));
821             }
822             else {
823
824                 throw new UTFDataFormatException JavaDoc();
825             }
826
827             str[strlen++] = actualChar;
828         }
829
830
831         rawData = str;
832         rawLength = strlen;
833                         
834         // clear out the int array, so it will stay current
835
intArray = null;
836         intLength = 0;
837         cKey = null;
838     }
839
840     /**
841      * returns the reasonable minimum amount by
842      * which the array can grow . See readExternal.
843      * when we know that the array needs to grow by at least
844      * one byte, it is not performant to grow by just one byte
845      * instead this amount is used to provide a resonable growby size.
846      * @return minimum reasonable growby size
847      */

848     protected int growBy()
849     {
850         return GROWBY_FOR_CHAR; //seems reasonable for a char
851
}
852     /**
853      * @see Storable#restoreToNull
854      *
855      */

856     public void restoreToNull()
857     {
858         value = null;
859         stream = null;
860         rawLength = -1;
861         // clear out the int array as well, so it will stay current
862
intArray = null;
863         intLength = 0;
864         cKey = null;
865     }
866
867     /**
868         @exception StandardException thrown on error
869      */

870     public boolean compare(int op,
871                            DataValueDescriptor other,
872                            boolean orderedNulls,
873                            boolean unknownRV)
874         throws StandardException
875     {
876         if (!orderedNulls) // nulls are unordered
877
{
878             if (this.isNull() || ((DataValueDescriptor) other).isNull())
879                 return unknownRV;
880         }
881
882         /* When comparing String types to non-string types, we always
883          * convert the string type to the non-string type.
884          */

885         if (! (other instanceof SQLChar))
886         {
887             return other.compare(flip(op), this, orderedNulls, unknownRV);
888         }
889
890         /* Do the comparison */
891         return super.compare(op, other, orderedNulls, unknownRV);
892     }
893
894     /**
895         @exception StandardException thrown on error
896      */

897     public int compare(DataValueDescriptor other) throws StandardException
898     {
899         /* Use compare method from dominant type, negating result
900          * to reflect flipping of sides.
901          */

902         if (typePrecedence() < other.typePrecedence())
903         {
904             return - (other.compare(this));
905         }
906
907         // stringCompare deals with null as comparable and smallest
908
return stringCompare(this, (SQLChar)other);
909     }
910
911     /*
912      * CloneableObject interface
913      */

914
915     /** From CloneableObject
916      * Shallow clone a StreamStorable without objectifying. This is used to avoid
917      * unnecessary objectifying of a stream object. The only difference of this method
918      * from getClone is this method does not objectify a stream. beetle 4896
919      */

920     public Object JavaDoc cloneObject()
921     {
922         if (stream == null)
923             return getClone();
924         SQLChar self = (SQLChar) getNewNull();
925         self.copyState(this);
926         return self;
927     }
928
929     /*
930      * DataValueDescriptor interface
931      */

932
933     /** @see DataValueDescriptor#getClone */
934     public DataValueDescriptor getClone()
935     {
936         try
937         {
938             return new SQLChar(getString());
939         }
940         catch (StandardException se)
941         {
942             if (SanityManager.DEBUG)
943                 SanityManager.THROWASSERT("Unexpected exception " + se);
944             return null;
945         }
946     }
947
948     /**
949      * @see DataValueDescriptor#getNewNull
950      *
951      */

952     public DataValueDescriptor getNewNull()
953     {
954         return new SQLChar();
955     }
956
957     /**
958      * @see DataValueDescriptor#setValueFromResultSet
959      *
960      * @exception SQLException Thrown on error
961      */

962     public final void setValueFromResultSet(ResultSet JavaDoc resultSet, int colNumber,
963                                       boolean isNullable)
964         throws SQLException JavaDoc
965     {
966             setValue(resultSet.getString(colNumber));
967     }
968
969     /**
970         Set the value into a PreparedStatement.
971     */

972     public final void setInto(PreparedStatement JavaDoc ps, int position) throws SQLException JavaDoc, StandardException {
973
974         ps.setString(position, getString());
975     }
976
977
978     /*
979      * class interface
980      */

981
982     /*
983      * constructors
984      */

985
986     /**
987         no-arg constructor, required by Formattable.
988     */

989     public SQLChar()
990     {
991     }
992
993     public SQLChar(String JavaDoc val)
994     {
995         value = val;
996     }
997
998     public void setValue(String JavaDoc theValue)
999     {
1000        stream = null;
1001        rawLength = -1;
1002        // clear out the int array as well, so it will stay current
1003
intArray = null;
1004        intLength = 0;
1005        cKey = null;
1006
1007        value = theValue;
1008    }
1009
1010    public void setValue(boolean theValue) throws StandardException
1011    {
1012        // match JCC.
1013
setValue(theValue ? "1" : "0");
1014    }
1015
1016    public void setValue(int theValue) throws StandardException
1017    {
1018        setValue(Integer.toString(theValue));
1019    }
1020
1021    public void setValue(double theValue) throws StandardException
1022    {
1023        setValue(Double.toString(theValue));
1024    }
1025
1026    public void setValue(float theValue) throws StandardException
1027    {
1028        setValue(Float.toString(theValue));
1029    }
1030
1031    public void setValue(short theValue) throws StandardException
1032    {
1033        setValue(Short.toString(theValue));
1034    }
1035
1036    public void setValue(long theValue) throws StandardException
1037    {
1038        setValue(Long.toString(theValue));
1039    }
1040
1041    public void setValue(byte theValue) throws StandardException
1042    {
1043        setValue(Byte.toString(theValue));
1044    }
1045
1046    public void setValue(byte[] theValue) throws StandardException
1047    {
1048        if (theValue == null)
1049        {
1050            restoreToNull();
1051            return;
1052        }
1053
1054        /*
1055        ** We can't just do a new String(theValue)
1056        ** because that method assumes we are converting
1057        ** ASCII and it will take on char per byte.
1058        ** So we need to convert the byte array to a
1059        ** char array and go from there.
1060        **
1061        ** If we have an odd number of bytes pad out.
1062        */

1063        int mod = (theValue.length % 2);
1064        int len = (theValue.length/2) + mod;
1065        char[] carray = new char[len];
1066        int cindex = 0;
1067        int bindex = 0;
1068
1069        /*
1070        ** If we have a left over byte, then get
1071        ** that now.
1072        */

1073        if (mod == 1)
1074        {
1075            carray[--len] = (char)(theValue[theValue.length - 1] << 8);
1076        }
1077
1078        for (; cindex < len; bindex+=2, cindex++)
1079        {
1080            carray[cindex] = (char)((theValue[bindex] << 8) |
1081                                (theValue[bindex+1] & 0x00ff));
1082        }
1083
1084        setValue(new String JavaDoc(carray));
1085    }
1086
1087    /**
1088        Only to be called when an application through JDBC is setting a
1089        SQLChar to a java.math.BigDecimal.
1090    */

1091    public void setBigDecimal(Number JavaDoc bigDecimal) throws StandardException
1092    {
1093        if (bigDecimal == null)
1094            setToNull();
1095        else
1096            setValue(bigDecimal.toString());
1097    }
1098
1099    /** @exception StandardException Thrown on error */
1100    public void setValue(Date theValue, Calendar JavaDoc cal) throws StandardException
1101    {
1102        String JavaDoc strValue = null;
1103        if( theValue != null)
1104        {
1105            if( cal == null)
1106                strValue = theValue.toString();
1107            else
1108            {
1109                cal.setTime( theValue);
1110                StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1111                formatJDBCDate( cal, sb);
1112                strValue= sb.toString();
1113            }
1114        }
1115        setValue( strValue);
1116    }
1117
1118    /** @exception StandardException Thrown on error */
1119    public void setValue(Time theValue, Calendar JavaDoc cal) throws StandardException
1120    {
1121        String JavaDoc strValue = null;
1122        if( theValue != null)
1123        {
1124            if( cal == null)
1125                strValue = theValue.toString();
1126            else
1127            {
1128                cal.setTime( theValue);
1129                StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1130                formatJDBCTime( cal, sb);
1131                strValue= sb.toString();
1132            }
1133        }
1134        setValue( strValue);
1135    }
1136
1137    /** @exception StandardException Thrown on error */
1138    public void setValue(Timestamp theValue, Calendar JavaDoc cal) throws StandardException
1139    {
1140        String JavaDoc strValue = null;
1141        if( theValue != null)
1142        {
1143            if( cal == null)
1144                strValue = theValue.toString();
1145            else
1146            {
1147                cal.setTime( theValue);
1148                StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1149                formatJDBCDate( cal, sb);
1150                sb.append( ' ');
1151                formatJDBCTime( cal, sb);
1152                int micros = (theValue.getNanos() + SQLTimestamp.FRACTION_TO_NANO/2)/SQLTimestamp.FRACTION_TO_NANO;
1153                if( micros > 0)
1154                {
1155                    sb.append( '.');
1156                    String JavaDoc microsStr = Integer.toString( micros);
1157                    if( microsStr.length() > SQLTimestamp.MAX_FRACTION_DIGITS)
1158                        sb.append( microsStr.substring( 0, SQLTimestamp.MAX_FRACTION_DIGITS));
1159                    else
1160                    {
1161                        for( int i = microsStr.length(); i < SQLTimestamp.MAX_FRACTION_DIGITS ; i++)
1162                            sb.append( '0');
1163                        sb.append( microsStr);
1164                    }
1165                }
1166                strValue= sb.toString();
1167            }
1168        }
1169        setValue( strValue);
1170    }
1171
1172    private void formatJDBCDate( Calendar JavaDoc cal, StringBuffer JavaDoc sb)
1173    {
1174        SQLDate.dateToString( cal.get( Calendar.YEAR),
1175                              cal.get( Calendar.MONTH) - Calendar.JANUARY + 1,
1176                              cal.get( Calendar.DAY_OF_MONTH),
1177                              sb);
1178    }
1179
1180    private void formatJDBCTime( Calendar JavaDoc cal, StringBuffer JavaDoc sb)
1181    {
1182        SQLTime.timeToString( cal.get( Calendar.HOUR), cal.get( Calendar.MINUTE), cal.get( Calendar.SECOND), sb);
1183    }
1184
1185    /**
1186     * Set the value from the stream which is in the on-disk format.
1187     * @param theStream On disk format of the stream
1188     * @param valueLength length of the logical value in characters.
1189     */

1190    public final void setValue(InputStream theStream, int valueLength)
1191    {
1192        setStream(theStream);
1193    }
1194    
1195    /**
1196     * Allow any Java type to be cast to a character type using
1197     * Object.toString.
1198     * @see DataValueDescriptor#setObjectForCast
1199     *
1200     * @exception StandardException
1201     * thrown on failure
1202     */

1203    public void setObjectForCast(Object JavaDoc theValue, boolean instanceOfResultType,
1204            String JavaDoc resultTypeClassName) throws StandardException {
1205        
1206        if (theValue == null)
1207        {
1208            setToNull();
1209            return;
1210        }
1211
1212        if ("java.lang.String".equals(resultTypeClassName))
1213            setValue(theValue.toString());
1214        else
1215            super.setObjectForCast(theValue, instanceOfResultType, resultTypeClassName);
1216    }
1217    
1218    protected void setFrom(DataValueDescriptor theValue) throws StandardException {
1219
1220        setValue(theValue.getString());
1221    }
1222
1223    /**
1224     * Normalization method - this method may be called when putting
1225     * a value into a SQLChar, for example, when inserting into a SQLChar
1226     * column. See NormalizeResultSet in execution.
1227     *
1228     * @param desiredType The type to normalize the source column to
1229     * @param source The value to normalize
1230     *
1231     *
1232     * @exception StandardException Thrown for null into
1233     * non-nullable column, and for
1234     * truncation error
1235     */

1236
1237    public void normalize(
1238                DataTypeDescriptor desiredType,
1239                DataValueDescriptor source)
1240                    throws StandardException
1241    {
1242
1243        normalize(desiredType, source.getString());
1244
1245    }
1246
1247    protected void normalize(DataTypeDescriptor desiredType, String JavaDoc sourceValue)
1248        throws StandardException
1249    {
1250
1251
1252        int desiredWidth = desiredType.getMaximumWidth();
1253        int sourceWidth = sourceValue.length();
1254
1255        /*
1256        ** If the input is already the right length, no normalization is
1257        ** necessary - just return the source.
1258        */

1259        if (sourceWidth == desiredWidth) {
1260            setValue(sourceValue);
1261            return;
1262        }
1263
1264        /*
1265        ** If the input is shorter than the desired type, construct a new
1266        ** SQLChar padded with blanks to the right length.
1267        */

1268        if (sourceWidth < desiredWidth)
1269        {
1270            setToNull();
1271
1272            char[] ca;
1273            if ((rawData == null) || (desiredWidth > rawData.length)) {
1274            
1275                ca = rawData = new char[desiredWidth];
1276            } else {
1277                ca = rawData;
1278            }
1279
1280            sourceValue.getChars(0, sourceWidth, ca, 0);
1281            SQLChar.appendBlanks(ca, sourceWidth, desiredWidth - sourceWidth);
1282
1283            rawLength = desiredWidth;
1284
1285            return;
1286        }
1287
1288        /*
1289        ** Check whether any non-blank characters will be truncated.
1290        */

1291        hasNonBlankChars(sourceValue, desiredWidth, sourceWidth);
1292
1293        /*
1294        ** No non-blank characters will be truncated. Truncate the blanks
1295        ** to the desired width.
1296        */

1297
1298        String JavaDoc truncatedString = sourceValue.substring(0, desiredWidth);
1299        setValue(truncatedString);
1300    }
1301
1302    /*
1303    ** Method to check for truncation of non blank chars.
1304    */

1305    protected final void hasNonBlankChars(String JavaDoc source, int start, int end)
1306        throws StandardException
1307    {
1308        /*
1309        ** Check whether any non-blank characters will be truncated.
1310        */

1311        for (int posn = start; posn < end; posn++)
1312        {
1313            if (source.charAt(posn) != ' ')
1314            {
1315                throw StandardException.newException(SQLState.LANG_STRING_TRUNCATION, getTypeName(), StringUtil.formatForPrint(source), String.valueOf(start));
1316            }
1317        }
1318    }
1319
1320    ///////////////////////////////////////////////////////////////
1321
//
1322
// VariableSizeDataValue INTERFACE
1323
//
1324
///////////////////////////////////////////////////////////////
1325

1326    /**
1327     * Set the width of the to the desired value. Used
1328     * when CASTing. Ideally we'd recycle normalize(), but
1329     * the behavior is different (we issue a warning instead
1330     * of an error, and we aren't interested in nullability).
1331     *
1332     * @param desiredWidth the desired length
1333     * @param desiredScale the desired scale (ignored)
1334     * @param errorOnTrunc throw an error on truncation
1335     *
1336     * @exception StandardException Thrown when errorOnTrunc
1337     * is true and when a shrink will truncate non-white
1338     * spaces.
1339     */

1340    public void setWidth(int desiredWidth,
1341                                    int desiredScale, // Ignored
1342
boolean errorOnTrunc)
1343                            throws StandardException
1344    {
1345        int sourceWidth;
1346
1347        /*
1348        ** If the input is NULL, nothing to do.
1349        */

1350        if (getString() == null)
1351        {
1352            return;
1353        }
1354
1355        sourceWidth = getLength();
1356
1357        /*
1358        ** If the input is shorter than the desired type, construct a new
1359        ** SQLChar padded with blanks to the right length. Only
1360        ** do this if we have a SQLChar -- SQLVarchars don't
1361        ** pad.
1362        */

1363        if (sourceWidth < desiredWidth)
1364        {
1365            if (!(this instanceof SQLVarchar))
1366            {
1367                StringBuffer JavaDoc strbuf;
1368
1369                strbuf = new StringBuffer JavaDoc(getString());
1370    
1371                for ( ; sourceWidth < desiredWidth; sourceWidth++)
1372                {
1373                    strbuf.append(' ');
1374                }
1375    
1376                setValue(new String JavaDoc(strbuf));
1377            }
1378        }
1379        else if (sourceWidth > desiredWidth && desiredWidth > 0)
1380        {
1381            /*
1382            ** Check whether any non-blank characters will be truncated.
1383            */

1384            if (errorOnTrunc)
1385                hasNonBlankChars(getString(), desiredWidth, sourceWidth);
1386            //RESOLVE: should issue a warning instead
1387

1388            /*
1389            ** Truncate to the desired width.
1390            */

1391            setValue(getString().substring(0, desiredWidth));
1392        }
1393        return;
1394    }
1395
1396    /*
1397    ** SQL Operators
1398    */

1399
1400    /**
1401     * The = operator as called from the language module, as opposed to
1402     * the storage module.
1403     *
1404     * @param left The value on the left side of the =
1405     * @param right The value on the right side of the =
1406     *
1407     * @return A SQL boolean value telling whether the two parameters are equal
1408     *
1409     * @exception StandardException Thrown on error
1410     */

1411
1412    public BooleanDataValue equals(DataValueDescriptor left,
1413                             DataValueDescriptor right)
1414                                throws StandardException
1415    {
1416        boolean comparison;
1417
1418        if ((left instanceof SQLChar) && (right instanceof SQLChar))
1419        {
1420            comparison = stringCompare((SQLChar) left, (SQLChar) right) == 0;
1421        }
1422        else
1423        {
1424            comparison = stringCompare(left.getString(),
1425                                       right.getString()) == 0;
1426        }
1427
1428        return SQLBoolean.truthValue(left,
1429                                     right,
1430                                     comparison);
1431    }
1432
1433    /**
1434     * The <> operator as called from the language module, as opposed to
1435     * the storage module.
1436     *
1437     * @param left The value on the left side of the <>
1438     * @param right The value on the right side of the <>
1439     *
1440     * @return A SQL boolean value telling whether the two parameters
1441     * are not equal
1442     *
1443     * @exception StandardException Thrown on error
1444     */

1445
1446    public BooleanDataValue notEquals(DataValueDescriptor left,
1447                             DataValueDescriptor right)
1448                                throws StandardException
1449    {
1450        boolean comparison;
1451
1452        if ((left instanceof SQLChar) && (right instanceof SQLChar))
1453        {
1454            comparison = stringCompare((SQLChar) left, (SQLChar) right) != 0;
1455        }
1456        else
1457        {
1458            comparison = stringCompare(left.getString(),
1459                                       right.getString()) != 0;
1460        }
1461
1462        return SQLBoolean.truthValue(left,
1463                                     right,
1464                                     comparison);
1465    }
1466
1467    /**
1468     * The < operator as called from the language module, as opposed to
1469     * the storage module.
1470     *
1471     * @param left The value on the left side of the <
1472     * @param right The value on the right side of the <
1473     *
1474     * @return A SQL boolean value telling whether the first operand is
1475     * less than the second operand
1476     *
1477     * @exception StandardException Thrown on error
1478     */

1479
1480    public BooleanDataValue lessThan(DataValueDescriptor left,
1481                             DataValueDescriptor right)
1482                                throws StandardException
1483    {
1484        boolean comparison;
1485
1486        if ((left instanceof SQLChar) && (right instanceof SQLChar))
1487        {
1488            comparison = stringCompare((SQLChar) left, (SQLChar) right) < 0;
1489        }
1490        else
1491        {
1492            comparison = stringCompare(left.getString(),
1493                                       right.getString()) < 0;
1494        }
1495
1496        return SQLBoolean.truthValue(left,
1497                                     right,
1498                                     comparison);
1499    }
1500
1501    /**
1502     * The > operator as called from the language module, as opposed to
1503     * the storage module.
1504     *
1505     * @param left The value on the left side of the >
1506     * @param right The value on the right side of the >
1507     *
1508     * @return A SQL boolean value telling whether the first operand is
1509     * greater than the second operand
1510     *
1511     * @exception StandardException Thrown on error
1512     */

1513
1514    public BooleanDataValue greaterThan(DataValueDescriptor left,
1515                             DataValueDescriptor right)
1516                                throws StandardException
1517    {
1518        boolean comparison;
1519
1520        if ((left instanceof SQLChar) && (right instanceof SQLChar))
1521        {
1522            comparison = stringCompare((SQLChar) left, (SQLChar) right) > 0;
1523        }
1524        else
1525        {
1526            comparison = stringCompare(left.getString(),
1527                                       right.getString()) > 0;
1528        }
1529
1530        return SQLBoolean.truthValue(left,
1531                                     right,
1532                                     comparison);
1533    }
1534
1535    /**
1536     * The <= operator as called from the language module, as opposed to
1537     * the storage module.
1538     *
1539     * @param left The value on the left side of the <=
1540     * @param right The value on the right side of the <=
1541     *
1542     * @return A SQL boolean value telling whether the first operand is
1543     * less than or equal to the second operand
1544     *
1545     * @exception StandardException Thrown on error
1546     */

1547
1548    public BooleanDataValue lessOrEquals(DataValueDescriptor left,
1549                             DataValueDescriptor right)
1550                                throws StandardException
1551    {
1552        boolean comparison;
1553
1554        if ((left instanceof SQLChar) && (right instanceof SQLChar))
1555        {
1556            comparison = stringCompare((SQLChar) left, (SQLChar) right) <= 0;
1557        }
1558        else
1559        {
1560            comparison = stringCompare(left.getString(),
1561                                       right.getString()) <= 0;
1562        }
1563
1564        return SQLBoolean.truthValue(left,
1565                                     right,
1566                                     comparison);
1567    }
1568
1569    /**
1570     * The >= operator as called from the language module, as opposed to
1571     * the storage module.
1572     *
1573     * @param left The value on the left side of the >=
1574     * @param right The value on the right side of the >=
1575     *
1576     * @return A SQL boolean value telling whether the first operand is
1577     * greater than or equal to the second operand
1578     *
1579     * @exception StandardException Thrown on error
1580     */

1581
1582    public BooleanDataValue greaterOrEquals(DataValueDescriptor left,
1583                             DataValueDescriptor right)
1584                                throws StandardException
1585    {
1586        boolean comparison;
1587
1588        if ((left instanceof SQLChar) && (right instanceof SQLChar))
1589        {
1590            comparison = stringCompare((SQLChar) left, (SQLChar) right) >= 0;
1591        }
1592        else
1593        {
1594            comparison = stringCompare(left.getString(),
1595                                       right.getString()) >= 0;
1596        }
1597
1598        return SQLBoolean.truthValue(left,
1599                                     right,
1600                                     comparison);
1601    }
1602
1603    /*
1604    ** Concatable interface
1605    */

1606    /**
1607     * This method implements the char_length function for char.
1608     *
1609     * @param result The result of a previous call to this method, null
1610     * if not called yet
1611     *
1612     * @return A SQLInteger containing the length of the char value
1613     *
1614     * @exception StandardException Thrown on error
1615     *
1616     * @see ConcatableDataValue#charLength(NumberDataValue)
1617     */

1618    public NumberDataValue charLength(NumberDataValue result)
1619                            throws StandardException
1620    {
1621        if (result == null)
1622        {
1623            result = new SQLInteger();
1624        }
1625
1626        if (this.isNull())
1627        {
1628            result.setToNull();
1629            return result;
1630        }
1631
1632        result.setValue(this.getLength());
1633        return result;
1634    }
1635
1636    /**
1637     * @see StringDataValue#concatenate
1638     *
1639     * @exception StandardException Thrown on error
1640     */

1641    public StringDataValue concatenate(
1642                StringDataValue leftOperand,
1643                StringDataValue rightOperand,
1644                StringDataValue result)
1645        throws StandardException
1646    {
1647        if (leftOperand.isNull() || leftOperand.getString() == null ||
1648            rightOperand.isNull() || rightOperand.getString() == null)
1649        {
1650            result.setToNull();
1651            return result;
1652        }
1653
1654        result.setValue(leftOperand.getString().concat(rightOperand.getString()));
1655        return result;
1656    }
1657
1658
1659    /**
1660     * This method implements the like function for char (with no escape value).
1661     *
1662     * @param pattern The pattern to use
1663     *
1664     * @return A SQL boolean value telling whether the first operand is
1665     * like the second operand
1666     *
1667     * @exception StandardException Thrown on error
1668     */

1669    public BooleanDataValue like(DataValueDescriptor pattern)
1670                                throws StandardException
1671    {
1672        Boolean JavaDoc likeResult;
1673
1674        if (! isNationalString())
1675        {
1676            // note that we call getLength() because the length
1677
// of the char array may be different than the
1678
// length we should be using (i.e. getLength()).
1679
// see getCharArray() for more info
1680
char[] evalCharArray = getCharArray();
1681            char[] patternCharArray = ((SQLChar)pattern).getCharArray();
1682            likeResult = Like.like(evalCharArray,
1683                                   getLength(),
1684                                   patternCharArray,
1685                                   pattern.getLength());
1686        }
1687        else
1688        {
1689            SQLChar patternSQLChar = (SQLChar) pattern;
1690            likeResult = Like.like(getIntArray(),
1691                                   getIntLength(),
1692                                   patternSQLChar.getIntArray(),
1693                                   patternSQLChar.getIntLength(),
1694                                   getLocaleFinder().getCollator());
1695        }
1696
1697        return SQLBoolean.truthValue(this,
1698                                     pattern,
1699                                     likeResult);
1700    }
1701
1702    /**
1703     * This method implements the like function for char with an escape value.
1704     *
1705     * @param pattern The pattern to use
1706     *
1707     * @return A SQL boolean value telling whether the first operand is
1708     * like the second operand
1709     *
1710     * @exception StandardException Thrown on error
1711     */

1712
1713    public BooleanDataValue like(
1714                             DataValueDescriptor pattern,
1715                             DataValueDescriptor escape)
1716                                throws StandardException
1717    {
1718        Boolean JavaDoc likeResult;
1719
1720        if (SanityManager.DEBUG)
1721            SanityManager.ASSERT(
1722                             pattern instanceof StringDataValue &&
1723                             escape instanceof StringDataValue,
1724            "All three operands must be instances of StringDataValue");
1725
1726        // ANSI states a null escape yields 'unknown' results
1727
//
1728
// This method is only called when we have an escape clause, so this
1729
// test is valid
1730

1731        if (escape.isNull())
1732        {
1733            throw StandardException.newException(SQLState.LANG_ESCAPE_IS_NULL);
1734        }
1735
1736        if (! isNationalString())
1737        {
1738            // note that we call getLength() because the length
1739
// of the char array may be different than the
1740
// length we should be using (i.e. getLength()).
1741
// see getCharArray() for more info
1742
char[] evalCharArray = getCharArray();
1743            char[] patternCharArray = ((SQLChar)pattern).getCharArray();
1744            char[] escapeCharArray = (((SQLChar) escape).getCharArray());
1745            int escapeLength = escape.getLength();
1746
1747            if (escapeCharArray != null && escapeLength != 1 )
1748            {
1749                throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_CHARACTER,
1750                        new String JavaDoc(escapeCharArray));
1751            }
1752            else
1753            {
1754              // Make sure we fail for both varchar an nvarchar
1755
// for multiple collation characters.
1756
SQLChar escapeSQLChar = (SQLChar) escape;
1757              int[] escapeIntArray = escapeSQLChar.getIntArray();
1758              if (escapeIntArray != null && (escapeIntArray.length != 1))
1759              {
1760                throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_CHARACTER,new String JavaDoc(escapeSQLChar.getCharArray()));
1761              }
1762            }
1763            likeResult = Like.like(evalCharArray,
1764                                   getLength(),
1765                                   patternCharArray,
1766                                   pattern.getLength(),
1767                                   escapeCharArray,
1768                                   escapeLength);
1769        }
1770        else
1771        {
1772            SQLChar patternSQLChar = (SQLChar) pattern;
1773            SQLChar escapeSQLChar = (SQLChar) escape;
1774            int[] escapeIntArray = escapeSQLChar.getIntArray();
1775            int escapeLength = escapeSQLChar.getIntLength();
1776
1777            if (escapeIntArray != null && (escapeIntArray.length != 1))
1778            {
1779                throw StandardException.newException(SQLState.LANG_INVALID_ESCAPE_CHARACTER,
1780                        new String JavaDoc(escapeSQLChar.getCharArray()));
1781            }
1782            likeResult = Like.like(getIntArray(),
1783                                   getIntLength(),
1784                                   patternSQLChar.getIntArray(),
1785                                   patternSQLChar.getIntLength(),
1786                                   escapeIntArray,
1787                                   escapeLength,
1788                                   getLocaleFinder().getCollator());
1789        }
1790
1791        return SQLBoolean.truthValue(this,
1792                                     pattern,
1793                                     likeResult);
1794    }
1795
1796    /**
1797     * This method implements the locate function for char.
1798     * @param searchFrom - The string to search from
1799     * @param start - The position to search from in string searchFrom
1800     * @param result - The object to return
1801     *
1802     * Note: use getString() to get the string to search for.
1803     *
1804     * @return The position in searchFrom the fist occurrence of this.value.
1805     * 0 is returned if searchFrom does not contain this.value.
1806     * @exception StandardException Thrown on error
1807     */

1808    public NumberDataValue locate( StringDataValue searchFrom,
1809                                    NumberDataValue start,
1810                                    NumberDataValue result)
1811                                    throws StandardException
1812    {
1813        int startVal;
1814
1815        if( result == null )
1816        {
1817            result = new SQLInteger();
1818        }
1819        
1820        if( start.isNull() )
1821        {
1822            startVal = 1;
1823        }
1824        else
1825        {
1826            startVal = start.getInt();
1827        }
1828
1829        if( isNull() || searchFrom.isNull() )
1830        {
1831            result.setToNull();
1832            return result;
1833        }
1834
1835        String JavaDoc mySearchFrom = searchFrom.getString();
1836        String JavaDoc mySearchFor = this.getString();
1837
1838        /* the below 2 if conditions are to emulate DB2's behavior */
1839        if( startVal < 1 )
1840        {
1841            throw StandardException.newException(
1842                    SQLState.LANG_INVALID_PARAMETER_FOR_SEARCH_POSITION,
1843                    new String JavaDoc(getString()), new String JavaDoc(mySearchFrom),
1844                    new Integer JavaDoc(startVal));
1845        }
1846        
1847        if( mySearchFor.length() == 0 )
1848        {
1849            result.setValue( startVal );
1850            return result;
1851        }
1852
1853        result.setValue( mySearchFrom.indexOf(mySearchFor, startVal - 1) + 1);
1854        return result;
1855    }
1856
1857    /**
1858     * The SQL substr() function.
1859     *
1860     * @param start Start of substr
1861     * @param length Length of substr
1862     * @param result The result of a previous call to this method,
1863     * null if not called yet.
1864     * @param maxLen Maximum length of the result
1865     *
1866     * @return A ConcatableDataValue containing the result of the substr()
1867     *
1868     * @exception StandardException Thrown on error
1869     */

1870    public ConcatableDataValue substring(
1871                NumberDataValue start,
1872                NumberDataValue length,
1873                ConcatableDataValue result,
1874                int maxLen)
1875        throws StandardException
1876    {
1877        int startInt;
1878        int lengthInt;
1879        StringDataValue stringResult;
1880
1881        if (result == null)
1882        {
1883            result = getNewVarchar();
1884        }
1885
1886        stringResult = (StringDataValue) result;
1887
1888        /* The result is null if the receiver (this) is null or if the length is negative.
1889         * We will return null, which is the only sensible thing to do.
1890         * (If the user did not specify a length then length is not a user null.)
1891         */

1892        if (this.isNull() || start.isNull() || (length != null && length.isNull()))
1893        {
1894            stringResult.setToNull();
1895            return stringResult;
1896        }
1897
1898        startInt = start.getInt();
1899
1900        // If length is not specified, make it till end of the string
1901
if (length != null)
1902        {
1903            lengthInt = length.getInt();
1904        }
1905        else lengthInt = maxLen - startInt + 1;
1906
1907        /* DB2 Compatibility: Added these checks to match DB2. We currently enforce these
1908         * limits in both modes. We could do these checks in DB2 mode only, if needed, so
1909         * leaving earlier code for out of range in for now, though will not be exercised
1910         */

1911        if ((startInt <= 0 || lengthInt < 0 || startInt > maxLen ||
1912                lengthInt > maxLen - startInt + 1))
1913            throw StandardException.newException(SQLState.LANG_SUBSTR_START_OR_LEN_OUT_OF_RANGE);
1914            
1915        // Return null if length is non-positive
1916
if (lengthInt < 0)
1917        {
1918            stringResult.setToNull();
1919            return stringResult;
1920        }
1921
1922        /* If startInt < 0 then we count from the right of the string */
1923        if (startInt < 0)
1924        {
1925            // Return '' if window is to left of string.
1926
if (startInt + getLength() < 0 &&
1927                (startInt + getLength() + lengthInt <= 0))
1928            {
1929                stringResult.setValue("");
1930                return stringResult;
1931            }
1932
1933            // Convert startInt to positive to get substring from right
1934
startInt += getLength();
1935
1936            while (startInt < 0)
1937            {
1938                startInt++;
1939                lengthInt--;
1940            }
1941        }
1942        else if (startInt > 0)
1943        {
1944            /* java substring() is 0 based */
1945            startInt--;
1946        }
1947
1948        /* Oracle docs don't say what happens if the window is to the
1949         * left of the string. Return "" if the window
1950         * is to the left or right.
1951         */

1952        if (lengthInt == 0 ||
1953            lengthInt <= 0 - startInt ||
1954            startInt > getLength())
1955        {
1956            stringResult.setValue("");
1957            return stringResult;
1958        }
1959
1960        if (lengthInt >= getLength() - startInt)
1961        {
1962            stringResult.setValue(getString().substring(startInt));
1963        }
1964        else
1965        {
1966            stringResult.setValue(getString().substring(startInt, startInt + lengthInt));
1967        }
1968
1969        return stringResult;
1970    }
1971
1972    /**
1973     * The SQL trim(), ltrim() and rtrim() functions.
1974     *
1975     * @param trimType Type of trim
1976     * @param result The result of a previous call to this method,
1977     * null if not called yet.
1978     *
1979     * @return A StringDataValue containing the result of the trim()
1980     *
1981     * @exception StandardException Thrown on error
1982     */

1983    public StringDataValue trim(
1984                int trimType,
1985                StringDataValue result)
1986        throws StandardException
1987    {
1988
1989        if (result == null)
1990        {
1991            result = getNewVarchar();
1992        }
1993
1994        /* The result is null if any of the parameters is a user null */
1995        if (this.isNull())
1996        {
1997            result.setToNull();
1998            return result;
1999        }
2000
2001        char[] trimChars = {' '};
2002        String JavaDoc tmpValue = getString();
2003
2004        // Trim leading characters if appropriate
2005
if (trimType == LEADING)
2006        {
2007            int start = 0;
2008            // Find the 1st character which doesn't get trimmed
2009
for ( ; start < tmpValue.length(); start++)
2010            {
2011                boolean found = false;
2012                for (int index = 0; index < trimChars.length; index++)
2013                {
2014                    if (tmpValue.charAt(start) == trimChars[index])
2015                    {
2016                        found = true;
2017                        break;
2018                    }
2019                }
2020
2021                if (! found)
2022                {
2023                    break;
2024                }
2025            }
2026
2027            // Trim if appropriate
2028
if (start == tmpValue.length())
2029            {
2030                tmpValue = "";
2031            }
2032            else if (start > 0)
2033            {
2034                tmpValue = tmpValue.substring(start);
2035            }
2036        }
2037
2038        // Trim trailing characters if appropriate
2039
if (trimType == TRAILING)
2040        {
2041            int start = tmpValue.length();
2042            // Find the 1st character which doesn't get trimmed
2043
for ( ; start > 0; start--)
2044            {
2045                boolean found = false;
2046                for (int index = 0; index < trimChars.length; index++)
2047                {
2048                    if (tmpValue.charAt(start - 1) == trimChars[index])
2049                    {
2050                        found = true;
2051                        break;
2052                    }
2053                }
2054
2055                if (! found)
2056                {
2057                    break;
2058                }
2059            }
2060
2061            // Trim if appropriate
2062
if (start == 0)
2063            {
2064                tmpValue = "";
2065            }
2066            else if (start < tmpValue.length())
2067            {
2068                tmpValue = tmpValue.substring(0, start);
2069            }
2070        }
2071        
2072        result.setValue(tmpValue);
2073        return result;
2074    }
2075
2076    /** @see StringDataValue#upper
2077     *
2078     * @exception StandardException Thrown on error
2079     */

2080    public StringDataValue upper(StringDataValue result)
2081                            throws StandardException
2082    {
2083        if (result == null)
2084        {
2085            result = (StringDataValue) getNewNull();
2086        }
2087
2088        if (this.isNull())
2089        {
2090            result.setToNull();
2091            return result;
2092        }
2093        
2094        String JavaDoc upper = getString();
2095        upper = upper.toUpperCase(getLocale());
2096        result.setValue(upper);
2097        return result;
2098    }
2099
2100    /** @see StringDataValue#lower
2101     *
2102     * @exception StandardException Thrown on error
2103     */

2104    public StringDataValue lower(StringDataValue result)
2105                            throws StandardException
2106    {
2107        if (result == null)
2108        {
2109            result = (StringDataValue) getNewNull();
2110        }
2111
2112        if (this.isNull())
2113        {
2114            result.setToNull();
2115            return result;
2116        }
2117
2118        
2119        String JavaDoc lower = getString();
2120        lower = lower.toLowerCase(getLocale());
2121        result.setValue(lower);
2122        return result;
2123    }
2124
2125    /*
2126     * DataValueDescriptor interface
2127     */

2128
2129    /** @see DataValueDescriptor#typePrecedence */
2130    public int typePrecedence()
2131    {
2132        return TypeId.CHAR_PRECEDENCE;
2133    }
2134
2135    /**
2136     * Compare two Strings using standard SQL semantics.
2137     *
2138     * @param op1 The first String
2139     * @param op2 The second String
2140     *
2141     * @return -1 - op1 < op2
2142     * 0 - op1 == op2
2143     * 1 - op1 > op2
2144     */

2145    protected static int stringCompare(String JavaDoc op1, String JavaDoc op2)
2146    {
2147        int posn;
2148        char leftchar;
2149        char rightchar;
2150        int leftlen;
2151        int rightlen;
2152        int retvalIfLTSpace;
2153        String JavaDoc remainingString;
2154        int remainingLen;
2155
2156        /*
2157        ** By convention, nulls sort High, and null == null
2158        */

2159        if (op1 == null || op2 == null)
2160        {
2161            if (op1 != null) // op2 == null
2162
return -1;
2163            if (op2 != null) // op1 == null
2164
return 1;
2165            return 0; // both null
2166
}
2167        /*
2168        ** Compare characters until we find one that isn't equal, or until
2169        ** one String or the other runs out of characters.
2170        */

2171
2172        leftlen = op1.length();
2173        rightlen = op2.length();
2174
2175        int shorterLen = leftlen < rightlen ? leftlen : rightlen;
2176
2177        for (posn = 0; posn < shorterLen; posn++)
2178        {
2179            leftchar = op1.charAt(posn);
2180            rightchar = op2.charAt(posn);
2181            if (leftchar != rightchar)
2182            {
2183                if (leftchar < rightchar)
2184                    return -1;
2185                else
2186                    return 1;
2187            }
2188        }
2189
2190        /*
2191        ** All the characters are equal up to the length of the shorter
2192        ** string. If the two strings are of equal length, the values are
2193        ** equal.
2194        */

2195        if (leftlen == rightlen)
2196            return 0;
2197
2198        /*
2199        ** One string is shorter than the other. Compare the remaining
2200        ** characters in the longer string to spaces (the SQL standard says
2201        ** that in this case the comparison is as if the shorter string is
2202        ** padded with blanks to the length of the longer string.
2203        */

2204        if (leftlen > rightlen)
2205        {
2206            /*
2207            ** Remaining characters are on the left.
2208            */

2209
2210            /* If a remaining character is less than a space, return -1 (op1 < op2) */
2211            retvalIfLTSpace = -1;
2212            remainingString = op1;
2213            posn = rightlen;
2214            remainingLen = leftlen;
2215        }
2216        else
2217        {
2218            /*
2219            ** Remaining characters are on the right.
2220            */

2221
2222            /* If a remaining character is less than a space, return 1 (op1 > op2) */
2223            retvalIfLTSpace = 1;
2224            remainingString = op2;
2225            posn = leftlen;
2226            remainingLen = rightlen;
2227        }
2228
2229        /* Look at the remaining characters in the longer string */
2230        for ( ; posn < remainingLen; posn++)
2231        {
2232            char remainingChar;
2233
2234            /*
2235            ** Compare the characters to spaces, and return the appropriate
2236            ** value, depending on which is the longer string.
2237            */

2238
2239            remainingChar = remainingString.charAt(posn);
2240
2241            if (remainingChar < ' ')
2242                return retvalIfLTSpace;
2243            else if (remainingChar > ' ')
2244                return -retvalIfLTSpace;
2245        }
2246
2247        /* The remaining characters in the longer string were all spaces,
2248        ** so the strings are equal.
2249        */

2250        return 0;
2251    }
2252
2253    /**
2254     * Compare two SQLChars. This method will be overriden in the
2255     * National char wrappers so that the appropriate comparison
2256     * is done.
2257     *
2258     * @exception StandardException Thrown on error
2259     */

2260     protected int stringCompare(SQLChar char1, SQLChar char2)
2261         throws StandardException
2262     {
2263         return stringCompare(char1.getCharArray(), char1.getLength(),
2264                              char2.getCharArray(), char2.getLength());
2265     }
2266
2267    /**
2268     * Compare two Strings using standard SQL semantics.
2269     *
2270     * @param op1 The first String
2271     * @param op2 The second String
2272     *
2273     * @return -1 - op1 < op2
2274     * 0 - op1 == op2
2275     * 1 - op1 > op2
2276     */

2277    protected static int stringCompare(char[] op1, int leftlen, char[] op2, int rightlen)
2278    {
2279        int posn;
2280        char leftchar;
2281        char rightchar;
2282        int retvalIfLTSpace;
2283        char[] remainingString;
2284        int remainingLen;
2285
2286        /*
2287        ** By convention, nulls sort High, and null == null
2288        */

2289        if (op1 == null || op2 == null)
2290        {
2291            if (op1 != null) // op2 == null
2292
return -1;
2293            if (op2 != null) // op1 == null
2294
return 1;
2295            return 0; // both null
2296
}
2297        /*
2298        ** Compare characters until we find one that isn't equal, or until
2299        ** one String or the other runs out of characters.
2300        */

2301        int shorterLen = leftlen < rightlen ? leftlen : rightlen;
2302        for (posn = 0; posn < shorterLen; posn++)
2303        {
2304            leftchar = op1[posn];
2305            rightchar = op2[posn];
2306            if (leftchar != rightchar)
2307            {
2308                if (leftchar < rightchar)
2309                    return -1;
2310                else
2311                    return 1;
2312            }
2313        }
2314
2315        /*
2316        ** All the characters are equal up to the length of the shorter
2317        ** string. If the two strings are of equal length, the values are
2318        ** equal.
2319        */

2320        if (leftlen == rightlen)
2321            return 0;
2322
2323        /*
2324        ** One string is shorter than the other. Compare the remaining
2325        ** characters in the longer string to spaces (the SQL standard says
2326        ** that in this case the comparison is as if the shorter string is
2327        ** padded with blanks to the length of the longer string.
2328        */

2329        if (leftlen > rightlen)
2330        {
2331            /*
2332            ** Remaining characters are on the left.
2333            */

2334
2335            /* If a remaining character is less than a space, return -1 (op1 < op2) */
2336            retvalIfLTSpace = -1;
2337            remainingString = op1;
2338            posn = rightlen;
2339            remainingLen = leftlen;
2340        }
2341        else
2342        {
2343            /*
2344            ** Remaining characters are on the right.
2345            */

2346
2347            /* If a remaining character is less than a space, return 1 (op1 > op2) */
2348            retvalIfLTSpace = 1;
2349            remainingString = op2;
2350            posn = leftlen;
2351            remainingLen = rightlen;
2352        }
2353
2354        /* Look at the remaining characters in the longer string */
2355        for ( ; posn < remainingLen; posn++)
2356        {
2357            char remainingChar;
2358
2359            /*
2360            ** Compare the characters to spaces, and return the appropriate
2361            ** value, depending on which is the longer string.
2362            */

2363
2364            remainingChar = remainingString[posn];
2365
2366            if (remainingChar < ' ')
2367                return retvalIfLTSpace;
2368            else if (remainingChar > ' ')
2369                return -retvalIfLTSpace;
2370        }
2371
2372        /* The remaining characters in the longer string were all spaces,
2373        ** so the strings are equal.
2374        */

2375        return 0;
2376    }
2377
2378
2379    /**
2380     * Compare a localized string with this one.
2381     *
2382     * @param str2 The other string
2383     *
2384     * @return -1 - this < str2
2385     * 0 - this == str2
2386     * 1 - this > str2
2387     */

2388    protected int stringCollatorCompare(SQLChar str2)
2389        throws StandardException
2390    {
2391        CollationKey JavaDoc ckey1 = this.getCollationKey();
2392        CollationKey JavaDoc ckey2 = str2.getCollationKey();
2393
2394        
2395        /*
2396        ** By convention, nulls sort High, and null == null
2397        */

2398        if (ckey1 == null || ckey2 == null)
2399        {
2400            if (ckey1 != null) // str2 == null
2401
return -1;
2402            if (ckey2 != null) // this == null
2403
return 1;
2404            return 0; // both == null
2405
}
2406
2407        return ckey1.compareTo(ckey2);
2408    }
2409        
2410    protected CollationKey JavaDoc getCollationKey() throws StandardException
2411    {
2412        char tmpCharArray[];
2413
2414        if (cKey != null)
2415            return cKey;
2416
2417        if (rawLength == -1)
2418        {
2419            /* materialize the string if input is a stream */
2420            tmpCharArray = getCharArray();
2421            if (tmpCharArray == null)
2422                return null;
2423        }
2424        
2425        int lastNonspaceChar = rawLength;
2426
2427        while (lastNonspaceChar > 0 &&
2428               rawData[lastNonspaceChar - 1] == '\u0020')
2429            lastNonspaceChar--; // count off the trailing spaces.
2430

2431        RuleBasedCollator JavaDoc rbc = getLocaleFinder().getCollator();
2432        cKey = rbc.getCollationKey(new String JavaDoc(rawData, 0, lastNonspaceChar));
2433
2434        return cKey;
2435    }
2436
2437    /*
2438     * String display of value
2439     */

2440
2441    public String JavaDoc toString()
2442    {
2443        if (isNull()) {
2444            return "NULL";
2445        }
2446
2447        if ((value == null) && (rawLength != -1)) {
2448
2449            return new String JavaDoc(rawData, 0, rawLength);
2450        }
2451
2452        if (stream != null) {
2453            try {
2454                return getString();
2455            } catch (Exception JavaDoc e) {
2456                return e.toString();
2457            }
2458        }
2459
2460        return value;
2461    }
2462
2463    /*
2464     * Hash code
2465     */

2466    public int hashCode()
2467    {
2468        try {
2469            if (getString() == null)
2470            {
2471                return 0;
2472            }
2473        }
2474        catch (StandardException se)
2475        {
2476            if (SanityManager.DEBUG)
2477                SanityManager.THROWASSERT("Unexpected exception " + se);
2478            return 0;
2479        }
2480
2481
2482        /* value.hashCode() doesn't work because of the SQL blank padding behavior
2483         * We want the hash code to be based on the value after the
2484         * trailing blanks have been trimmed. Calling trim() is too expensive
2485         * since it will create a new object, so here's what we do:
2486         * o Walk from the right until we've found the 1st
2487         * non-blank character.
2488         * o Add up the characters from that character to the 1st in
2489         * the string and return that as the hash code.
2490         */

2491        int index;
2492        int hashcode = 0;
2493
2494        // value will have been set by the getString() above
2495
String JavaDoc lvalue = value;
2496
2497        // Find 1st non-blank from the right
2498
for (index = lvalue.length() - 1;
2499             index >= 0 && lvalue.charAt(index) == ' ';
2500             index--)
2501        {
2502            ;
2503        }
2504
2505        // Build the hash code
2506
for ( ; index >= 0; index--)
2507        {
2508            hashcode += lvalue.charAt(index);
2509        }
2510
2511        return hashcode;
2512    }
2513
2514    /**
2515     * Implementation of hashCode() for the national character types,
2516     * put here to make it accessible to all the national types.
2517     */

2518    protected int nationalHashCode()
2519    {
2520        CollationKey JavaDoc tmpCKey = null;
2521
2522        try
2523        {
2524            tmpCKey = getCollationKey();
2525        }
2526        catch (StandardException se)
2527        {
2528            if (SanityManager.DEBUG)
2529            {
2530                SanityManager.THROWASSERT("Unexpected exception " + se);
2531            }
2532        }
2533
2534        if (tmpCKey == null)
2535            return 0;
2536        return tmpCKey.hashCode();
2537    }
2538
2539    private int[] getIntArray()
2540        throws StandardException
2541    {
2542        if (isNull())
2543        {
2544            return (int[]) null;
2545        }
2546
2547        if (intArray != null)
2548        {
2549            return intArray;
2550        }
2551
2552        // intLength should always be 0 when intArray is null
2553
if (SanityManager.DEBUG)
2554        {
2555            if (intLength != 0)
2556            {
2557                SanityManager.THROWASSERT(
2558                    "intLength expected to be 0, not " + intLength);
2559            }
2560        }
2561
2562        intArray = new int[getLength()];
2563
2564        RuleBasedCollator JavaDoc rbc = getLocaleFinder().getCollator();
2565        CollationElementIterator JavaDoc cei = rbc.getCollationElementIterator(getString());
2566        int nextInt;
2567        while ((nextInt = cei.next()) != CollationElementIterator.NULLORDER)
2568        {
2569            /* Believe it or not, a String might have more
2570             * collation elements than characters.
2571             * So, we handle that case by increasing the int array
2572             * by 5 and copying array elements.
2573             */

2574            if (intLength == intArray.length)
2575            {
2576                int[] tempArray = intArray;
2577                intArray = new int[intLength + 5];
2578                for (int index = 0; index < tempArray.length; index++)
2579                {
2580                    intArray[index] = tempArray[index];
2581                }
2582            }
2583            intArray[intLength++] = nextInt;
2584        }
2585
2586        return intArray;
2587    }
2588
2589    private int getIntLength()
2590    {
2591        return intLength;
2592    }
2593
2594    /**
2595     * Get a SQLVarchar for a built-in string function.
2596     * (Could be either a SQLVarchar or SQLNationalVarchar.)
2597     *
2598     * @return a SQLVarchar or SQLNationalVarchar.
2599     *
2600     * @exception StandardException Thrown on error
2601     */

2602    protected StringDataValue getNewVarchar() throws StandardException
2603    {
2604        return new SQLVarchar();
2605    }
2606
2607    /**
2608     * Return whether or not this is a national character datatype.
2609     */

2610    protected boolean isNationalString()
2611    {
2612        return false;
2613    }
2614
2615    /**
2616     * This implements getDate() for the national types. It lives
2617     * here so it can be shared between all the national types.
2618     *
2619     * @exception StandardException thrown on failure to convert
2620     */

2621    protected Date nationalGetDate( Calendar JavaDoc cal) throws StandardException
2622    {
2623        if (isNull())
2624            return null;
2625        SQLDate internalDate = new SQLDate( getString(), false, getLocaleFinder(), cal);
2626        return internalDate.getDate( cal);
2627    }
2628
2629    /**
2630     * This implements getTime() for the national types. It lives
2631     * here so it can be shared between all the national types.
2632     *
2633     * @exception StandardException thrown on failure to convert
2634     */

2635    protected Time nationalGetTime( Calendar JavaDoc cal) throws StandardException
2636    {
2637        if (isNull())
2638            return null;
2639        SQLTime internalTime = new SQLTime( getString(), false, getLocaleFinder(), cal);
2640        return internalTime.getTime( cal);
2641    }
2642
2643    /**
2644     * This implements getTimestamp() for the national types. It lives
2645     * here so it can be shared between all the national types.
2646     *
2647     * @exception StandardException thrown on failure to convert
2648     */

2649    protected Timestamp nationalGetTimestamp( Calendar JavaDoc cal) throws StandardException
2650    {
2651        // DB2 does not support internationalized timestamps
2652
return getTimestamp( cal, getString(), getLocaleFinder());
2653    }
2654
2655    protected void setLocaleFinder(LocaleFinder localeFinder)
2656    {
2657        this.localeFinder = localeFinder;
2658    }
2659
2660    /** @exception StandardException Thrown on error */
2661    private Locale JavaDoc getLocale() throws StandardException
2662    {
2663        return getLocaleFinder().getCurrentLocale();
2664    }
2665
2666    protected LocaleFinder getLocaleFinder()
2667    {
2668        // This is not very satisfactory, as it creates a dependency on
2669
// the DatabaseContext. It's the best I could do on short notice,
2670
// though. - Jeff
2671
if (localeFinder == null)
2672        {
2673            DatabaseContext dc = (DatabaseContext) ContextService.getContext(DatabaseContext.CONTEXT_ID);
2674            if( dc != null)
2675                localeFinder = dc.getDatabase();
2676        }
2677
2678        return localeFinder;
2679    }
2680
2681    protected DateFormat JavaDoc getDateFormat() throws StandardException {
2682        return getLocaleFinder().getDateFormat();
2683    }
2684    protected DateFormat JavaDoc getTimeFormat() throws StandardException {
2685        return getLocaleFinder().getTimeFormat();
2686    }
2687    protected DateFormat JavaDoc getTimestampFormat() throws StandardException {
2688        return getLocaleFinder().getTimestampFormat();
2689    }
2690
2691    protected DateFormat JavaDoc getDateFormat( Calendar JavaDoc cal) throws StandardException {
2692        return setDateFormatCalendar( getLocaleFinder().getDateFormat(), cal);
2693    }
2694    protected DateFormat JavaDoc getTimeFormat( Calendar JavaDoc cal) throws StandardException {
2695        return setDateFormatCalendar( getLocaleFinder().getTimeFormat(), cal);
2696    }
2697    protected DateFormat JavaDoc getTimestampFormat( Calendar JavaDoc cal) throws StandardException {
2698        return setDateFormatCalendar( getLocaleFinder().getTimestampFormat(), cal);
2699    }
2700
2701    private DateFormat JavaDoc setDateFormatCalendar( DateFormat JavaDoc df, Calendar JavaDoc cal)
2702    {
2703        if( cal != null && df.getTimeZone() != cal.getTimeZone())
2704        {
2705            // The DateFormat returned by getDateFormat may be cached and used by other threads.
2706
// Therefore we cannot change its calendar.
2707
df = (DateFormat JavaDoc) df.clone();
2708            df.setCalendar( cal);
2709        }
2710        return df;
2711    }
2712
2713    /*
2714     * object state
2715     */

2716
2717    // Don't use value directly in most situations. Use getString()
2718
// OR use the rawData array if rawLength != -1.
2719
private String JavaDoc value;
2720
2721    // rawData holds the reusable array for reading in
2722
// SQLChars. It contains a valid value if rawLength
2723
// is greater than or equal to 0. See getString() to see how it is
2724
// converted to a String. Even when converted to a String
2725
// object the rawData array remains for potential future
2726
// use, unless rawLength is > 4096. In this case the
2727
// rawData is set to null to avoid huge memory use.
2728
private char[] rawData;
2729    private int rawLength = -1;
2730
2731    // For null strings, cKey = null.
2732
private CollationKey JavaDoc cKey;
2733
2734    /**
2735     * The value as a stream in the on-disk format.
2736     */

2737    InputStream stream;
2738    
2739    /* Comparison info for National subclasses) */
2740    private int[] intArray;
2741    private int intLength;
2742
2743    /* Locale info (for International support) */
2744    private LocaleFinder localeFinder;
2745
2746    private static final int BASE_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( SQLChar.class);
2747
2748    public int estimateMemoryUsage()
2749    {
2750        int sz = BASE_MEMORY_USAGE + ClassSize.estimateMemoryUsage( value);
2751        if( null != rawData)
2752            sz += 2*rawData.length;
2753        // Assume that cKey, stream, and localFinder are shared, so do not count their memory usage
2754
if( null != intArray)
2755            sz += intArray.length*ClassSize.getIntSize();
2756        return sz;
2757    } // end of estimateMemoryUsage
2758

2759    protected void copyState(SQLChar other) {
2760
2761        this.value = other.value;
2762        this.rawData = other.rawData;
2763        this.rawLength = other.rawLength;
2764        this.cKey = other.cKey;
2765        this.stream = other.stream;
2766        this.intArray = intArray;
2767        this.intLength = intLength;
2768        this.localeFinder = localeFinder;
2769    }
2770
2771}
2772
Popular Tags