gt:             return new AS400JDBCBlob(bytes, bytes.length);
context: ///////////////////////////////////////////////////////////////////////////////
  //                                                                             
  // JTOpen (IBM Toolbox for Java - OSS version)                                 
  //                                                                             
  // Filename: SQLVarchar.java
  //                                                                             
  // The source code contained herein is licensed under the IBM Public License   
  // Version 1.0, which has been approved by the Open Source Initiative.         
  // Copyright (C) 1997-2003 International Business Machines Corporation and     
  // others. All rights reserved.                                                
  //                                                                             
  ///////////////////////////////////////////////////////////////////////////////
  
  package com.ibm.as400.access;
  
  import java.io.ByteArrayInputStream;
  import java.io.InputStream;
  import java.io.Reader;
  import java.io.StringReader;
  import java.io.UnsupportedEncodingException;
  import java.math.BigDecimal;
  import java.sql.Array;
  import java.sql.Blob;
  import java.sql.Clob;
  import java.sql.Date;
  /* ifdef JDBC40 
  import java.sql.NClob;
  import java.sql.RowId;
  endif */ 
  import java.sql.SQLException;
  /* ifdef JDBC40 
  import java.sql.SQLXML;
  endif */ 
  import java.sql.Time;
  import java.sql.Timestamp;
  import java.util.Calendar;
  import java.net.URL;
  
  final class SQLVarchar
  implements SQLData
  {
      static final String copyright = "Copyright (C) 1997-2003 International Business Machines Corporation and others.";
  
      // Private data.
      private SQLConversionSettings   settings_;
      private int                     length_;
      private int                     maxLength_;
      private int                     truncated_;
      private String                  value_;
  
      // Note: maxLength is in bytes not counting 2 for LL.
      //
      SQLVarchar(int maxLength, SQLConversionSettings settings)
      {
          settings_       = settings;
          length_         = 0;
          maxLength_      = maxLength;
          truncated_      = 0;
          value_          = "";
      }
  
      public Object clone()
      {
          return new SQLVarchar(maxLength_, settings_);
      }
  
      // @A2A
      // Added method trim() to trim the string.
      public void trim()                                // @A2A
      {                                                 // @A2A
          value_ = value_.trim();                       // @A2A
      }                                                 // @A2A
  
      //---------------------------------------------------------//
      //                                                         //
      // CONVERSION TO AND FROM RAW BYTES                        //
      //                                                         //
      //---------------------------------------------------------//
  
      public void convertFromRawBytes(byte[] rawBytes, int offset, ConvTable ccsidConverter)
      throws SQLException
      {
          length_ = BinaryConverter.byteArrayToUnsignedShort(rawBytes, offset);
  
          int bidiStringType = settings_.getBidiStringType();
          // if bidiStringType is not set by user, use ccsid to get value
          if(bidiStringType == -1)
              bidiStringType = ccsidConverter.bidiStringType_;
              
          BidiConversionProperties bidiConversionProperties = new BidiConversionProperties(bidiStringType);  //@KBA
          bidiConversionProperties.setBidiImplicitReordering(settings_.getBidiImplicitReordering());         //@KBA
          bidiConversionProperties.setBidiNumericOrderingRoundTrip(settings_.getBidiNumericOrdering());      //@KBA
  
          try{
              value_ = ccsidConverter.byteArrayToString(rawBytes, offset+2, length_, bidiConversionProperties);   //@KBC changed to use bidiConversionProperties instead of bidiStringType
          }catch(Exception e){
              JDError.throwSQLException(JDError.EXC_CHAR_CONVERSION_INVALID, e);
          }
      }
  
      public void convertToRawBytes(byte[] rawBytes, int offset, ConvTable ccsidConverter)
      throws SQLException
      {
          try
          {
              int bidiStringType = settings_.getBidiStringType();
              // if bidiStringType is not set by user, use ccsid to get value
              if(bidiStringType == -1)
                  bidiStringType = ccsidConverter.bidiStringType_;
                  
              BidiConversionProperties bidiConversionProperties = new BidiConversionProperties(bidiStringType);  //@KBA
              bidiConversionProperties.setBidiImplicitReordering(settings_.getBidiImplicitReordering());         //@KBA
              bidiConversionProperties.setBidiNumericOrderingRoundTrip(settings_.getBidiNumericOrdering());      //@KBA
  
              // The length in the first 2 bytes is actually the length in characters.
              byte[] temp = ccsidConverter.stringToByteArray(value_, bidiConversionProperties);   //@KBC changed to used bidiConversionProperties instead of bidiStringType
              BinaryConverter.unsignedShortToByteArray(temp.length, rawBytes, offset);
              if(temp.length > maxLength_)
              {
                  maxLength_ = temp.length;
                  JDError.throwSQLException(this, JDError.EXC_INTERNAL, "Change Descriptor");
              }
              System.arraycopy(temp, 0, rawBytes, offset+2, temp.length);
  
              // The buffer we are filling with data is big enough to hold the entire field.
              // For varchar fields the actual data is often smaller than the field width.
              // That means whatever is in the buffer from the previous send is sent to the
              // system.  The data stream includes actual data length so the old bytes are not 
              // written to the database, but the junk left over may decrease the affectiveness 
              // of compression.  The following code will write hex 0s to the buffer when
              // actual length is less that field length.  Note the 0s are written only if 
              // the field length is pretty big.  The data stream code (DBBaseRequestDS)
              // does not compress anything smaller than 1K.
              if( (maxLength_ - temp.length > 16))  //@rle
              {
                  int stopHere = offset + 2 + maxLength_;
                  for(int i=offset + 2 + temp.length; i<stopHere; i++)
                      rawBytes[i] = 0x00;
              }
          }
          catch(Exception e)
          {
              JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
          }
      }
  
      //---------------------------------------------------------//
      //                                                         //
      // SET METHODS                                             //
      //                                                         //
      //---------------------------------------------------------//
  
      public void set(Object object, Calendar calendar, int scale)
      throws SQLException
      {
          String value = null;                                                        // @C1A
  
          if(object instanceof String)
              value = (String) object;                                                // @C1C
  
          else if(object instanceof Number)
              value = object.toString();                                              // @C1C
  
          else if(object instanceof Boolean)
          { 
              // @PDC
              // if "translate boolean" == false, then use "0" and "1" values to match native driver
              if(settings_.getTranslateBoolean() == true)
                  value = object.toString();  //"true" or "false"     
              else
                  value = ((Boolean)object).booleanValue() == true ? "1" : "0";
          }
          else if(object instanceof Time)
              value = SQLTime.timeToString((Time) object, settings_, calendar);      // @C1C
  
          else if(object instanceof Timestamp)
              value = SQLTimestamp.timestampToString((Timestamp) object, calendar);  // @C1C
  
          else if(object instanceof java.util.Date)                                  // @F5M @F5C
              value = SQLDate.dateToString((java.util.Date) object, settings_, calendar); // @C1C @F5C
  
          else if(object instanceof URL)
              value = object.toString();
  
          else if(JDUtilities.JDBCLevel_ >= 20 && object instanceof Clob)
          {                                                                          // @C1C
              Clob clob = (Clob)object;                                              // @C1C
              value = clob.getSubString(1, (int)clob.length());                      // @C1C  @D1
          }                                                                     // @C1C
               
          /* ifdef JDBC40 
          else if(object instanceof SQLXML) //@PDA jdbc40 
          {    
              SQLXML xml = (SQLXML)object;
              value = xml.getString();
          }   
          endif */         
  
          if(value == null)                                                          // @C1C
              JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
          value_ = value;                                                            // @C1A
  
          // Truncate if necessary.
          int valueLength = value_.length();
  
          int truncLimit = maxLength_;              // @F2a
  
          if(valueLength > truncLimit)             // @F2c
          {
              value_ = value_.substring(0, truncLimit); // @F2c
              truncated_ = valueLength - truncLimit;     // @F2c
          }
          else
              truncated_ = 0;
  
          length_ = value_.length();
      }
  
      //---------------------------------------------------------//
      //                                                         //
      // DESCRIPTION OF SQL TYPE                                 //
      //                                                         //
      //---------------------------------------------------------//
  
      public int getSQLType()
      {
          return SQLData.VARCHAR;
      }
  
      public String getCreateParameters()
      {
          return AS400JDBCDriver.getResource("MAXLENGTH");
      }
  
      public int getDisplaySize()
      {
          return maxLength_;
      }
  
      //@F1A JDBC 3.0
      public String getJavaClassName()
      {
          return "java.lang.String";   
      }
  
      public String getLiteralPrefix()
      {
          return "\'";
      }
  
      public String getLiteralSuffix()
      {
          return "\'";
      }
  
      public String getLocalName()
      {
          return "VARCHAR";
      }
  
      public int getMaximumPrecision()
      {
          return 32739;
      }
  
      public int getMaximumScale()
      {
          return 0;
      }
  
      public int getMinimumScale()
      {
          return 0;
      }
  
      public int getNativeType()
      {
          return 448;
      }
  
      public int getPrecision()
      {
          return maxLength_;
      }
  
      public int getRadix()
      {
          return 0;
      }
  
      public int getScale()
      {
          return 0;
      }
  
      public int getType()
      {
          return java.sql.Types.VARCHAR;
      }
  
      public String getTypeName()
      {
          return "VARCHAR";
      }
  
      public boolean isSigned()
      {
          return false;
      }
  
      public boolean isText()
      {
          return true;
      }
  
      public int getActualSize()
      {
          return value_.length();
      }
  
      public int getTruncated()
      {
          return truncated_;
      }
  
      //---------------------------------------------------------//
      //                                                         //
      // CONVERSIONS TO JAVA TYPES                               //
      //                                                         //
      //---------------------------------------------------------//
  
      public InputStream getAsciiStream()
      throws SQLException
      {
          truncated_ = 0;
          try
          {
              return new ByteArrayInputStream(ConvTable.getTable(819, null).stringToByteArray(getString()));
          }
          catch(UnsupportedEncodingException e)
          {
              JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
              return null;
          }
      }
  
      public BigDecimal getBigDecimal(int scale)
      throws SQLException
      {
          truncated_ = 0;
          try
          {
              BigDecimal bigDecimal = new BigDecimal(SQLDataFactory.convertScientificNotation(getString())); // @F3C
              if(scale >= 0)
              {
                  if(scale >= bigDecimal.scale())
                  {
                      truncated_ = 0;
                      return bigDecimal.setScale(scale);
                  }
                  else
                  {
                      truncated_ = bigDecimal.scale() - scale;
                      return bigDecimal.setScale(scale, BigDecimal.ROUND_HALF_UP);
                  }
              }
              else
                  return bigDecimal;
          }
          catch(NumberFormatException e)
          {
              JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH, e);
              return null;
          }
      }
  
      public InputStream getBinaryStream()
      throws SQLException
      {
          truncated_ = 0;
          return new HexReaderInputStream(new StringReader(getString()));
      }
  
      public Blob getBlob()
      throws SQLException
      {
          truncated_ = 0;
          try
          {
              byte[] bytes = BinaryConverter.stringToBytes(getString());
  