/**
   * Returns a <code>Reader</code> object that contains a partial <code>Clob</code> value, starting
   * with the character specified by pos, which is length characters in length.
   *
   * @param pos the offset to the first character of the partial value to be retrieved. The first
   *     character in the Clob is at position 1.
   * @param length the length in characters of the partial value to be retrieved.
   * @return <code>Reader</code> through which the partial <code>Clob</code> value can be read.
   * @throws SQLException if pos is less than 1 or if pos is greater than the number of characters
   *     in the <code>Clob</code> or if pos + length is greater than the number of characters in the
   *     <code>Clob</code>
   */
  public Reader getCharacterStream(long pos, long length) throws SQLException // @sync
      {
    if (locator_ == null) // @free
    JDError.throwSQLException(this, JDError.EXC_FUNCTION_SEQUENCE); // @free

    synchronized (locator_) // @sync
    {
      if (pos < 1
          || (pos - 1 + length) > locator_.getMaxLength()
          || length < 0) // @pdc change parm check like getSubString
      {
        JDError.throwSQLException(this, JDError.EXC_ATTRIBUTE_VALUE_INVALID);
      }
      Reader r = null;

      try {
        // @xml3 if xml column, remove xml declaration via ConvTableReader
        r =
            new ConvTableReader(
                new AS400JDBCInputStream(locator_),
                converter_.getCcsid(),
                converter_.bidiStringType_,
                isXML_); // @xml3
        r.skip(pos);
        return r;
      } catch (UnsupportedEncodingException e) {
        JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
        return null;
      } catch (IOException e) {
        JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
        return null;
      }
    }
  }
 public void convertFromRawBytes(
     byte[] rawBytes, int offset, ConvTable ccsidConverter, boolean ignoreConversionErrors)
     throws SQLException {
   int locatorHandle = BinaryConverter.byteArrayToInt(rawBytes, offset);
   locator_.setHandle(locatorHandle);
   locator_.setColumnIndex(columnIndex_);
   // @J5A reset saved handle after setting new value
   savedObject_ = null;
 }
Example #3
0
  public String getString() throws SQLException {
    if (savedObject_ != null) // @loch
    { // @loch
      // get value from RS.updateX(value)
      doConversion(); // @loch
      truncated_ = 0; // @loch
      return value_; // @loch
    } // @loch

    DBLobData data = locator_.retrieveData(0, locator_.getMaxLength());
    String value =
        converter_.byteArrayToString(data.getRawBytes(), data.getOffset(), data.getLength());
    truncated_ = 0; // @pda make consistent with other SQLData Clob classes
    return value;
  }
  /**
   * Writes a String to this CLOB, starting at position <i>position</i>. The CLOB will be truncated
   * after the last character written.
   *
   * @param position The position (1-based) in the CLOB where writes should start.
   * @param stringToWrite The string that will be written to the CLOB.
   * @return The number of characters that were written.
   * @exception SQLException If there is an error accessing the CLOB or if the position specified is
   *     greater than the length of the CLOB.
   */
  public int setString(long position, String stringToWrite) throws SQLException {
    if (locator_ == null) // @free
    JDError.throwSQLException(this, JDError.EXC_FUNCTION_SEQUENCE); // @free

    synchronized (locator_) {
      int offset = (int) position - 1;

      if (offset < 0 || offset >= maxLength_ || stringToWrite == null) {
        throw JDError.throwSQLException(this, JDError.EXC_ATTRIBUTE_VALUE_INVALID);
      }

      // We will write as many chars as we can. If our internal char array
      // would overflow past the 2 GB boundary, we don't throw an error, we just
      // return the number of chars that were set.
      char[] charsToWrite = stringToWrite.toCharArray();
      int newSize = offset + charsToWrite.length;
      if (newSize < 0) newSize = 0x7FFFFFFF; // In case the addition resulted in overflow.
      int numChars = newSize - offset;
      if (numChars != charsToWrite.length) {
        char[] temp = charsToWrite;
        charsToWrite = new char[newSize];
        System.arraycopy(temp, 0, charsToWrite, 0, numChars);
      }

      // We don't really know if all of these chars can be written until we go to
      // the system, so we just return the char[] length as the number written.
      byte[] bytesToWrite = converter_.stringToByteArray(charsToWrite, 0, charsToWrite.length);
      locator_.writeData((long) offset, bytesToWrite, false); // @K1A
      return charsToWrite.length;
    }
  }
  /**
   * Writes a String to this CLOB, starting at position <i>position</i> in the CLOB. The CLOB will
   * be truncated after the last character written. The <i>lengthOfWrite</i> characters written will
   * start from <i>offset</i> in the string that was provided by the application.
   *
   * @param position The position (1-based) in the CLOB where writes should start.
   * @param string The string that will be written to the CLOB.
   * @param offset The offset into string to start reading characters (0-based).
   * @param lengthOfWrite The number of characters to write.
   * @return The number of characters written.
   * @exception SQLException If there is an error accessing the CLOB value or if the position
   *     specified is greater than the length of the CLOB.
   */
  public int setString(long position, String string, int offset, int lengthOfWrite)
      throws SQLException {
    if (locator_ == null) // @free
    JDError.throwSQLException(this, JDError.EXC_FUNCTION_SEQUENCE); // @free

    synchronized (locator_) {
      int clobOffset = (int) position - 1;
      if (clobOffset < 0
          || clobOffset >= maxLength_
          || string == null
          || offset < 0
          || lengthOfWrite < 0
          || (offset + lengthOfWrite) > string.length()
          || (clobOffset + lengthOfWrite) > maxLength_) {
        throw JDError.throwSQLException(this, JDError.EXC_ATTRIBUTE_VALUE_INVALID);
      }

      // We will write as many chars as we can. If our internal char array
      // would overflow past the 2 GB boundary, we don't throw an error, we just
      // return the number of chars that were set.
      int newSize = clobOffset + lengthOfWrite;
      if (newSize < 0) newSize = 0x7FFFFFFF; // In case the addition resulted in overflow.
      int numChars = newSize - clobOffset;
      int realLength = (numChars < lengthOfWrite ? numChars : lengthOfWrite);
      char[] charsToWrite = new char[realLength];
      string.getChars(offset, offset + numChars, charsToWrite, 0); // @K2C

      // We don't really know if all of these chars can be written until we go to
      // the system, so we just return the char[] length as the number written.
      byte[] bytesToWrite = converter_.stringToByteArray(charsToWrite, 0, charsToWrite.length);
      locator_.writeData((long) clobOffset, bytesToWrite, false); // @k1A
      return charsToWrite.length;
    }
  }
 /**
  * Constructs an AS400JDBCClobLocator object. The data for the CLOB will be retrieved as
  * requested, directly from the IBM i system, using the locator handle.
  *
  * @param locator The locator.
  * @param converter The text converter.
  */
 AS400JDBCClobLocator(
     JDLobLocator locator, ConvTable converter, Object savedObject, int savedScale) {
   locator_ = locator;
   converter_ = converter;
   savedObject_ = savedObject;
   savedScale_ = savedScale;
   maxLength_ = locator_.getMaxLength();
 }
  /**
   * Returns the length of the current contents of the CLOB in characters.
   *
   * @return The length of the CLOB in characters.
   * @exception SQLException If an error occurs.
   */
  public long length() throws SQLException {
    if (locator_ == null) // @free
    JDError.throwSQLException(this, JDError.EXC_FUNCTION_SEQUENCE); // @free

    synchronized (locator_) {
      return locator_.getLength();
    }
  }
  // @pda jdbc40
  public String getNString() throws SQLException {
    truncated_ = 0;
    outOfBounds_ = false;

    if (savedObject_ != null) // @loch
    { // @loch
      // get value from RS.updateX(value)
      doConversion(); // @loch
      truncated_ = 0;
      outOfBounds_ = false; // @loch
      return value_; // @loch
    } // @loch

    DBLobData data = locator_.retrieveData(0, locator_.getMaxLength());
    String value =
        converter_.byteArrayToString(data.getRawBytes(), data.getOffset(), data.getLength());
    return value;
  }
  /**
   * Returns the handle to this CLOB locator in the database.
   *
   * @return The handle to this locator in the databaes.
   */
  int getHandle()
      throws
          SQLException // @free called from rs.updateValue(), which in turn will throw exc back to
        // rs.updateX() caller
      {
    if (locator_ == null) // @free
    JDError.throwSQLException(this, JDError.EXC_FUNCTION_SEQUENCE); // @free

    return locator_.getHandle();
  }
Example #10
0
  // @CRS - This is only called from AS400JDBCPreparedStatement in one place.
  public void convertToRawBytes(byte[] rawBytes, int offset, ConvTable ccsidConverter)
      throws SQLException {
    BinaryConverter.intToByteArray(locator_.getHandle(), rawBytes, offset);

    // Now we write our saved data to the system, because the prepared statement is being executed.
    // We used to write the data to the system on the call to set(), but this messed up
    // batch executes, since the host server only reserves temporary space for locator handles one
    // row at a time.
    // See the toObject() method in this class for more details.
    if (savedObject_ != null) writeToServer();
  }
Example #11
0
  public byte[] getBytes() throws SQLException {
    if (savedObject_ != null) // @loch
    { // @loch
      // get value from RS.updateX(value)
      doConversion(); // @loch
      truncated_ = 0;
      outOfBounds_ = false; // @loch
      return value_; // @loch
    } // @loch

    int locatorLength = (int) locator_.getLength();
    if (locatorLength == 0) return new byte[0];
    DBLobData data = locator_.retrieveData(0, locatorLength);
    int actualLength = data.getLength();
    byte[] bytes = new byte[actualLength];
    System.arraycopy(data.getRawBytes(), data.getOffset(), bytes, 0, actualLength);
    truncated_ = 0;
    outOfBounds_ = false;
    return bytes;
  }
  /**
   * This method frees the <code>Clob</code> object and releases the resources that it holds. The
   * object is invalid once the <code>free</code> method is called. If <code>free</code> is called
   * multiple times, the subsequent calls to <code>free</code> are treated as a no-op.
   *
   * @throws SQLException if an error occurs releasing the Clob's resources
   */
  public void free() throws SQLException // @sync
      {
    if (locator_ == null) return; // no-op

    synchronized (locator_) // @sync
    {
      locator_.free();

      locator_ = null; // @pda make objects available for GC
      converter_ = null;
      savedObject_ = null;
      cache_ = null;
    }
  }
  /**
   * Returns part of the contents of the CLOB.
   *
   * @param position The position within the CLOB (1-based).
   * @param length The number of characters to return.
   * @return The contents.
   * @exception SQLException If the position is not valid, if the length is not valid, or an error
   *     occurs.
   */
  public String getSubString(long position, int length) throws SQLException {
    if (locator_ == null) // @free
    JDError.throwSQLException(this, JDError.EXC_FUNCTION_SEQUENCE); // @free

    synchronized (locator_) {
      int offset = (int) position - 1;
      if (offset < 0 || length < 0 || (offset > length())) {
        JDError.throwSQLException(this, JDError.EXC_ATTRIBUTE_VALUE_INVALID);
      }

      int lengthToUse = (int) length() - offset;
      if (lengthToUse < 0) return "";
      if (lengthToUse > length) lengthToUse = length;

      // @xml4 if xml column, remove xml declaration via ConvTableReader
      if (isXML_) {
        ConvTableReader r = null;
        try {
          r =
              new ConvTableReader(
                  new AS400JDBCInputStream(locator_),
                  converter_.getCcsid(),
                  converter_.bidiStringType_,
                  isXML_); // @xml4
          r.skip(offset); // @xml4 ConvTableReader will already have skipped XML header if column is
          // XML type
          return r.read(lengthToUse); // @xml4
        } catch (Exception e) {
          JDError.throwSQLException(this, JDError.EXC_INTERNAL, e);
          return null;
        } finally {
          try {
            if (r != null) r.close();
          } catch (Exception ee) {
            JDTrace.logException(this, "getSubString r.close() threw exception", ee);
          }
        }
      }

      DBLobData data = locator_.retrieveData(offset, lengthToUse);
      int actualLength = data.getLength();
      return converter_.byteArrayToString(data.getRawBytes(), data.getOffset(), actualLength);
    }
  }
  /**
   * Truncates this CLOB to a length of <i>lengthOfCLOB</i> characters.
   *
   * @param lengthOfCLOB The length, in characters, that this CLOB should be after truncation.
   * @exception SQLException If there is an error accessing the CLOB or if the length specified is
   *     greater than the length of the CLOB.
   */
  public void truncate(long lengthOfCLOB) throws SQLException {
    if (locator_ == null) // @free
    JDError.throwSQLException(this, JDError.EXC_FUNCTION_SEQUENCE); // @free

    synchronized (locator_) {
      int length = (int) lengthOfCLOB;
      if (length < 0 || length > maxLength_) {
        JDError.throwSQLException(this, JDError.EXC_ATTRIBUTE_VALUE_INVALID);
      }
      // truncate_ = length;

      // The host server does not currently provide a way for us
      // to truncate the temp space used to hold the locator data,
      // so we just keep track of it ourselves.  This should work,
      // since the temp space on the system should only be valid
      // within the scope of our transaction/connection. That means
      // there's no reason to go to the system to update the data,
      // since no other process can get at it.
      locator_.writeData(length, new byte[0], 0, 0, true); // @k1A
    }
  }
  /**
   * Get the locator handle corresponding to this ClobLocator
   *
   * @throws SQLException
   */
  public int getLocator() throws SQLException {
    if (locator_ == null) // @free
    JDError.throwSQLException(this, JDError.EXC_FUNCTION_SEQUENCE); // @free

    return locator_.getHandle();
  }
Example #16
0
  // This method actually writes the data to the system.
  private void writeToServer() throws SQLException {
    if (savedObject_ instanceof byte[]) {
      byte[] bytes = (byte[]) savedObject_;
      locator_.writeData(0, bytes, true); // @K1A
    } else if (savedObject_ instanceof InputStream) {
      int length = scale_; // hack to get the length into the set method

      // Need to write even if there are 0 bytes in case we are batching and
      // the host server reuses the same handle for the previous locator; otherwise,
      // we'll have data in the current row from the previous row.
      if (length == 0) {
        locator_.writeData(0, new byte[0], 0, 0, true); // @K1A
      } else if (length > 0) {
        InputStream stream = (InputStream) savedObject_;
        int blockSize =
            length < AS400JDBCPreparedStatement.LOB_BLOCK_SIZE
                ? length
                : AS400JDBCPreparedStatement.LOB_BLOCK_SIZE;
        byte[] byteBuffer = new byte[blockSize];
        try {
          int totalBytesRead = 0;
          int bytesRead = stream.read(byteBuffer, 0, blockSize);
          while (bytesRead > -1 && totalBytesRead < length) {
            locator_.writeData(
                totalBytesRead,
                byteBuffer,
                0,
                bytesRead,
                true); // totalBytesRead is our offset.  @K1A
            totalBytesRead += bytesRead;
            int bytesRemaining = length - totalBytesRead;
            if (bytesRemaining < blockSize) {
              blockSize = bytesRemaining;
            }
            bytesRead = stream.read(byteBuffer, 0, blockSize);
          }

          if (totalBytesRead < length) {
            // a length longer than the stream was specified
            JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
          }
        } catch (IOException ie) {
          JDError.throwSQLException(this, JDError.EXC_INTERNAL, ie);
        }
      } else if (length == -2) // @readerlen new else-if block (read all data)
      {
        InputStream stream = (InputStream) savedObject_;
        int blockSize = AS400JDBCPreparedStatement.LOB_BLOCK_SIZE;
        byte[] byteBuffer = new byte[blockSize];
        try {
          int totalBytesRead = 0;
          int bytesRead = stream.read(byteBuffer, 0, blockSize);
          while (bytesRead > -1) {
            locator_.writeData(
                totalBytesRead,
                byteBuffer,
                0,
                bytesRead,
                true); // totalBytesRead is our offset.  @K1A
            totalBytesRead += bytesRead;

            bytesRead = stream.read(byteBuffer, 0, blockSize);
          }

        } catch (IOException ie) {
          JDError.throwSQLException(this, JDError.EXC_INTERNAL, ie);
        }
      } else {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
      }
    } else if (JDUtilities.JDBCLevel_ >= 20
        && savedObject_ instanceof Blob) // @H0A check for jdbc level to know if lobs exist
    {
      // @A1C
      // @G5A Start new code for updateable locator case to go through the Vectors
      // @G5A and update the blob copy when ResultSet.updateBlob() is called.
      boolean set = false;
      if (savedObject_ instanceof AS400JDBCBlobLocator) {
        AS400JDBCBlobLocator blob = (AS400JDBCBlobLocator) savedObject_;

        // Synchronize on a lock so that the user can't keep making updates
        // to the blob while we are taking updates off the vectors.
        synchronized (blob) {
          // See if we saved off our real object from earlier.
          if (blob.savedObject_ != null) {
            savedObject_ = blob.savedObject_;
            scale_ = blob.savedScale_;
            blob.savedObject_ = null;
            writeToServer();
            return;
          }
        }
      }

      // @G5A If the code for updateable lob locators did not run, then run old code.
      if (!set) {
        Blob blob = (Blob) savedObject_; // @A1C
        int length = (int) blob.length();
        byte[] data = blob.getBytes(1, length);
        locator_.writeData(0, data, 0, length, true); // @K1A
      }
    } else {
      JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
    }
  }
 public void setHandle(int handle) {
   locator_.setHandle(handle);
   // @J5A reset savedObject after setting handle
   savedObject_ = null;
 }
Example #18
0
 public void convertFromRawBytes(byte[] rawBytes, int offset, ConvTable ccsidConverter)
     throws SQLException {
   int locatorHandle = BinaryConverter.byteArrayToInt(rawBytes, offset);
   locator_.setHandle(locatorHandle);
   locator_.setColumnIndex(columnIndex_);
 }
Example #19
0
 // @loch
 public int getHandle() {
   return locator_.getHandle();
 }
Example #20
0
 public void setHandle(int handle) {
   locator_.setHandle(handle);
 }
Example #21
0
  // @loch method to temporary convert from object input to output before even going to host
  // (writeToServer() does the conversion needed before writing to host)
  // This will only be used when resultSet.updateX(obj1) is called followed by a obj2 =
  // resultSet.getX()
  // Purpose is to do a local type conversion from obj1 to obj2 like other non-locator lob types
  private void doConversion() throws SQLException {
    int length_ = scale_;

    if (length_ == -1) {
      try {
        // try to get length from locator
        length_ = (int) locator_.getLength();
      } catch (Exception e) {
      }
    }

    try {
      Object object = savedObject_;
      if (savedObject_ instanceof String) {
        value_ = (String) object;
      } else if (object instanceof Reader) {
        if (length_ >= 0) {
          try {
            int blockSize =
                length_ < AS400JDBCPreparedStatement.LOB_BLOCK_SIZE
                    ? length_
                    : AS400JDBCPreparedStatement.LOB_BLOCK_SIZE;
            Reader stream = (Reader) object;
            StringBuffer buf = new StringBuffer();
            char[] charBuffer = new char[blockSize];
            int totalCharsRead = 0;
            int charsRead = stream.read(charBuffer, 0, blockSize);
            while (charsRead > -1 && totalCharsRead < length_) {
              buf.append(charBuffer, 0, charsRead);
              totalCharsRead += charsRead;
              int charsRemaining = length_ - totalCharsRead;
              if (charsRemaining < blockSize) {
                blockSize = charsRemaining;
              }
              charsRead = stream.read(charBuffer, 0, blockSize);
            }
            value_ = buf.toString();

            if (value_.length() < length_) {
              // a length longer than the stream was specified
              JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
            }
          } catch (IOException ie) {
            JDError.throwSQLException(this, JDError.EXC_INTERNAL, ie);
          }
        } else if (length_ == -2) // @readerlen new else-if block (read all data)
        {
          try {
            int blockSize = AS400JDBCPreparedStatement.LOB_BLOCK_SIZE;
            Reader stream = (Reader) object;
            StringBuffer buf = new StringBuffer();
            char[] charBuffer = new char[blockSize];
            int totalCharsRead = 0;
            int charsRead = stream.read(charBuffer, 0, blockSize);
            while (charsRead > -1) {
              buf.append(charBuffer, 0, charsRead);
              totalCharsRead += charsRead;
              charsRead = stream.read(charBuffer, 0, blockSize);
            }
            value_ = buf.toString();

          } catch (IOException ie) {
            JDError.throwSQLException(this, JDError.EXC_INTERNAL, ie);
          }
        } else {
          JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        }
      } else if (object instanceof Clob) {
        Clob clob = (Clob) object;
        value_ = clob.getSubString(1, (int) clob.length());
      }
      /* ifdef JDBC40
       else if( object instanceof SQLXML )
       {
           SQLXML xml = (SQLXML)object;
           value_ = xml.getString();
       }
      endif */
      else {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
      }

      // Truncate if necessary.
      int valueLength = value_.length();
      if (valueLength > maxLength_) {
        value_ = value_.substring(0, maxLength_);
      }
    } finally {
      // nothing
    }
  }
Example #22
0
  private void writeToServer() throws SQLException {
    try {
      Object object = savedObject_;
      if (object instanceof String) {
        String string = (String) object;
        int bidiStringType = settings_.getBidiStringType();
        if (bidiStringType == -1) bidiStringType = converter_.bidiStringType_;

        BidiConversionProperties bidiConversionProperties =
            new BidiConversionProperties(bidiStringType); // @KBA
        bidiConversionProperties.setBidiImplicitReordering(
            settings_.getBidiImplicitReordering()); // @KBA
        bidiConversionProperties.setBidiNumericOrderingRoundTrip(
            settings_.getBidiNumericOrdering()); // @KBA

        byte[] bytes =
            converter_.stringToByteArray(
                string,
                bidiConversionProperties); // @KBC changed to use bidiConversionProperties instead
                                           // of bidiStringType
        locator_.writeData(0L, bytes, true); // @K1C
      } else if (object instanceof Reader) {
        int length = scale_; // hack to get the length into the set method
        // Need to write even if there are 0 bytes in case we are batching and
        // the host server reuses the same handle for the previous locator; otherwise,
        // we'll have data in the current row from the previous row.
        if (length == 0) {
          locator_.writeData(0, new byte[0], 0, 0, true); // @K1C
        } else if (length > 0) {
          try {
            int blockSize =
                length < AS400JDBCPreparedStatement.LOB_BLOCK_SIZE
                    ? length
                    : AS400JDBCPreparedStatement.LOB_BLOCK_SIZE;
            int bidiStringType = settings_.getBidiStringType();
            if (bidiStringType == -1) bidiStringType = converter_.bidiStringType_;

            BidiConversionProperties bidiConversionProperties =
                new BidiConversionProperties(bidiStringType); // @KBA
            bidiConversionProperties.setBidiImplicitReordering(
                settings_.getBidiImplicitReordering()); // @KBA
            bidiConversionProperties.setBidiNumericOrderingRoundTrip(
                settings_.getBidiNumericOrdering()); // @KBA

            ReaderInputStream stream =
                new ReaderInputStream(
                    (Reader) savedObject_,
                    converter_.getCcsid(),
                    bidiConversionProperties,
                    blockSize); // @KBC changed to use bidiConversionProperties instead of
                                // bidiStringType
            byte[] byteBuffer = new byte[blockSize];
            int totalBytesRead = 0;
            int bytesRead = stream.read(byteBuffer, 0, blockSize);
            while (bytesRead > -1 && totalBytesRead < length) {
              locator_.writeData(
                  (long) totalBytesRead,
                  byteBuffer,
                  0,
                  bytesRead,
                  true); // totalBytesRead is our offset.  @K1C
              totalBytesRead += bytesRead;
              int bytesRemaining = length - totalBytesRead;
              if (bytesRemaining < blockSize) {
                blockSize = bytesRemaining;
                if (stream.available() == 0 && blockSize != 0) {
                  stream.close(); // @scan1
                  stream =
                      new ReaderInputStream(
                          (Reader) savedObject_,
                          converter_.getCcsid(),
                          bidiConversionProperties,
                          blockSize); // do this so we don't read more chars out of the Reader than
                                      // we have to. //@KBC changed to use bidiConversionProperties
                                      // instead of bidiStringType
                }
              }
              bytesRead = stream.read(byteBuffer, 0, blockSize);
            }
            stream.close(); // @scan1

            if (totalBytesRead < length) {
              // a length longer than the stream was specified
              JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
            }

          } catch (IOException ie) {
            JDError.throwSQLException(this, JDError.EXC_INTERNAL, ie);
          }
        } else if (length == -2) // @readerlen new else-if block (read all data)
        {
          try {
            // String readerStr = JDUtilities.readerToString((Reader)savedObject_);
            int blockSize = AS400JDBCPreparedStatement.LOB_BLOCK_SIZE;
            int bidiStringType = settings_.getBidiStringType();
            if (bidiStringType == -1) bidiStringType = converter_.bidiStringType_;

            BidiConversionProperties bidiConversionProperties =
                new BidiConversionProperties(bidiStringType); // @KBA
            bidiConversionProperties.setBidiImplicitReordering(
                settings_.getBidiImplicitReordering()); // @KBA
            bidiConversionProperties.setBidiNumericOrderingRoundTrip(
                settings_.getBidiNumericOrdering()); // @KBA

            ReaderInputStream stream =
                new ReaderInputStream(
                    (Reader) savedObject_,
                    converter_.getCcsid(),
                    bidiConversionProperties,
                    blockSize); // @KBC changed to use bidiConversionProperties instead of
                                // bidiStringType
            byte[] byteBuffer = new byte[blockSize];
            int totalBytesRead = 0;
            int bytesRead = stream.read(byteBuffer, 0, blockSize);
            while (bytesRead > -1) {
              locator_.writeData(
                  (long) totalBytesRead,
                  byteBuffer,
                  0,
                  bytesRead,
                  true); // totalBytesRead is our offset.  @K1C
              totalBytesRead += bytesRead;
              bytesRead = stream.read(byteBuffer, 0, blockSize);
            }
            stream.close(); // @scan1

          } catch (IOException ie) {
            JDError.throwSQLException(this, JDError.EXC_INTERNAL, ie);
          }
        } else {
          JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        }
      } else if (object instanceof InputStream) {
        int length = scale_; // hack to get the length into the set method
        // Need to write even if there are 0 bytes in case we are batching and
        // the host server reuses the same handle for the previous locator; otherwise,
        // we'll have data in the current row from the previous row.
        if (length == 0) {
          locator_.writeData(0, new byte[0], 0, 0, true); // @K1C
        } else if (length > 0) {
          InputStream stream = (InputStream) savedObject_;
          int blockSize =
              length < AS400JDBCPreparedStatement.LOB_BLOCK_SIZE
                  ? length
                  : AS400JDBCPreparedStatement.LOB_BLOCK_SIZE;
          byte[] byteBuffer = new byte[blockSize];
          try {
            int totalBytesRead = 0;
            int bytesRead = stream.read(byteBuffer, 0, blockSize);
            while (bytesRead > -1 && totalBytesRead < length) {
              locator_.writeData(
                  (long) totalBytesRead,
                  byteBuffer,
                  0,
                  bytesRead,
                  true); // totalBytesRead is our offset.  @K1C
              totalBytesRead += bytesRead;
              int bytesRemaining = length - totalBytesRead;
              if (bytesRemaining < blockSize) {
                blockSize = bytesRemaining;
              }
              bytesRead = stream.read(byteBuffer, 0, blockSize);
            }

            if (totalBytesRead < length) {
              // a length longer than the stream was specified
              JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
            }

          } catch (IOException ie) {
            JDError.throwSQLException(this, JDError.EXC_INTERNAL, ie);
          }
        } else if (length == -2) // @readerlen new else-if block (read all data)
        {
          InputStream stream = (InputStream) savedObject_;
          int blockSize = AS400JDBCPreparedStatement.LOB_BLOCK_SIZE;
          byte[] byteBuffer = new byte[blockSize];
          try {
            int totalBytesRead = 0;
            int bytesRead = stream.read(byteBuffer, 0, blockSize);
            while (bytesRead > -1) {
              locator_.writeData(
                  (long) totalBytesRead,
                  byteBuffer,
                  0,
                  bytesRead,
                  true); // totalBytesRead is our offset.  @K1C
              totalBytesRead += bytesRead;

              bytesRead = stream.read(byteBuffer, 0, blockSize);
            }
          } catch (IOException ie) {
            JDError.throwSQLException(this, JDError.EXC_INTERNAL, ie);
          }
        } else {
          JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        }
      } else if (JDUtilities.JDBCLevel_ >= 20
          && object instanceof Clob) // @H0A check for jdbc level to know if lobs exist
      {
        // @G5A Start new code for updateable locator case
        boolean set = false;
        if (object instanceof AS400JDBCClobLocator) {
          AS400JDBCClobLocator clob = (AS400JDBCClobLocator) object;

          // Synchronize on a lock so that the user can't keep making updates
          // to the clob while we are taking updates off the vectors.
          synchronized (clob) {
            // See if we saved off our real object from earlier.
            if (clob.savedObject_ != null) {
              savedObject_ = clob.savedObject_;
              scale_ = clob.savedScale_;
              clob.savedObject_ = null;
              writeToServer();
              return;
            }
          }
        }

        // @G5A If the code for updateable lob locators did not run, then run old code.
        if (!set) {
          Clob clob = (Clob) object;
          int length = (int) clob.length();
          String substring = clob.getSubString(1, length);
          locator_.writeData(0L, converter_.stringToByteArray(substring), 0, length, true); // @K1C
          set = true;
        } else {
          JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
        }
      }
      /*ifdef JDBC40
      else if( object instanceof SQLXML ) //@PDA jdbc40
      {
          SQLXML xml = (SQLXML)object;

          String stringVal = xml.getString();
          locator_.writeData(0L, converter_.stringToByteArray(stringVal), 0, stringVal.length(), true);
      }
      endif */
      else {
        JDError.throwSQLException(this, JDError.EXC_DATA_TYPE_MISMATCH);
      }
    } finally {
      savedObject_ = null;
    }
    scale_ = (int) locator_.getLength();
  }