You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by km...@apache.org on 2008/09/04 17:48:26 UTC
svn commit: r692118 [2/3] - in /db/derby/code/branches/10.3/java:
engine/org/apache/derby/iapi/types/
testing/org/apache/derbyTesting/functionTests/tests/memory/
Modified: db/derby/code/branches/10.3/java/engine/org/apache/derby/iapi/types/SQLChar.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/engine/org/apache/derby/iapi/types/SQLChar.java?rev=692118&r1=692117&r2=692118&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/engine/org/apache/derby/iapi/types/SQLChar.java (original)
+++ db/derby/code/branches/10.3/java/engine/org/apache/derby/iapi/types/SQLChar.java Thu Sep 4 08:48:25 2008
@@ -44,6 +44,7 @@
import org.apache.derby.iapi.services.cache.ClassSize;
import org.apache.derby.iapi.services.io.ArrayInputStream;
import org.apache.derby.iapi.util.StringUtil;
+import org.apache.derby.iapi.util.UTF8Util;
import org.apache.derby.iapi.services.i18n.LocaleFinder;
import org.apache.derby.iapi.db.DatabaseContext;
@@ -72,2563 +73,2736 @@
import java.util.Locale;
import java.util.Calendar;
+
+
+
/**
- * SQLChar represents a CHAR value with UCS_BASIC collation.
- * SQLChar may be used directly by any code when it is guaranteed
- * that the required collation is UCS_BASIC, e.g. system columns.
- */
+
+The SQLChar represents a CHAR value with UCS_BASIC collation.
+SQLChar may be used directly by any code when it is guaranteed
+that the required collation is UCS_BASIC, e.g. system columns.
+<p>
+The state may be in char[], a String, or an unread stream, depending
+on how the datatype was created.
+<p>
+Stream notes:
+<p>
+When the datatype comes from the database layer and the length of the bytes
+necessary to store the datatype on disk exceeds the size of a page of the
+container holding the data then the store returns a stream rather than reading
+all the bytes into a char[] or String. The hope is that the usual usage case
+is that data never need be expanded in the derby layer, and that client can
+just be given a stream that can be read a char at a time through the jdbc
+layer. Even though SQLchar's can't ever be this big, this code is shared
+by all the various character datatypes including SQLClob which is expected
+to usually larger than a page.
+<p>
+The state can also be a stream in the case of insert/update where the client
+has used a jdbc interface to set the value as a stream rather than char[].
+In this case the hope is that the usual usage case is that stream never need
+be read until it is passed to store, read once, and inserted into the database.
+
+**/
+
public class SQLChar
- extends DataType implements StringDataValue, StreamStorable
+ extends DataType implements StringDataValue, StreamStorable
{
+ /**************************************************************************
+ * static fields of the class
+ **************************************************************************
+ */
/**
* threshold, that decides when we return space back to the VM
* see getString() where it is used
*/
protected final static int RETURN_SPACE_THRESHOLD = 4096;
-
+
/**
* when we know that the array needs to grow by at least
* one byte, it is not performant to grow by just one byte
* instead this amount is used to provide a reasonable growby size.
*/
private final static int GROWBY_FOR_CHAR = 64;
- /**
- Static array that can be used for blank padding.
- */
- private static final char[] BLANKS = new char[40];
- static {
- for (int i = 0; i < BLANKS.length; i++) {
- BLANKS[i] = ' ';
- }
- }
-
- private static void appendBlanks(char[] ca, int offset, int howMany) {
- while (howMany > 0) {
-
- int count = howMany > BLANKS.length ? BLANKS.length : howMany;
- System.arraycopy(BLANKS, 0, ca, offset, count);
- howMany -= count;
- offset += count;
- }
- }
- /*
- * DataValueDescriptor interface
- * (mostly implemented in DataType)
- * casts to the
- * numeric and date/time types as well, "for valid strings"
- */
-
- /**
- * @see DataValueDescriptor#getBoolean
- *
- * @exception StandardException Thrown on error
- */
- public boolean getBoolean()
- throws StandardException
- {
- if (isNull()) return false;
- // match JCC, match only "0" or "false" for false. No case insensitivity.
- // everything else is true.
+ private static final int BASE_MEMORY_USAGE =
+ ClassSize.estimateBaseFromCatalog( SQLChar.class);
- String cleanedValue = getString().trim();
+ /**
+ Static array that can be used for blank padding.
+ */
+ private static final char[] BLANKS = new char[40];
+ static {
+ for (int i = 0; i < BLANKS.length; i++) {
+ BLANKS[i] = ' ';
+ }
+ }
- return !(cleanedValue.equals("0") || cleanedValue.equals("false"));
- }
+ /**************************************************************************
+ * Fields of the class
+ **************************************************************************
+ */
- /**
- * @see DataValueDescriptor#getByte
- * @exception StandardException thrown on failure to convert
- */
- public byte getByte() throws StandardException
- {
- if (isNull()) return (byte)0;
- try {
- return Byte.parseByte(getString().trim());
- } catch (NumberFormatException nfe) {
- throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "byte");
- }
- }
+ /*
+ * object state
+ */
- /**
- * @see DataValueDescriptor#getShort
- * @exception StandardException thrown on failure to convert
- */
- public short getShort() throws StandardException
- {
- if (isNull()) return (short)0;
- try {
- return Short.parseShort(getString().trim());
- } catch (NumberFormatException nfe) {
- throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "short");
- }
- }
+ // Don't use value directly in most situations. Use getString()
+ // OR use the rawData array if rawLength != -1.
+ private String value;
+
+ // rawData holds the reusable array for reading in SQLChars. It contains a
+ // valid value if rawLength is greater than or equal to 0. See getString()
+ // to see how it is converted to a String. Even when converted to a String
+ // object the rawData array remains for potential future use, unless
+ // rawLength is > 4096. In this case the rawData is set to null to avoid
+ // huge memory use.
+ private char[] rawData;
+ private int rawLength = -1;
- /**
- * @see DataValueDescriptor#getInt
- * @exception StandardException thrown on failure to convert
- */
- public int getInt() throws StandardException
- {
- if (isNull()) return 0;
- try {
- return Integer.parseInt(getString().trim());
- } catch (NumberFormatException nfe) {
- throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "int");
- }
- }
+ // For null strings, cKey = null.
+ private CollationKey cKey;
- /**
- * @see DataValueDescriptor#getLong
- * @exception StandardException thrown on failure to convert
- */
- public long getLong() throws StandardException
- {
- if (isNull()) return 0;
- try {
- return Long.parseLong(getString().trim());
- } catch (NumberFormatException nfe) {
- throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "long");
- }
- }
+ /**
+ * The value as a stream in the on-disk format.
+ */
+ InputStream stream;
- /**
- * @see DataValueDescriptor#getFloat
- * @exception StandardException thrown on failure to convert
- */
- public float getFloat() throws StandardException
- {
- if (isNull()) return 0;
- try {
- return new Float(getString().trim()).floatValue();
- } catch (NumberFormatException nfe) {
- throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "float");
- }
- }
+ /* Locale info (for International support) */
+ private LocaleFinder localeFinder;
- /**
- * @see DataValueDescriptor#getDouble
- * @exception StandardException thrown on failure to convert
- */
- public double getDouble() throws StandardException
- {
- if (isNull()) return 0;
- try {
- return new Double(getString().trim()).doubleValue();
- } catch (NumberFormatException nfe) {
- throw StandardException.newException(SQLState.LANG_FORMAT_EXCEPTION, "double");
- }
- }
- /**
- * CHAR/VARCHAR/LONG VARCHAR implementation. Convert to a BigDecimal using getString.
- */
- public int typeToBigDecimal() throws StandardException
- {
- return java.sql.Types.CHAR;
- }
- /**
- * @see DataValueDescriptor#getDate
- * @exception StandardException thrown on failure to convert
- */
- public Date getDate( Calendar cal) throws StandardException
- {
- return getDate( cal, getString(), getLocaleFinder());
- }
+ /**************************************************************************
+ * Constructors for This class:
+ **************************************************************************
+ */
- public static Date getDate(java.util.Calendar cal, String str, LocaleFinder localeFinder) throws StandardException
+ /**
+ * no-arg constructor, required by Formattable.
+ **/
+ public SQLChar()
{
- if( str == null)
- return null;
- SQLDate internalDate = new SQLDate( str, false, localeFinder);
- return internalDate.getDate( cal);
}
- /**
- * @see DataValueDescriptor#getTime
- * @exception StandardException thrown on failure to convert
- */
- public Time getTime(Calendar cal) throws StandardException
- {
- return getTime( cal, getString(), getLocaleFinder());
- }
-
- /**
- * @exception StandardException thrown on failure to convert
- */
- public static Time getTime( Calendar cal, String str, LocaleFinder localeFinder) throws StandardException
- {
- if( str == null)
- return null;
- SQLTime internalTime = new SQLTime( str, false, localeFinder, cal);
- return internalTime.getTime( cal);
- }
-
- /**
- * @see DataValueDescriptor#getTimestamp
- * @exception StandardException thrown on failure to convert
- */
- public Timestamp getTimestamp( Calendar cal) throws StandardException
- {
- return getTimestamp( cal, getString(), getLocaleFinder());
- }
-
- /**
- * @see DataValueDescriptor#getTimestamp
- * @exception StandardException thrown on failure to convert
- */
- public static Timestamp getTimestamp(java.util.Calendar cal, String str, LocaleFinder localeFinder)
- throws StandardException
- {
- if( str == null)
- return null;
- SQLTimestamp internalTimestamp = new SQLTimestamp( str, false, localeFinder, cal);
- return internalTimestamp.getTimestamp( cal);
- }
-
- /**
- * @exception StandardException Thrown on error
- */
- public Object getObject() throws StandardException
- {
- return getString();
- }
+ public SQLChar(String val)
+ {
+ value = val;
+ }
- /**
- * @exception StandardException Thrown on error
- */
- public InputStream getStream() throws StandardException
- {
- return stream;
- }
+ /**************************************************************************
+ * Private/Protected methods of This class:
+ **************************************************************************
+ */
- /**
- * @exception StandardException Thrown on error
- */
- public int getLength() throws StandardException
- {
- if (rawLength != -1)
- return rawLength;
-
- String tmpString = getString();
- return (tmpString == null) ?
- 0 : tmpString.length();
- }
+ private static void appendBlanks(char[] ca, int offset, int howMany)
+ {
+ while (howMany > 0)
+ {
+ int count = howMany > BLANKS.length ? BLANKS.length : howMany;
- public String getTypeName()
- {
- return TypeId.CHAR_NAME;
- }
+ System.arraycopy(BLANKS, 0, ca, offset, count);
+ howMany -= count;
+ offset += count;
+ }
+ }
- /**
- * If possible, use getCharArray() if you don't really
- * need a string. getString() will cause an extra
- * char array to be allocated when it calls the the String()
- * constructor (the first time through), so may be
- * cheaper to use getCharArray().
- *
- * @exception StandardException Thrown on error
- */
- public String getString() throws StandardException
- {
- if (value == null) {
-
- int len = rawLength;
-
- if (len != -1) {
-
- // data is stored in the char[] array
-
- value = new String(rawData, 0, len);
- if (len > RETURN_SPACE_THRESHOLD) {
- // free up this char[] array to reduce memory usage
- rawData = null;
- rawLength = -1;
- cKey = null;
- }
-
- } else if (stream != null) {
-
- // data stored as a stream
- try {
-
- if (stream instanceof FormatIdInputStream) {
- readExternal((FormatIdInputStream) stream);
- } else {
- readExternal(new FormatIdInputStream(stream));
- }
- stream = null;
-
- // at this point the value is only in the char[]
- // so call again to convert to a String
- return getString();
+ /**************************************************************************
+ * Public Methods of This class:
+ **************************************************************************
+ */
- } catch (IOException ioe) {
+ /**************************************************************************
+ * Public Methods of DataValueDescriptor interface:
+ * Mostly implemented in Datatype.
+ **************************************************************************
+ */
- throw StandardException.newException(
- SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION,
- ioe,
- "java.sql.String");
- }
- }
- }
+ /**
+ * Get Boolean from a SQLChar.
+ *
+ * <p>
+ * Return false for only "0" or "false" for false. No case insensitivity.
+ * Everything else is true.
+ * <p>
+ * The above matches JCC.
+ *
+ *
+ * @see DataValueDescriptor#getBoolean
+ *
+ * @exception StandardException Thrown on error
+ **/
+ public boolean getBoolean()
+ throws StandardException
+ {
+ if (isNull())
+ return false;
- return value;
- }
+ // match JCC, match only "0" or "false" for false. No case
+ // insensitivity. everything else is true.
- /**
- * Get a char array. Typically, this is a simple
- * getter that is cheaper than getString() because
- * we always need to create a char array when
- * doing I/O. Use this instead of getString() where
- * reasonable.
- * <p>
- * <b>WARNING</b>: may return a character array that has spare
- * characters at the end. MUST be used in conjunction
- * with getLength() to be safe.
- *
- * @exception StandardException Thrown on error
- */
- public char[] getCharArray() throws StandardException
- {
- if (isNull())
- {
- return (char[])null;
- }
- else if (rawLength != -1)
- {
- return rawData;
- }
- else
- {
- // this is expensive -- we are getting a
- // copy of the char array that the
- // String wrapper uses.
- getString();
- rawData = value.toCharArray();
- rawLength = rawData.length;
- cKey = null;
- return rawData;
- }
- }
+ String cleanedValue = getString().trim();
- /*
- * StreamStorable interface :
- */
- public InputStream returnStream()
- {
- return stream;
- }
+ return !(cleanedValue.equals("0") || cleanedValue.equals("false"));
+ }
/**
- * Set this value to the on-disk format stream.
- */
- public final void setStream(InputStream newStream)
- {
- this.value = null;
- this.rawLength = -1;
- this.stream = newStream;
- cKey = null;
- }
+ * Get Byte from a SQLChar.
+ *
+ * <p>
+ * Uses java standard Byte.parseByte() to perform coercion.
+ *
+ * @see DataValueDescriptor#getByte
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public byte getByte() throws StandardException
+ {
+ if (isNull())
+ return (byte)0;
- public void loadStream() throws StandardException
- {
- getString();
- }
+ try
+ {
+ return Byte.parseByte(getString().trim());
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw StandardException.newException(
+ SQLState.LANG_FORMAT_EXCEPTION, "byte");
+ }
+ }
- /*
- * Storable interface, implies Externalizable, TypedFormat
- */
-
- /**
- Return my format identifier.
-
- @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
- */
- public int getTypeFormatId() {
- return StoredFormatIds.SQL_CHAR_ID;
- }
+ /**
+ * Get Short from a SQLChar.
+ *
+ * <p>
+ * Uses java standard Short.parseShort() to perform coercion.
+ *
+ * @see DataValueDescriptor#getShort
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public short getShort() throws StandardException
+ {
+ if (isNull())
+ return (short)0;
- /**
- * see if the String value is null.
- @see Storable#isNull
- */
- public boolean isNull()
- {
- return ((value == null) && (rawLength == -1) && (stream == null));
- }
+ try
+ {
+ return Short.parseShort(getString().trim());
- /**
- The maximum stored size is based upon the UTF format
- used to stored the String. The format consists of
- a two byte length field and a maximum number of three
- bytes for each character.
- <BR>
- This puts an upper limit on the length of a stored
- String. The maximum stored length is 65535, these leads to
- the worse case of a maximum string length of 21844 ((65535 - 2) / 3).
- <BR>
- Strings with stored length longer than 64K is handled with
- the following format:
- (1) 2 byte length: will be assigned 0.
- (2) UTF formated string data.
- (3) terminate the string with the following 3 bytes:
- first byte is:
- +---+---+---+---+---+---+---+---+
- | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
- +---+---+---+---+---+---+---+---+
- second byte is:
- +---+---+---+---+---+---+---+---+
- | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
- +---+---+---+---+---+---+---+---+
- third byte is:
- +---+---+---+---+---+---+---+---+
- | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
- +---+---+---+---+---+---+---+---+
-
-
- The UTF format:
- Writes a string to the underlying output stream using UTF-8
- encoding in a machine-independent manner.
- <p>
- First, two bytes are written to the output stream as if by the
- <code>writeShort</code> method giving the number of bytes to
- follow. This value is the number of bytes actually written out,
- not the length of the string. Following the length, each character
- of the string is output, in sequence, using the UTF-8 encoding
- for the character.
- @exception IOException if an I/O error occurs.
- @since JDK1.0
-
-
- @exception IOException thrown by writeUTF
-
- @see java.io.DataInputStream
-
- */
- public void writeExternal(ObjectOutput out) throws IOException
- {
- // never called when value is null
- if (SanityManager.DEBUG)
- SanityManager.ASSERT(!isNull());
-
- String lvalue = null;
- char[] data = null;
-
- int strlen = rawLength;
- boolean isRaw;
-
- if (strlen < 0) {
- lvalue = value;
- strlen = lvalue.length();
- isRaw = false;
- } else {
- data = rawData;
- isRaw = true;
- }
-
- // byte length will always be at least string length
- int utflen = strlen;
-
- for (int i = 0 ; (i < strlen) && (utflen <= 65535); i++)
- {
- int c = isRaw ? data[i] : lvalue.charAt(i);
- if ((c >= 0x0001) && (c <= 0x007F))
- {
- // 1 byte for character
- }
- else if (c > 0x07FF)
- {
- utflen += 2; // 3 bytes for character
- }
- else
- {
- utflen += 1; // 2 bytes for character
- }
- }
-
- boolean isLongUTF = false;
- // for length than 64K, see format description above
- if (utflen > 65535)
- {
- isLongUTF = true;
- utflen = 0;
- }
-
- out.write((utflen >>> 8) & 0xFF);
- out.write((utflen >>> 0) & 0xFF);
- for (int i = 0 ; i < strlen ; i++)
- {
- int c = isRaw ? data[i] : lvalue.charAt(i);
- if ((c >= 0x0001) && (c <= 0x007F))
- {
- out.write(c);
- }
- else if (c > 0x07FF)
- {
- out.write(0xE0 | ((c >> 12) & 0x0F));
- out.write(0x80 | ((c >> 6) & 0x3F));
- out.write(0x80 | ((c >> 0) & 0x3F));
- }
- else
- {
- out.write(0xC0 | ((c >> 6) & 0x1F));
- out.write(0x80 | ((c >> 0) & 0x3F));
- }
- }
-
- if (isLongUTF)
- {
- // write the following 3 bytes to terminate the string:
- // (11100000, 00000000, 00000000)
- out.write(0xE0);
- out.write(0);
- out.write(0);
- }
- }
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw StandardException.newException(
+ SQLState.LANG_FORMAT_EXCEPTION, "short");
+ }
+ }
/**
- * Reads in a string from the specified data input stream. The
- * string has been encoded using a modified UTF-8 format.
- * <p>
- * The first two bytes are read as if by
- * <code>readUnsignedShort</code>. This value gives the number of
- * following bytes that are in the encoded string, not
- * the length of the resulting string. The following bytes are then
- * interpreted as bytes encoding characters in the UTF-8 format
- * and are converted into characters.
+ * Get int from a SQLChar.
+ *
* <p>
- * This method blocks until all the bytes are read, the end of the
- * stream is detected, or an exception is thrown.
+ * Uses java standard Short.parseInt() to perform coercion.
*
- * @param in a data input stream.
- * @exception EOFException if the input stream reaches the end
- * before all the bytes.
- * @exception IOException if an I/O error occurs.
- * @exception UTFDataFormatException if the bytes do not represent a
- * valid UTF-8 encoding of a Unicode string.
- * @see java.io.DataInputStream#readUnsignedShort()
-
- * @see java.io.Externalizable#readExternal
- */
- public void readExternalFromArray(ArrayInputStream in)
- throws IOException
+ * @see DataValueDescriptor#getInt
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public int getInt() throws StandardException
{
- arg_passer[0] = rawData;
+ if (isNull())
+ return 0;
- rawLength = in.readDerbyUTF(arg_passer);
+ try
+ {
+ return Integer.parseInt(getString().trim());
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw StandardException.newException(
+ SQLState.LANG_FORMAT_EXCEPTION, "int");
+ }
+ }
- rawData = arg_passer[0];
+ /**
+ * Get long from a SQLChar.
+ *
+ * <p>
+ * Uses java standard Short.parseLong() to perform coercion.
+ *
+ * @see DataValueDescriptor#getLong
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public long getLong() throws StandardException
+ {
+ if (isNull())
+ return 0;
- // restoreToNull();
- value = null;
- stream = null;
+ try
+ {
+ return Long.parseLong(getString().trim());
- cKey = null;
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw StandardException.newException(
+ SQLState.LANG_FORMAT_EXCEPTION, "long");
+ }
}
- char[][] arg_passer = new char[1][];
- public void readExternal(ObjectInput in) throws IOException
+ /**
+ * Get float from a SQLChar.
+ *
+ * <p>
+ * Uses java standard Float.floatValue() to perform coercion.
+ *
+ * @see DataValueDescriptor#getFloat
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public float getFloat() throws StandardException
{
- // if in.available() blocked at 0, use this default string size
-
- int utflen = in.readUnsignedShort();
+ if (isNull())
+ return 0;
- int requiredLength;
- // minimum amount that is reasonable to grow the array
- // when we know the array needs to growby at least one
- // byte but we dont want to grow by one byte as that
- // is not performant
- int minGrowBy = growBy();
- if (utflen != 0)
+ try
{
- // the object was not stored as a streaming column
- // we know exactly how long it is
- requiredLength = utflen;
- }
- else
+ return new Float(getString().trim()).floatValue();
+ }
+ catch (NumberFormatException nfe)
{
- // the object was stored as a streaming column
- // and we have a clue how much we can read unblocked
- // OR
- // The original string was a 0 length string.
- requiredLength = in.available();
- if (requiredLength < minGrowBy)
- requiredLength = minGrowBy;
- }
-
- char str[];
- if ((rawData == null) || (requiredLength > rawData.length)) {
-
- str = new char[requiredLength];
- } else {
- str = rawData;
+ throw StandardException.newException(
+ SQLState.LANG_FORMAT_EXCEPTION, "float");
}
- int arrayLength = str.length;
-
- // Set these to null to allow GC of the array if required.
- rawData = null;
- restoreToNull();
+ }
- int count = 0;
- int strlen = 0;
+ /**
+ * Get double from a SQLChar.
+ *
+ * <p>
+ * Uses java standard Double.doubleValue() to perform coercion.
+ *
+ * @see DataValueDescriptor#getDouble
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public double getDouble() throws StandardException
+ {
+ if (isNull())
+ return 0;
-readingLoop:
- while ( ((count < utflen) || (utflen == 0)))
+ try
{
- int c;
+ return new Double(getString().trim()).doubleValue();
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw StandardException.newException(
+ SQLState.LANG_FORMAT_EXCEPTION, "double");
+ }
+ }
- try {
+ /**
+ * Get date from a SQLChar.
+ *
+ * @see DataValueDescriptor#getDate
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public Date getDate(Calendar cal)
+ throws StandardException
+ {
+ return getDate(cal, getString(), getLocaleFinder());
+ }
- c = in.readUnsignedByte();
- } catch (EOFException eof) {
- if (utflen != 0)
- throw new EOFException();
+ /**
+ * Static function to Get date from a string.
+ *
+ * @see DataValueDescriptor#getDate
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public static Date getDate(
+ java.util.Calendar cal,
+ String str,
+ LocaleFinder localeFinder)
+ throws StandardException
+ {
+ if( str == null)
+ return null;
- // This is the case for a 0 length string.
- // OR the string was originally streamed in
- // which puts a 0 for utflen but no trailing
- // E0,0,0 markers.
- break readingLoop;
- }
+ SQLDate internalDate = new SQLDate(str, false, localeFinder);
- //if (c == -1) // read EOF
- //{
- // if (utflen != 0)
- // throw new EOFException();
+ return internalDate.getDate(cal);
+ }
- // break;
- //}
+ /**
+ * Get time from a SQLChar.
+ *
+ * @see DataValueDescriptor#getTime
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public Time getTime(Calendar cal) throws StandardException
+ {
+ return getTime( cal, getString(), getLocaleFinder());
+ }
- // change it to an unsigned byte
- //c &= 0xFF;
+ /**
+ * Static function to Get Time from a string.
+ *
+ * @see DataValueDescriptor#getTime
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public static Time getTime(
+ Calendar cal,
+ String str,
+ LocaleFinder localeFinder)
+ throws StandardException
+ {
+ if( str == null)
+ return null;
+ SQLTime internalTime = new SQLTime( str, false, localeFinder, cal);
+ return internalTime.getTime( cal);
+ }
- if (strlen >= arrayLength) // the char array needs to be grown
- {
- int growby = in.available();
- // We know that the array needs to be grown by at least one.
- // However, even if the input stream wants to block on every
- // byte, we don't want to grow by a byte at a time.
- // Note, for large data (clob > 32k), it is performant
- // to grow the array by atleast 4k rather than a small amount
- // Even better maybe to grow by 32k but then may be
- // a little excess(?) for small data.
- // hopefully in.available() will give a fair
- // estimate of how much data can be read to grow the
- // array by larger and necessary chunks.
- // This performance issue due to
- // the slow growth of this array was noticed since inserts
- // on clobs was taking a really long time as
- // the array here grew previously by 64 bytes each time
- // till stream was drained. (Derby-302)
- // for char, growby 64 seems reasonable, but for varchar
- // clob 4k or 32k is performant and hence
- // growBy() is override correctly to ensure this
- if (growby < minGrowBy)
- growby = minGrowBy;
-
- int newstrlength = arrayLength + growby;
- char oldstr[] = str;
- str = new char[newstrlength];
+ /**
+ * Get Timestamp from a SQLChar.
+ *
+ * @see DataValueDescriptor#getTimestamp
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public Timestamp getTimestamp( Calendar cal) throws StandardException
+ {
+ return getTimestamp( cal, getString(), getLocaleFinder());
+ }
- System.arraycopy(oldstr, 0, str, 0, arrayLength);
- arrayLength = newstrlength;
- }
+ /**
+ * Static function to Get Timestamp from a string.
+ *
+ * @see DataValueDescriptor#getTimestamp
+ *
+ * @exception StandardException thrown on failure to convert
+ **/
+ public static Timestamp getTimestamp(
+ java.util.Calendar cal,
+ String str,
+ LocaleFinder localeFinder)
+ throws StandardException
+ {
+ if( str == null)
+ return null;
- /// top fours bits of the first unsigned byte that maps to a
- // 1,2 or 3 byte character
- //
- // 0000xxxx - 0 - 1 byte char
- // 0001xxxx - 1 - 1 byte char
- // 0010xxxx - 2 - 1 byte char
- // 0011xxxx - 3 - 1 byte char
- // 0100xxxx - 4 - 1 byte char
- // 0101xxxx - 5 - 1 byte char
- // 0110xxxx - 6 - 1 byte char
- // 0111xxxx - 7 - 1 byte char
- // 1000xxxx - 8 - error
- // 1001xxxx - 9 - error
- // 1010xxxx - 10 - error
- // 1011xxxx - 11 - error
- // 1100xxxx - 12 - 2 byte char
- // 1101xxxx - 13 - 2 byte char
- // 1110xxxx - 14 - 3 byte char
- // 1111xxxx - 15 - error
+ SQLTimestamp internalTimestamp =
+ new SQLTimestamp( str, false, localeFinder, cal);
- int char2, char3;
- char actualChar;
- if ((c & 0x80) == 0x00)
- {
- // one byte character
- count++;
- actualChar = (char) c;
- }
- else if ((c & 0x60) == 0x40) // we know the top bit is set here
- {
- // two byte character
- count += 2;
- if (utflen != 0 && count > utflen)
- throw new UTFDataFormatException();
- char2 = in.readUnsignedByte();
- if ((char2 & 0xC0) != 0x80)
- throw new UTFDataFormatException();
- actualChar = (char)(((c & 0x1F) << 6) | (char2 & 0x3F));
- }
- else if ((c & 0x70) == 0x60) // we know the top bit is set here
- {
- // three byte character
- count += 3;
- if (utflen != 0 && count > utflen)
- throw new UTFDataFormatException();
- char2 = in.readUnsignedByte();
- char3 = in.readUnsignedByte();
- if ((c == 0xE0) && (char2 == 0) && (char3 == 0)
- && (utflen == 0))
- {
- // we reached the end of a long string,
- // that was terminated with
- // (11100000, 00000000, 00000000)
- break readingLoop;
- }
+ return internalTimestamp.getTimestamp( cal);
+ }
- if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
- throw new UTFDataFormatException();
-
-
- actualChar = (char)(((c & 0x0F) << 12) |
- ((char2 & 0x3F) << 6) |
- ((char3 & 0x3F) << 0));
- }
- else {
+ /**************************************************************************
+ * Public Methods of StreamStorable interface:
+ **************************************************************************
+ */
+ public InputStream returnStream()
+ {
+ return stream;
+ }
- throw new UTFDataFormatException();
- }
+ /**
+ * Set this value to the on-disk format stream.
+ */
+ public final void setStream(InputStream newStream)
+ {
+ this.value = null;
+ this.rawLength = -1;
+ this.stream = newStream;
+ cKey = null;
+ }
- str[strlen++] = actualChar;
- }
+ public void loadStream() throws StandardException
+ {
+ getString();
+ }
- rawData = str;
- rawLength = strlen;
-
- cKey = null;
+ /**
+ * @exception StandardException Thrown on error
+ */
+ public Object getObject() throws StandardException
+ {
+ return getString();
}
/**
- * returns the reasonable minimum amount by
- * which the array can grow . See readExternal.
- * when we know that the array needs to grow by at least
- * one byte, it is not performant to grow by just one byte
- * instead this amount is used to provide a resonable growby size.
- * @return minimum reasonable growby size
+ * @exception StandardException Thrown on error
*/
- protected int growBy()
+ public InputStream getStream() throws StandardException
{
- return GROWBY_FOR_CHAR; //seems reasonable for a char
+ return stream;
+ }
+ /**
+ * CHAR/VARCHAR/LONG VARCHAR implementation.
+ * Convert to a BigDecimal using getString.
+ */
+ public int typeToBigDecimal() throws StandardException
+ {
+ return java.sql.Types.CHAR;
+ }
+
+ /**
+ * @exception StandardException Thrown on error
+ */
+ public int getLength() throws StandardException {
+ if (rawLength != -1)
+ return rawLength;
+ if (stream != null) {
+ if (stream instanceof Resetable && stream instanceof ObjectInput) {
+ try {
+ int clobLength = 0;
+ // If we have the stream length encoded.
+ // just read that.
+ int utf8len = readCharacterLength((ObjectInput) stream);
+ if (utf8len != 0) {
+ clobLength = utf8len;
+ return clobLength;
+ }
+ // Otherwise we will have to read the whole stream.
+ int skippedCharSize = (int) UTF8Util.skipUntilEOF(stream);
+ clobLength = skippedCharSize;
+ return clobLength;
+ } catch (IOException ioe) {
+ throwStreamingIOException(ioe);
+ } finally {
+ try {
+ ((Resetable) stream).resetStream();
+ } catch (IOException ioe) {
+ throwStreamingIOException(ioe);
+ }
+ }
+ }
+ }
+ String tmpString = getString();
+ if (tmpString == null) {
+ return 0;
+ } else {
+ int clobLength = tmpString.length();
+ return clobLength;
+ }
}
- /**
- * @see Storable#restoreToNull
- *
- */
- public void restoreToNull()
- {
- value = null;
- stream = null;
- rawLength = -1;
- cKey = null;
- }
- /**
- @exception StandardException thrown on error
- */
- public boolean compare(int op,
- DataValueDescriptor other,
- boolean orderedNulls,
- boolean unknownRV)
- throws StandardException
- {
- if (!orderedNulls) // nulls are unordered
- {
- if (this.isNull() || ((DataValueDescriptor) other).isNull())
- return unknownRV;
- }
-
- /* When comparing String types to non-string types, we always
- * convert the string type to the non-string type.
- */
- if (! (other instanceof SQLChar))
- {
- return other.compare(flip(op), this, orderedNulls, unknownRV);
- }
+ private int readCharacterLength(ObjectInput in) throws IOException {
+ int utflen = in.readUnsignedShort();
+ return utflen;
+ }
- /* Do the comparison */
- return super.compare(op, other, orderedNulls, unknownRV);
+ private void throwStreamingIOException(IOException ioe) throws StandardException {
+ throw StandardException.
+ newException(SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION,
+ ioe, getTypeName());
}
- /**
- @exception StandardException thrown on error
- */
- public int compare(DataValueDescriptor other) throws StandardException
- {
- /* Use compare method from dominant type, negating result
- * to reflect flipping of sides.
- */
- if (typePrecedence() < other.typePrecedence())
- {
- return - (other.compare(this));
- }
+ public String getTypeName()
+ {
+ return TypeId.CHAR_NAME;
+ }
- // stringCompare deals with null as comparable and smallest
- return stringCompare(this, (SQLChar)other);
- }
+ /**
+ * If possible, use getCharArray() if you don't really
+ * need a string. getString() will cause an extra
+ * char array to be allocated when it calls the the String()
+ * constructor (the first time through), so may be
+ * cheaper to use getCharArray().
+ *
+ * @exception StandardException Thrown on error
+ */
+ public String getString() throws StandardException
+ {
+ if (value == null) {
- /*
- * CloneableObject interface
- */
-
- /** From CloneableObject
- * Shallow clone a StreamStorable without objectifying. This is used to avoid
- * unnecessary objectifying of a stream object. The only difference of this method
- * from getClone is this method does not objectify a stream. beetle 4896
- */
- public Object cloneObject()
- {
- if (stream == null)
- return getClone();
- SQLChar self = (SQLChar) getNewNull();
- self.copyState(this);
- return self;
- }
+ int len = rawLength;
- /*
- * DataValueDescriptor interface
- */
-
- /** @see DataValueDescriptor#getClone */
- public DataValueDescriptor getClone()
- {
- try
- {
- return new SQLChar(getString());
- }
- catch (StandardException se)
- {
- if (SanityManager.DEBUG)
- SanityManager.THROWASSERT("Unexpected exception", se);
- return null;
- }
- }
+ if (len != -1) {
- /**
- * @see DataValueDescriptor#getNewNull
- *
- */
- public DataValueDescriptor getNewNull()
- {
- return new SQLChar();
- }
+ // data is stored in the char[] array
- /** @see StringDataValue#getValue(RuleBasedCollator) */
- public StringDataValue getValue(RuleBasedCollator collatorForComparison)
- {
- if (collatorForComparison == null)
- {//null collatorForComparison means use UCS_BASIC for collation
- return this;
- } else {
- //non-null collatorForComparison means use collator sensitive
- //implementation of SQLChar
- CollatorSQLChar s = new CollatorSQLChar(collatorForComparison);
- s.copyState(this);
- return s;
- }
- }
+ value = new String(rawData, 0, len);
+ if (len > RETURN_SPACE_THRESHOLD) {
+ // free up this char[] array to reduce memory usage
+ rawData = null;
+ rawLength = -1;
+ cKey = null;
+ }
- /**
- * @see DataValueDescriptor#setValueFromResultSet
- *
- * @exception SQLException Thrown on error
- */
- public final void setValueFromResultSet(ResultSet resultSet, int colNumber,
- boolean isNullable)
- throws SQLException
- {
- setValue(resultSet.getString(colNumber));
- }
+ } else if (stream != null) {
- /**
- Set the value into a PreparedStatement.
- */
- public final void setInto(PreparedStatement ps, int position) throws SQLException, StandardException {
+ // data stored as a stream
+ try {
- ps.setString(position, getString());
- }
+ if (stream instanceof FormatIdInputStream) {
+ readExternal((FormatIdInputStream) stream);
+ } else {
+ readExternal(new FormatIdInputStream(stream));
+ }
+ stream = null;
+ // at this point the value is only in the char[]
+ // so call again to convert to a String
+ return getString();
- /*
- * class interface
- */
-
- /*
- * constructors
- */
-
- /**
- no-arg constructor, required by Formattable.
- */
- public SQLChar()
- {
- }
+ } catch (IOException ioe) {
- public SQLChar(String val)
- {
- value = val;
- }
+ throw StandardException.newException(
+ SQLState.LANG_STREAMING_COLUMN_I_O_EXCEPTION,
+ ioe,
+ "java.sql.String");
+ }
+ }
+ }
- public void setValue(String theValue)
- {
- stream = null;
- rawLength = -1;
- cKey = null;
+ return value;
+ }
- value = theValue;
- }
+ /**
+ * Get a char array. Typically, this is a simple
+ * getter that is cheaper than getString() because
+ * we always need to create a char array when
+ * doing I/O. Use this instead of getString() where
+ * reasonable.
+ * <p>
+ * <b>WARNING</b>: may return a character array that has spare
+ * characters at the end. MUST be used in conjunction
+ * with getLength() to be safe.
+ *
+ * @exception StandardException Thrown on error
+ */
+ public char[] getCharArray() throws StandardException
+ {
+ if (isNull())
+ {
+ return (char[])null;
+ }
+ else if (rawLength != -1)
+ {
+ return rawData;
+ }
+ else
+ {
+ // this is expensive -- we are getting a
+ // copy of the char array that the
+ // String wrapper uses.
+ getString();
+ rawData = value.toCharArray();
+ rawLength = rawData.length;
+ cKey = null;
+ return rawData;
+ }
+ }
- public void setValue(boolean theValue) throws StandardException
- {
- // match JCC.
- setValue(theValue ? "1" : "0");
- }
- public void setValue(int theValue) throws StandardException
- {
- setValue(Integer.toString(theValue));
- }
+ /*
+ * Storable interface, implies Externalizable, TypedFormat
+ */
- public void setValue(double theValue) throws StandardException
- {
- setValue(Double.toString(theValue));
- }
+ /**
+ Return my format identifier.
- public void setValue(float theValue) throws StandardException
- {
- setValue(Float.toString(theValue));
- }
+ @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
+ */
+ public int getTypeFormatId() {
+ return StoredFormatIds.SQL_CHAR_ID;
+ }
- public void setValue(short theValue) throws StandardException
- {
- setValue(Short.toString(theValue));
- }
+ /**
+ * see if the String value is null.
+ @see Storable#isNull
+ */
+ public boolean isNull()
+ {
+ return ((value == null) && (rawLength == -1) && (stream == null));
+ }
- public void setValue(long theValue) throws StandardException
- {
- setValue(Long.toString(theValue));
- }
+ /**
+ The maximum stored size is based upon the UTF format
+ used to stored the String. The format consists of
+ a two byte length field and a maximum number of three
+ bytes for each character.
+ <BR>
+ This puts an upper limit on the length of a stored
+ String. The maximum stored length is 65535, these leads to
+ the worse case of a maximum string length of 21844 ((65535 - 2) / 3).
+ <BR>
+ Strings with stored length longer than 64K is handled with
+ the following format:
+ (1) 2 byte length: will be assigned 0.
+ (2) UTF formated string data.
+ (3) terminate the string with the following 3 bytes:
+ first byte is:
+ +---+---+---+---+---+---+---+---+
+ | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
+ +---+---+---+---+---+---+---+---+
+ second byte is:
+ +---+---+---+---+---+---+---+---+
+ | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+ +---+---+---+---+---+---+---+---+
+ third byte is:
+ +---+---+---+---+---+---+---+---+
+ | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+ +---+---+---+---+---+---+---+---+
+
+
+ The UTF format:
+ Writes a string to the underlying output stream using UTF-8
+ encoding in a machine-independent manner.
+ <p>
+ First, two bytes are written to the output stream as if by the
+ <code>writeShort</code> method giving the number of bytes to
+ follow. This value is the number of bytes actually written out,
+ not the length of the string. Following the length, each character
+ of the string is output, in sequence, using the UTF-8 encoding
+ for the character.
+ @exception IOException if an I/O error occurs.
+ @since JDK1.0
- public void setValue(byte theValue) throws StandardException
- {
- setValue(Byte.toString(theValue));
- }
- public void setValue(byte[] theValue) throws StandardException
- {
- if (theValue == null)
- {
- restoreToNull();
- return;
- }
-
- /*
- ** We can't just do a new String(theValue)
- ** because that method assumes we are converting
- ** ASCII and it will take on char per byte.
- ** So we need to convert the byte array to a
- ** char array and go from there.
- **
- ** If we have an odd number of bytes pad out.
- */
- int mod = (theValue.length % 2);
- int len = (theValue.length/2) + mod;
- char[] carray = new char[len];
- int cindex = 0;
- int bindex = 0;
-
- /*
- ** If we have a left over byte, then get
- ** that now.
- */
- if (mod == 1)
- {
- carray[--len] = (char)(theValue[theValue.length - 1] << 8);
- }
-
- for (; cindex < len; bindex+=2, cindex++)
- {
- carray[cindex] = (char)((theValue[bindex] << 8) |
- (theValue[bindex+1] & 0x00ff));
- }
+ @exception IOException thrown by writeUTF
- setValue(new String(carray));
- }
+ @see java.io.DataInputStream
- /**
- Only to be called when an application through JDBC is setting a
- SQLChar to a java.math.BigDecimal.
- */
- public void setBigDecimal(Number bigDecimal) throws StandardException
- {
- if (bigDecimal == null)
- setToNull();
- else
- setValue(bigDecimal.toString());
- }
+ */
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ // never called when value is null
+ if (SanityManager.DEBUG)
+ SanityManager.ASSERT(!isNull());
+
+ String lvalue = null;
+ char[] data = null;
+
+ int strlen = rawLength;
+ boolean isRaw;
+
+ if (strlen < 0) {
+ lvalue = value;
+ strlen = lvalue.length();
+ isRaw = false;
+ } else {
+ data = rawData;
+ isRaw = true;
+ }
- /** @exception StandardException Thrown on error */
- public void setValue(Date theValue, Calendar cal) throws StandardException
- {
- String strValue = null;
- if( theValue != null)
+ // byte length will always be at least string length
+ int utflen = strlen;
+
+ for (int i = 0 ; (i < strlen) && (utflen <= 65535); i++)
{
- if( cal == null)
- strValue = theValue.toString();
+ int c = isRaw ? data[i] : lvalue.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F))
+ {
+ // 1 byte for character
+ }
+ else if (c > 0x07FF)
+ {
+ utflen += 2; // 3 bytes for character
+ }
else
{
- cal.setTime( theValue);
- StringBuffer sb = new StringBuffer();
- formatJDBCDate( cal, sb);
- strValue= sb.toString();
+ utflen += 1; // 2 bytes for character
}
}
- setValue( strValue);
- }
- /** @exception StandardException Thrown on error */
- public void setValue(Time theValue, Calendar cal) throws StandardException
- {
- String strValue = null;
- if( theValue != null)
+ boolean isLongUTF = false;
+ // for length than 64K, see format description above
+ if (utflen > 65535)
{
- if( cal == null)
- strValue = theValue.toString();
+ isLongUTF = true;
+ utflen = 0;
+ }
+
+ out.write((utflen >>> 8) & 0xFF);
+ out.write((utflen >>> 0) & 0xFF);
+ for (int i = 0 ; i < strlen ; i++)
+ {
+ int c = isRaw ? data[i] : lvalue.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F))
+ {
+ out.write(c);
+ }
+ else if (c > 0x07FF)
+ {
+ out.write(0xE0 | ((c >> 12) & 0x0F));
+ out.write(0x80 | ((c >> 6) & 0x3F));
+ out.write(0x80 | ((c >> 0) & 0x3F));
+ }
else
{
- cal.setTime( theValue);
- StringBuffer sb = new StringBuffer();
- formatJDBCTime( cal, sb);
- strValue= sb.toString();
+ out.write(0xC0 | ((c >> 6) & 0x1F));
+ out.write(0x80 | ((c >> 0) & 0x3F));
}
}
- setValue( strValue);
- }
- /** @exception StandardException Thrown on error */
- public void setValue(Timestamp theValue, Calendar cal) throws StandardException
- {
- String strValue = null;
- if( theValue != null)
+ if (isLongUTF)
{
- if( cal == null)
- strValue = theValue.toString();
- else
- {
- cal.setTime( theValue);
- StringBuffer sb = new StringBuffer();
- formatJDBCDate( cal, sb);
- sb.append( ' ');
- formatJDBCTime( cal, sb);
- int micros = (theValue.getNanos() + SQLTimestamp.FRACTION_TO_NANO/2)/SQLTimestamp.FRACTION_TO_NANO;
- if( micros > 0)
- {
- sb.append( '.');
- String microsStr = Integer.toString( micros);
- if( microsStr.length() > SQLTimestamp.MAX_FRACTION_DIGITS)
- sb.append( microsStr.substring( 0, SQLTimestamp.MAX_FRACTION_DIGITS));
- else
- {
- for( int i = microsStr.length(); i < SQLTimestamp.MAX_FRACTION_DIGITS ; i++)
- sb.append( '0');
- sb.append( microsStr);
- }
+ // write the following 3 bytes to terminate the string:
+ // (11100000, 00000000, 00000000)
+ out.write(0xE0);
+ out.write(0);
+ out.write(0);
+ }
+ }
+
+ /**
+ * Reads in a string from the specified data input stream. The
+ * string has been encoded using a modified UTF-8 format.
+ * <p>
+ * The first two bytes are read as if by
+ * <code>readUnsignedShort</code>. This value gives the number of
+ * following bytes that are in the encoded string, not
+ * the length of the resulting string. The following bytes are then
+ * interpreted as bytes encoding characters in the UTF-8 format
+ * and are converted into characters.
+ * <p>
+ * This method blocks until all the bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @param in a data input stream.
+ * @exception EOFException if the input stream reaches the end
+ * before all the bytes.
+ * @exception IOException if an I/O error occurs.
+ * @exception UTFDataFormatException if the bytes do not represent a
+ * valid UTF-8 encoding of a Unicode string.
+ * @see java.io.DataInputStream#readUnsignedShort()
+
+ * @see java.io.Externalizable#readExternal
+ */
+ public void readExternalFromArray(ArrayInputStream in)
+ throws IOException
+ {
+ arg_passer[0] = rawData;
+
+ rawLength = in.readDerbyUTF(arg_passer);
+
+ rawData = arg_passer[0];
+
+ // restoreToNull();
+ value = null;
+ stream = null;
+
+ cKey = null;
+ }
+ char[][] arg_passer = new char[1][];
+
+ public void readExternal(ObjectInput in) throws IOException
+ {
+ // if in.available() blocked at 0, use this default string size
+
+ int utflen = in.readUnsignedShort();
+
+ int requiredLength;
+ // minimum amount that is reasonable to grow the array
+ // when we know the array needs to growby at least one
+ // byte but we dont want to grow by one byte as that
+ // is not performant
+ int minGrowBy = growBy();
+ if (utflen != 0)
+ {
+ // the object was not stored as a streaming column
+ // we know exactly how long it is
+ requiredLength = utflen;
+ }
+ else
+ {
+ // the object was stored as a streaming column
+ // and we have a clue how much we can read unblocked
+ // OR
+ // The original string was a 0 length string.
+ requiredLength = in.available();
+ if (requiredLength < minGrowBy)
+ requiredLength = minGrowBy;
+ }
+
+ char str[];
+ if ((rawData == null) || (requiredLength > rawData.length)) {
+
+ str = new char[requiredLength];
+ } else {
+ str = rawData;
+ }
+ int arrayLength = str.length;
+
+ // Set these to null to allow GC of the array if required.
+ rawData = null;
+ restoreToNull();
+
+ int count = 0;
+ int strlen = 0;
+
+readingLoop:
+ while ( ((count < utflen) || (utflen == 0)))
+ {
+ int c;
+
+ try {
+
+ c = in.readUnsignedByte();
+ } catch (EOFException eof) {
+ if (utflen != 0)
+ throw new EOFException();
+
+ // This is the case for a 0 length string.
+ // OR the string was originally streamed in
+ // which puts a 0 for utflen but no trailing
+ // E0,0,0 markers.
+ break readingLoop;
+ }
+
+ //if (c == -1) // read EOF
+ //{
+ // if (utflen != 0)
+ // throw new EOFException();
+
+ // break;
+ //}
+
+ // change it to an unsigned byte
+ //c &= 0xFF;
+
+ if (strlen >= arrayLength) // the char array needs to be grown
+ {
+ int growby = in.available();
+ // We know that the array needs to be grown by at least one.
+ // However, even if the input stream wants to block on every
+ // byte, we don't want to grow by a byte at a time.
+ // Note, for large data (clob > 32k), it is performant
+ // to grow the array by atleast 4k rather than a small amount
+ // Even better maybe to grow by 32k but then may be
+ // a little excess(?) for small data.
+ // hopefully in.available() will give a fair
+ // estimate of how much data can be read to grow the
+ // array by larger and necessary chunks.
+ // This performance issue due to
+ // the slow growth of this array was noticed since inserts
+ // on clobs was taking a really long time as
+ // the array here grew previously by 64 bytes each time
+ // till stream was drained. (Derby-302)
+ // for char, growby 64 seems reasonable, but for varchar
+ // clob 4k or 32k is performant and hence
+ // growBy() is override correctly to ensure this
+ if (growby < minGrowBy)
+ growby = minGrowBy;
+
+ int newstrlength = arrayLength + growby;
+ char oldstr[] = str;
+ str = new char[newstrlength];
+
+ System.arraycopy(oldstr, 0, str, 0, arrayLength);
+ arrayLength = newstrlength;
+ }
+
+ /// top fours bits of the first unsigned byte that maps to a
+ // 1,2 or 3 byte character
+ //
+ // 0000xxxx - 0 - 1 byte char
+ // 0001xxxx - 1 - 1 byte char
+ // 0010xxxx - 2 - 1 byte char
+ // 0011xxxx - 3 - 1 byte char
+ // 0100xxxx - 4 - 1 byte char
+ // 0101xxxx - 5 - 1 byte char
+ // 0110xxxx - 6 - 1 byte char
+ // 0111xxxx - 7 - 1 byte char
+ // 1000xxxx - 8 - error
+ // 1001xxxx - 9 - error
+ // 1010xxxx - 10 - error
+ // 1011xxxx - 11 - error
+ // 1100xxxx - 12 - 2 byte char
+ // 1101xxxx - 13 - 2 byte char
+ // 1110xxxx - 14 - 3 byte char
+ // 1111xxxx - 15 - error
+
+ int char2, char3;
+ char actualChar;
+ if ((c & 0x80) == 0x00)
+ {
+ // one byte character
+ count++;
+ actualChar = (char) c;
+ }
+ else if ((c & 0x60) == 0x40) // we know the top bit is set here
+ {
+ // two byte character
+ count += 2;
+ if (utflen != 0 && count > utflen)
+ throw new UTFDataFormatException();
+ char2 = in.readUnsignedByte();
+ if ((char2 & 0xC0) != 0x80)
+ throw new UTFDataFormatException();
+ actualChar = (char)(((c & 0x1F) << 6) | (char2 & 0x3F));
+ }
+ else if ((c & 0x70) == 0x60) // we know the top bit is set here
+ {
+ // three byte character
+ count += 3;
+ if (utflen != 0 && count > utflen)
+ throw new UTFDataFormatException();
+ char2 = in.readUnsignedByte();
+ char3 = in.readUnsignedByte();
+ if ((c == 0xE0) && (char2 == 0) && (char3 == 0)
+ && (utflen == 0))
+ {
+ // we reached the end of a long string,
+ // that was terminated with
+ // (11100000, 00000000, 00000000)
+ break readingLoop;
}
- strValue= sb.toString();
+
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+ throw new UTFDataFormatException();
+
+
+ actualChar = (char)(((c & 0x0F) << 12) |
+ ((char2 & 0x3F) << 6) |
+ ((char3 & 0x3F) << 0));
+ }
+ else {
+
+ throw new UTFDataFormatException();
}
+
+ str[strlen++] = actualChar;
+ }
+
+
+ rawData = str;
+ rawLength = strlen;
+
+ cKey = null;
+ }
+
+ /**
+ * returns the reasonable minimum amount by
+ * which the array can grow . See readExternal.
+ * when we know that the array needs to grow by at least
+ * one byte, it is not performant to grow by just one byte
+ * instead this amount is used to provide a resonable growby size.
+ * @return minimum reasonable growby size
+ */
+ protected int growBy()
+ {
+ return GROWBY_FOR_CHAR; //seems reasonable for a char
+ }
+ /**
+ * @see Storable#restoreToNull
+ *
+ */
+ public void restoreToNull()
+ {
+ value = null;
+ stream = null;
+ rawLength = -1;
+ cKey = null;
+ }
+
+ /**
+ @exception StandardException thrown on error
+ */
+ public boolean compare(int op,
+ DataValueDescriptor other,
+ boolean orderedNulls,
+ boolean unknownRV)
+ throws StandardException
+ {
+ if (!orderedNulls) // nulls are unordered
+ {
+ if (this.isNull() || ((DataValueDescriptor) other).isNull())
+ return unknownRV;
+ }
+
+ /* When comparing String types to non-string types, we always
+ * convert the string type to the non-string type.
+ */
+ if (! (other instanceof SQLChar))
+ {
+ return other.compare(flip(op), this, orderedNulls, unknownRV);
+ }
+
+ /* Do the comparison */
+ return super.compare(op, other, orderedNulls, unknownRV);
+ }
+
+ /**
+ @exception StandardException thrown on error
+ */
+ public int compare(DataValueDescriptor other) throws StandardException
+ {
+ /* Use compare method from dominant type, negating result
+ * to reflect flipping of sides.
+ */
+ if (typePrecedence() < other.typePrecedence())
+ {
+ return - (other.compare(this));
+ }
+
+ // stringCompare deals with null as comparable and smallest
+ return stringCompare(this, (SQLChar)other);
+ }
+
+ /*
+ * CloneableObject interface
+ */
+
+ /** From CloneableObject
+ * Shallow clone a StreamStorable without objectifying. This is used to
+ * avoid unnecessary objectifying of a stream object. The only
+ * difference of this method from getClone is this method does not
+ * objectify a stream.
+ */
+ public Object cloneObject()
+ {
+ if (stream == null)
+ return getClone();
+ SQLChar self = (SQLChar) getNewNull();
+ self.copyState(this);
+ return self;
+ }
+
+ /*
+ * DataValueDescriptor interface
+ */
+
+ /** @see DataValueDescriptor#getClone */
+ public DataValueDescriptor getClone()
+ {
+ try
+ {
+ return new SQLChar(getString());
+ }
+ catch (StandardException se)
+ {
+ if (SanityManager.DEBUG)
+ SanityManager.THROWASSERT("Unexpected exception", se);
+ return null;
+ }
+ }
+
+ /**
+ * @see DataValueDescriptor#getNewNull
+ *
+ */
+ public DataValueDescriptor getNewNull()
+ {
+ return new SQLChar();
+ }
+
+ /** @see StringDataValue#getValue(RuleBasedCollator) */
+ public StringDataValue getValue(RuleBasedCollator collatorForComparison)
+ {
+ if (collatorForComparison == null)
+ {//null collatorForComparison means use UCS_BASIC for collation
+ return this;
+ } else {
+ //non-null collatorForComparison means use collator sensitive
+ //implementation of SQLChar
+ CollatorSQLChar s = new CollatorSQLChar(collatorForComparison);
+ s.copyState(this);
+ return s;
+ }
+ }
+
+ /**
+ * @see DataValueDescriptor#setValueFromResultSet
+ *
+ * @exception SQLException Thrown on error
+ */
+ public final void setValueFromResultSet(ResultSet resultSet, int colNumber,
+ boolean isNullable)
+ throws SQLException
+ {
+ setValue(resultSet.getString(colNumber));
+ }
+
+ /**
+ Set the value into a PreparedStatement.
+ */
+ public final void setInto(
+ PreparedStatement ps,
+ int position)
+ throws SQLException, StandardException
+ {
+ ps.setString(position, getString());
+ }
+
+
+
+ public void setValue(String theValue)
+ {
+ stream = null;
+ rawLength = -1;
+ cKey = null;
+
+ value = theValue;
+ }
+
+ public void setValue(boolean theValue) throws StandardException
+ {
+ // match JCC.
+ setValue(theValue ? "1" : "0");
+ }
+
+ public void setValue(int theValue) throws StandardException
+ {
+ setValue(Integer.toString(theValue));
+ }
+
+ public void setValue(double theValue) throws StandardException
+ {
+ setValue(Double.toString(theValue));
+ }
+
+ public void setValue(float theValue) throws StandardException
+ {
+ setValue(Float.toString(theValue));
+ }
+
+ public void setValue(short theValue) throws StandardException
+ {
+ setValue(Short.toString(theValue));
+ }
+
+ public void setValue(long theValue) throws StandardException
+ {
+ setValue(Long.toString(theValue));
+ }
+
+ public void setValue(byte theValue) throws StandardException
+ {
+ setValue(Byte.toString(theValue));
+ }
+
+ public void setValue(byte[] theValue) throws StandardException
+ {
+ if (theValue == null)
+ {
+ restoreToNull();
+ return;
+ }
+
+ /*
+ ** We can't just do a new String(theValue)
+ ** because that method assumes we are converting
+ ** ASCII and it will take on char per byte.
+ ** So we need to convert the byte array to a
+ ** char array and go from there.
+ **
+ ** If we have an odd number of bytes pad out.
+ */
+ int mod = (theValue.length % 2);
+ int len = (theValue.length/2) + mod;
+ char[] carray = new char[len];
+ int cindex = 0;
+ int bindex = 0;
+
+ /*
+ ** If we have a left over byte, then get
+ ** that now.
+ */
+ if (mod == 1)
+ {
+ carray[--len] = (char)(theValue[theValue.length - 1] << 8);
+ }
+
+ for (; cindex < len; bindex+=2, cindex++)
+ {
+ carray[cindex] = (char)((theValue[bindex] << 8) |
+ (theValue[bindex+1] & 0x00ff));
+ }
+
+ setValue(new String(carray));
+ }
+
+ /**
+ Only to be called when an application through JDBC is setting a
+ SQLChar to a java.math.BigDecimal.
+ */
+ public void setBigDecimal(Number bigDecimal) throws StandardException
+ {
+ if (bigDecimal == null)
+ setToNull();
+ else
+ setValue(bigDecimal.toString());
+ }
+
+ /** @exception StandardException Thrown on error */
+ public void setValue(Date theValue, Calendar cal) throws StandardException
+ {
+ String strValue = null;
+ if( theValue != null)
+ {
+ if( cal == null)
+ strValue = theValue.toString();
+ else
+ {
+ cal.setTime( theValue);
+ StringBuffer sb = new StringBuffer();
+ formatJDBCDate( cal, sb);
+ strValue= sb.toString();
+ }
+ }
+ setValue( strValue);
+ }
+
+ /** @exception StandardException Thrown on error */
+ public void setValue(Time theValue, Calendar cal) throws StandardException
+ {
+ String strValue = null;
+ if( theValue != null)
+ {
+ if( cal == null)
+ strValue = theValue.toString();
+ else
+ {
+ cal.setTime( theValue);
+ StringBuffer sb = new StringBuffer();
+ formatJDBCTime( cal, sb);
+ strValue= sb.toString();
+ }
+ }
+ setValue( strValue);
+ }
+
+ /** @exception StandardException Thrown on error */
+ public void setValue(
+ Timestamp theValue,
+ Calendar cal)
+ throws StandardException
+ {
+ String strValue = null;
+ if( theValue != null)
+ {
+ if( cal == null)
+ strValue = theValue.toString();
+ else
+ {
+ cal.setTime( theValue);
+ StringBuffer sb = new StringBuffer();
+ formatJDBCDate( cal, sb);
+ sb.append( ' ');
+ formatJDBCTime( cal, sb);
+ int micros =
+ (theValue.getNanos() + SQLTimestamp.FRACTION_TO_NANO/2) /
+ SQLTimestamp.FRACTION_TO_NANO;
+
+ if( micros > 0)
+ {
+ sb.append( '.');
+ String microsStr = Integer.toString( micros);
+ if(microsStr.length() > SQLTimestamp.MAX_FRACTION_DIGITS)
+ {
+ sb.append(
+ microsStr.substring(
+ 0, SQLTimestamp.MAX_FRACTION_DIGITS));
+ }
+ else
+ {
+ for(int i = microsStr.length();
+ i < SQLTimestamp.MAX_FRACTION_DIGITS ; i++)
+ {
+ sb.append( '0');
+ }
+
+ sb.append( microsStr);
+ }
+ }
+ strValue= sb.toString();
+ }
+ }
+ setValue( strValue);
+ }
+
+ private void formatJDBCDate( Calendar cal, StringBuffer sb)
+ {
+ SQLDate.dateToString( cal.get( Calendar.YEAR),
+ cal.get( Calendar.MONTH) - Calendar.JANUARY + 1,
+ cal.get( Calendar.DAY_OF_MONTH),
+ sb);
+ }
+
+ private void formatJDBCTime( Calendar cal, StringBuffer sb)
+ {
+ SQLTime.timeToString(
+ cal.get(Calendar.HOUR),
+ cal.get(Calendar.MINUTE),
+ cal.get(Calendar.SECOND),
+ sb);
+ }
+
+ /**
+ * Set the value from the stream which is in the on-disk format.
+ * @param theStream On disk format of the stream
+ * @param valueLength length of the logical value in characters.
+ */
+ public final void setValue(InputStream theStream, int valueLength)
+ {
+ setStream(theStream);
+ }
+
+ /**
+ * Allow any Java type to be cast to a character type using
+ * Object.toString.
+ * @see DataValueDescriptor#setObjectForCast
+ *
+ * @exception StandardException
+ * thrown on failure
+ */
+ public void setObjectForCast(
+ Object theValue,
+ boolean instanceOfResultType,
+ String resultTypeClassName)
+ throws StandardException
+ {
+ if (theValue == null)
+ {
+ setToNull();
+ return;
+ }
+
+ if ("java.lang.String".equals(resultTypeClassName))
+ setValue(theValue.toString());
+ else
+ super.setObjectForCast(
+ theValue, instanceOfResultType, resultTypeClassName);
+ }
+
+ protected void setFrom(DataValueDescriptor theValue)
+ throws StandardException
+ {
+ setValue(theValue.getString());
+ }
+
+ /**
+ * Normalization method - this method may be called when putting
+ * a value into a SQLChar, for example, when inserting into a SQLChar
+ * column. See NormalizeResultSet in execution.
+ *
+ * @param desiredType The type to normalize the source column to
+ * @param source The value to normalize
+ *
+ *
+ * @exception StandardException Thrown for null into
+ * non-nullable column, and for
+ * truncation error
+ */
+
+ public void normalize(
+ DataTypeDescriptor desiredType,
+ DataValueDescriptor source)
+ throws StandardException
+ {
+
+ normalize(desiredType, source.getString());
+
+ }
+
+ protected void normalize(DataTypeDescriptor desiredType, String sourceValue)
+ throws StandardException
+ {
+
+
+ int desiredWidth = desiredType.getMaximumWidth();
+ int sourceWidth = sourceValue.length();
+
+ /*
+ ** If the input is already the right length, no normalization is
+ ** necessary - just return the source.
+ */
+ if (sourceWidth == desiredWidth) {
+ setValue(sourceValue);
+ return;
+ }
+
+ /*
+ ** If the input is shorter than the desired type, construct a new
+ ** SQLChar padded with blanks to the right length.
+ */
+ if (sourceWidth < desiredWidth)
+ {
+ setToNull();
+
+ char[] ca;
+ if ((rawData == null) || (desiredWidth > rawData.length)) {
+
+ ca = rawData = new char[desiredWidth];
+ } else {
+ ca = rawData;
+ }
+
+ sourceValue.getChars(0, sourceWidth, ca, 0);
+ SQLChar.appendBlanks(ca, sourceWidth, desiredWidth - sourceWidth);
+
+ rawLength = desiredWidth;
+
+ return;
+ }
+
+ /*
+ ** Check whether any non-blank characters will be truncated.
+ */
+ hasNonBlankChars(sourceValue, desiredWidth, sourceWidth);
+
+ /*
+ ** No non-blank characters will be truncated. Truncate the blanks
+ ** to the desired width.
+ */
+
+ String truncatedString = sourceValue.substring(0, desiredWidth);
+ setValue(truncatedString);
+ }
+
+ /*
+ ** Method to check for truncation of non blank chars.
+ */
+ protected final void hasNonBlankChars(String source, int start, int end)
+ throws StandardException
+ {
+ /*
+ ** Check whether any non-blank characters will be truncated.
+ */
+ for (int posn = start; posn < end; posn++)
+ {
+ if (source.charAt(posn) != ' ')
+ {
+ throw StandardException.newException(
+ SQLState.LANG_STRING_TRUNCATION,
+ getTypeName(),
+ StringUtil.formatForPrint(source),
+ String.valueOf(start));
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////
+ //
+ // VariableSizeDataValue INTERFACE
+ //
+ ///////////////////////////////////////////////////////////////
+
+ /**
+ * Set the width of the to the desired value. Used
+ * when CASTing. Ideally we'd recycle normalize(), but
+ * the behavior is different (we issue a warning instead
+ * of an error, and we aren't interested in nullability).
+ *
+ * @param desiredWidth the desired length
+ * @param desiredScale the desired scale (ignored)
+ * @param errorOnTrunc throw an error on truncation
+ *
+ * @exception StandardException Thrown when errorOnTrunc
+ * is true and when a shrink will truncate non-white
+ * spaces.
+ */
+ public void setWidth(int desiredWidth,
+ int desiredScale, // Ignored
+ boolean errorOnTrunc)
+ throws StandardException
+ {
+ int sourceWidth;
+
+ /*
+ ** If the input is NULL, nothing to do.
+ */
+ if (getString() == null)
+ {
+ return;
+ }
+
+ sourceWidth = getLength();
+
+ /*
+ ** If the input is shorter than the desired type, construct a new
+ ** SQLChar padded with blanks to the right length. Only
+ ** do this if we have a SQLChar -- SQLVarchars don't
+ ** pad.
+ */
+ if (sourceWidth < desiredWidth)
+ {
+ if (!(this instanceof SQLVarchar))
+ {
+ StringBuffer strbuf;
+
+ strbuf = new StringBuffer(getString());
+
+ for ( ; sourceWidth < desiredWidth; sourceWidth++)
+ {
+ strbuf.append(' ');
+ }
+
+ setValue(new String(strbuf));
+ }
+ }
+ else if (sourceWidth > desiredWidth && desiredWidth > 0)
+ {
+ /*
+ ** Check whether any non-blank characters will be truncated.
+ */
+ if (errorOnTrunc)
+ hasNonBlankChars(getString(), desiredWidth, sourceWidth);
+ //RESOLVE: should issue a warning instead
+
+ /*
+ ** Truncate to the desired width.
+ */
+ setValue(getString().substring(0, desiredWidth));
+ }
+ return;
+ }
+
+ /*
+ ** SQL Operators
+ */
+
+ /**
+ * The = operator as called from the language module, as opposed to
+ * the storage module.
+ *
+ * @param left The value on the left side of the =
+ * @param right The value on the right side of the =
+ *
+ * @return A SQL boolean value telling whether the two parameters are equal
+ *
+ * @exception StandardException Thrown on error
+ */
+
+ public BooleanDataValue equals(DataValueDescriptor left,
+ DataValueDescriptor right)
+ throws StandardException
+ {
+ boolean comparison;
+
+ if ((left instanceof SQLChar) && (right instanceof SQLChar))
+ {
+ comparison = stringCompare((SQLChar) left, (SQLChar) right) == 0;
+ }
+ else
+ {
+ comparison = stringCompare(left.getString(),
+ right.getString()) == 0;
+ }
+
+ return SQLBoolean.truthValue(left,
+ right,
+ comparison);
+ }
+
+ /**
+ * The <> operator as called from the language module, as opposed to
+ * the storage module.
+ *
+ * @param left The value on the left side of the <>
+ * @param right The value on the right side of the <>
+ *
+ * @return A SQL boolean value telling whether the two parameters
+ * are not equal
+ *
+ * @exception StandardException Thrown on error
+ */
+
+ public BooleanDataValue notEquals(DataValueDescriptor left,
+ DataValueDescriptor right)
+ throws StandardException
+ {
+ boolean comparison;
+
+ if ((left instanceof SQLChar) && (right instanceof SQLChar))
+ {
+ comparison = stringCompare((SQLChar) left, (SQLChar) right) != 0;
+ }
+ else
+ {
+ comparison = stringCompare(left.getString(),
+ right.getString()) != 0;
+ }
+
+ return SQLBoolean.truthValue(left,
+ right,
+ comparison);
+ }
+
+ /**
+ * The < operator as called from the language module, as opposed to
+ * the storage module.
+ *
+ * @param left The value on the left side of the <
+ * @param right The value on the right side of the <
+ *
+ * @return A SQL boolean value telling whether the first operand is
+ * less than the second operand
+ *
+ * @exception StandardException Thrown on error
+ */
+
+ public BooleanDataValue lessThan(DataValueDescriptor left,
+ DataValueDescriptor right)
+ throws StandardException
+ {
+ boolean comparison;
+
+ if ((left instanceof SQLChar) && (right instanceof SQLChar))
+ {
+ comparison = stringCompare((SQLChar) left, (SQLChar) right) < 0;
+ }
+ else
+ {
+ comparison = stringCompare(left.getString(),
+ right.getString()) < 0;
+ }
+
+ return SQLBoolean.truthValue(left,
+ right,
+ comparison);
+ }
+
+ /**
+ * The > operator as called from the language module, as opposed to
+ * the storage module.
+ *
+ * @param left The value on the left side of the >
+ * @param right The value on the right side of the >
+ *
+ * @return A SQL boolean value telling whether the first operand is
+ * greater than the second operand
+ *
+ * @exception StandardException Thrown on error
+ */
+
+ public BooleanDataValue greaterThan(DataValueDescriptor left,
+ DataValueDescriptor right)
+ throws StandardException
+ {
+ boolean comparison;
+
+ if ((left instanceof SQLChar) && (right instanceof SQLChar))
+ {
+ comparison = stringCompare((SQLChar) left, (SQLChar) right) > 0;
+ }
+ else
+ {
+ comparison = stringCompare(left.getString(),
+ right.getString()) > 0;
+ }
+
+ return SQLBoolean.truthValue(left,
+ right,
+ comparison);
+ }
+
+ /**
+ * The <= operator as called from the language module, as opposed to
+ * the storage module.
+ *
+ * @param left The value on the left side of the <=
+ * @param right The value on the right side of the <=
+ *
+ * @return A SQL boolean value telling whether the first operand is
+ * less than or equal to the second operand
+ *
+ * @exception StandardException Thrown on error
+ */
+
+ public BooleanDataValue lessOrEquals(DataValueDescriptor left,
+ DataValueDescriptor right)
+ throws StandardException
+ {
+ boolean comparison;
+
+ if ((left instanceof SQLChar) && (right instanceof SQLChar))
+ {
+ comparison = stringCompare((SQLChar) left, (SQLChar) right) <= 0;
+ }
+ else
+ {
+ comparison = stringCompare(left.getString(),
+ right.getString()) <= 0;
+ }
+
+ return SQLBoolean.truthValue(left,
+ right,
+ comparison);
+ }
+
+ /**
+ * The >= operator as called from the language module, as opposed to
+ * the storage module.
+ *
+ * @param left The value on the left side of the >=
+ * @param right The value on the right side of the >=
+ *
+ * @return A SQL boolean value telling whether the first operand is
+ * greater than or equal to the second operand
+ *
+ * @exception StandardException Thrown on error
+ */
+
+ public BooleanDataValue greaterOrEquals(DataValueDescriptor left,
+ DataValueDescriptor right)
+ throws StandardException
+ {
+ boolean comparison;
+
+ if ((left instanceof SQLChar) && (right instanceof SQLChar))
+ {
+ comparison = stringCompare((SQLChar) left, (SQLChar) right) >= 0;
+ }
+ else
+ {
+ comparison = stringCompare(left.getString(),
+ right.getString()) >= 0;
+ }
+
+ return SQLBoolean.truthValue(left,
+ right,
+ comparison);
+ }
+
+ /*
+ ** Concatable interface
+ */
+ /**
+ * This method implements the char_length function for char.
+ *
+ * @param result The result of a previous call to this method, null
+ * if not called yet
+ *
+ * @return A SQLInteger containing the length of the char value
+ *
+ * @exception StandardException Thrown on error
+ *
+ * @see ConcatableDataValue#charLength(NumberDataValue)
+ */
+ public NumberDataValue charLength(NumberDataValue result)
+ throws StandardException
+ {
+ if (result == null)
+ {
+ result = new SQLInteger();
+ }
+
+ if (this.isNull())
+ {
+ result.setToNull();
+ return result;
+ }
+
+ result.setValue(this.getLength());
+ return result;
+ }
+
+ /**
+ * @see StringDataValue#concatenate
+ *
+ * @exception StandardException Thrown on error
+ */
+ public StringDataValue concatenate(
+ StringDataValue leftOperand,
+ StringDataValue rightOperand,
+ StringDataValue result)
+ throws StandardException
+ {
+ if (leftOperand.isNull() || leftOperand.getString() == null ||
+ rightOperand.isNull() || rightOperand.getString() == null)
+ {
+ result.setToNull();
+ return result;
+ }
+
+ result.setValue(
+ leftOperand.getString().concat(rightOperand.getString()));
+
+ return result;
+ }
+
+
+ /**
+ * This method implements the like function for char (with no escape value).
+ *
+ * @param pattern The pattern to use
+ *
+ * @return A SQL boolean value telling whether the first operand is
+ * like the second operand
+ *
+ * @exception StandardException Thrown on error
+ */
+ public BooleanDataValue like(DataValueDescriptor pattern)
+ throws StandardException
+ {
+ Boolean likeResult;
+
+ // note that we call getLength() because the length
+ // of the char array may be different than the
+ // length we should be using (i.e. getLength()).
+ // see getCharArray() for more info
+ char[] evalCharArray = getCharArray();
+ char[] patternCharArray = ((SQLChar)pattern).getCharArray();
+ likeResult = Like.like(evalCharArray,
+ getLength(),
+ patternCharArray,
+ pattern.getLength(),
+ null);
+
+ return SQLBoolean.truthValue(this,
+ pattern,
+ likeResult);
+ }
+
+ /**
+ * This method implements the like function for char with an escape value.
+ *
+ * @param pattern The pattern to use
+ *
+ * @return A SQL boolean value telling whether the first operand is
+ * like the second operand
+ *
+ * @exception StandardException Thrown on error
+ */
+
+ public BooleanDataValue like(
+ DataValueDescriptor pattern,
+ DataValueDescriptor escape)
+ throws StandardException
+ {
+ Boolean likeResult;
+
[... 2218 lines stripped ...]