Added: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java?rev=165178&view=auto ============================================================================== --- incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java (added) +++ incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java Thu Apr 28 12:05:42 2005 @@ -0,0 +1,1153 @@ +/* + + Derby - Class org.apache.derby.client.am.Cursor + + Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.apache.derby.client.am; + +// When we calculate column offsets make sure we calculate the correct offsets for double byte charactr5er data +// length from server is number of chars, not bytes +// Direct byte-level converters are called directly by this class, cross converters are deferred to the CrossConverters class. +public abstract class Cursor +{ + protected Agent agent_; + + //-----------------------------varchar representations------------------------ + + public final static int STRING = 0; + public final static int VARIABLE_STRING = 2; // uses a 2-byte length indicator + public final static int VARIABLE_SHORT_STRING = 1; // aka Pascal L; uses a 1-byte length indicator + public final static int NULL_TERMINATED_STRING = 3; + + public final static int BYTES = 4; + public final static int VARIABLE_BYTES = 5; + public final static int VARIABLE_SHORT_BYTES = 6; + public final static int NULL_TERMINATED_BYTES = 7; + + public final static int SBCS_CLOB = 8; + public final static int MBCS_CLOB = 9; + public final static int DBCS_CLOB = 10; + //-----------------------------internal state--------------------------------- + + //-------------Structures for holding and scrolling the data ----------------- + public byte[] dataBuffer_; + public java.io.ByteArrayOutputStream dataBufferStream_; + public int position_; // This is the read head + public int lastValidBytePosition_; + public boolean hasLobs_; // is there at least one LOB column? + + // Current row positioning + protected int currentRowPosition_; + private int nextRowPosition_; + // Let's new up a 2-dimensional array based on fetch-size and reuse so that + protected int[] columnDataPosition_; + + // This is the actual, computed lengths of varchar fields, not the max length from query descriptor or DA + protected int[] columnDataComputedLength_; + // populate this for + + // All the data is in the buffers, but user may not have necessarily stepped to the last row yet. + // This flag indicates that the server has returned all the rows, and is positioned + // after last, for both scrollable and forward-only cursors. + // For singleton cursors, this memeber will be set to true as soon as next is called. + public boolean allRowsReceivedFromServer_; + + // Total number of rows read so far. + // This should never exceed this.statement.maxRows + int rowsRead_; + + // Maximum column size limit in bytes. + int maxFieldSize_ = 0; + + // Row positioning for all cached rows + // For scrollable result sets, these lists hold the offsets into the cached rowset buffer for each row of data. + protected java.util.ArrayList columnDataPositionCache_ = new java.util.ArrayList(); + protected java.util.ArrayList columnDataLengthCache_ = new java.util.ArrayList(); + protected java.util.ArrayList columnDataIsNullCache_ = new java.util.ArrayList(); + public java.util.ArrayList isUpdateDeleteHoleCache_ = new java.util.ArrayList(); + public boolean isUpdateDeleteHole_; + final static public java.lang.Boolean ROW_IS_NULL = new Boolean (true); + final static public java.lang.Boolean ROW_IS_NOT_NULL = new Boolean (false); + + java.sql.Date recyclableDate_ = null; + java.sql.Time recyclableTime_ = null; + java.sql.Timestamp recyclableTimestamp_ = null; + + // For the net, this data comes from the query descriptor. + + public int[] jdbcTypes_; + public int columns_; + public boolean[] nullable_; + public String[] charsetName_; + public boolean[] isNull_; + public int[] fdocaLength_; // this is the max length for + + //---------------------------------------------------------------------------- + + public int [] ccsid_; + char[] charBuffer_; + + //---------------------constructors/finalizer--------------------------------- + + public Cursor (Agent agent) + { + agent_ = agent; + dataBufferStream_ = new java.io.ByteArrayOutputStream (); + } + + public Cursor (Agent agent, byte[] dataBuffer) + { + this (agent); + dataBuffer_ = dataBuffer; + allRowsReceivedFromServer_ = false; + } + + public void setNumberOfColumns (int numberOfColumns) + { + columnDataPosition_ = new int[numberOfColumns]; + columnDataComputedLength_ = new int[numberOfColumns]; + + columns_ = numberOfColumns; + nullable_ = new boolean[numberOfColumns]; + charsetName_ = new String[numberOfColumns]; + + ccsid_ = new int [numberOfColumns]; + + isNull_ = new boolean[numberOfColumns]; + jdbcTypes_ = new int[numberOfColumns]; + } + + // Makes the next row the current row. + // Returns true if the current row position is a valid row position. + public boolean next () throws SqlException + { + // local variable usd to hold the returned value from calculateColumnOffsetsForRow() + boolean rowPositionIsValid = true; + + // reset lob data + // clears out Cursor.lobs_ calculated for the current row when cursor is moved. + clearLobData_ (); + + // mark the start of a new row. + makeNextRowPositionCurrent (); + + // Drive the CNTQRY outside of calculateColumnOffsetsForRow() if the dataBuffer_ + // contains no data since it has no abilities to handle replies other than + // the QRYDTA, i.e. ENDQRYRM when the result set contains no more rows. + while (!dataBufferHasUnprocessedData()) { + if (allRowsReceivedFromServer_) + return false; + getMoreData_(); + } + + // The parameter passed in here is used as an index into the cached rowset for + // scrollable cursors, for the arrays to be reused. It is not used for forward-only + // cursors, so just pass in 0. + rowPositionIsValid = calculateColumnOffsetsForRow_(0); // readFetchedRows() + markNextRowPosition (); + return rowPositionIsValid; + } + + //--------------------------reseting cursor state----------------------------- + + public final void setAllRowsReceivedFromServer (boolean b) + { + allRowsReceivedFromServer_ = b; + } + + public final boolean currentRowPositionIsEqualToNextRowPosition () + { + return (currentRowPosition_ == nextRowPosition_); + } + + // reset the beginning and ending position in the data buffer to 0 + // reset the currentRowPosition and nextRowPosition to 0 + // reset lastRowReached and sqlcode100Received to false + // clear the column data offsets cache + public final void resetDataBuffer () + { + position_ = 0; + lastValidBytePosition_ = 0; + currentRowPosition_ = 0; + nextRowPosition_ = 0; + allRowsReceivedFromServer_ = false; + dataBufferStream_.reset(); + } + + public final boolean dataBufferHasUnprocessedData () + { + return (lastValidBytePosition_ - position_) > 0; + } + + protected abstract boolean calculateColumnOffsetsForRow_ (int row) throws SqlException, DisconnectException; + protected abstract void clearLobData_(); + protected abstract void getMoreData_() throws SqlException; + + // Associate a new underlying COM or SQLDA output data buffer for this converter. + public final void setBuffer (byte[] dataBuffer) + { + dataBuffer_ = dataBuffer; + } + + public final void setIsUpdataDeleteHole (int row, boolean isRowNull) + { + isUpdateDeleteHole_ = isRowNull; + Boolean nullIndicator = (isUpdateDeleteHole_ == true) ? ROW_IS_NULL : ROW_IS_NOT_NULL; + if (isUpdateDeleteHoleCache_.size() == row) + isUpdateDeleteHoleCache_.add (nullIndicator); + else + isUpdateDeleteHoleCache_.set (row, nullIndicator); + } + //---------------------------cursor positioning------------------------------- + + final int getPosition () + { + return position_; + } + + final void setPosition (int newPosition) + { + position_ = newPosition; + } + + public final void markCurrentRowPosition () + { + currentRowPosition_ = position_; + } + + public final void markNextRowPosition () + { + nextRowPosition_ = position_; + } + + public final void makeNextRowPositionCurrent () + { + currentRowPosition_ = nextRowPosition_; + } + + final void repositionCursorToCurrentRow () + { + position_ = currentRowPosition_; + } + + final void repositionCursorToNextRow () + { + position_ = nextRowPosition_; + } + + public final byte[] getDataBuffer () + { + return dataBuffer_; + } + + public final int getDataBufferLength() + { + return dataBuffer_.length; + } + + public final int getLastValidBytePosition () + { + return lastValidBytePosition_; + } + + // This tracks the total number of rows read into the client side buffer for + // this result set, irregardless of scrolling. + // Per jdbc semantics, this should never exceed statement.maxRows. + // This event should be generated in the materialized cursor's implementation + // of calculateColumnOffsetsForRow(). + public final void incrementRowsReadEvent() + { + rowsRead_++; + } + + //------- the following getters are called on known column types ------------- + // Direct conversions only, cross conversions are handled by another set of getters. + + // Build a Java short from a 2-byte signed binary representation. + private final short get_SMALLINT (int column) + { + return org.apache.derby.client.am.SignedBinary.getShort (dataBuffer_, + columnDataPosition_[column-1]); + } + + // Build a Java int from a 4-byte signed binary representation. + private final int get_INTEGER (int column) + { + return org.apache.derby.client.am.SignedBinary.getInt (dataBuffer_, + columnDataPosition_[column-1]); + } + + // Build a Java long from an 8-byte signed binary representation. + private final long get_BIGINT (int column) + { + return org.apache.derby.client.am.SignedBinary.getLong (dataBuffer_, + columnDataPosition_[column-1]); + } + + // Build a Java float from a 4-byte floating point representation. + private final float get_FLOAT (int column) + { + return org.apache.derby.client.am.FloatingPoint.getFloat (dataBuffer_, + columnDataPosition_[column-1]); + } + + // Build a Java double from an 8-byte floating point representation. + private final double get_DOUBLE (int column) + { + return org.apache.derby.client.am.FloatingPoint.getDouble (dataBuffer_, + columnDataPosition_[column-1]); + } + + // Build a java.math.BigDecimal from a fixed point decimal byte representation. + private final java.math.BigDecimal get_DECIMAL (int column) throws SqlException + { + try { + return org.apache.derby.client.am.Decimal.getBigDecimal (dataBuffer_, + columnDataPosition_[column-1], + getColumnPrecision (column-1), + getColumnScale (column-1)); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e, "Encoding is unsupported for conversion to BigDecimal"); + } + } + + + // Build a Java double from a fixed point decimal byte representation. + private final double getDoubleFromDECIMAL (int column) throws SqlException + { + try { + return org.apache.derby.client.am.Decimal.getDouble (dataBuffer_, + columnDataPosition_[column-1], + getColumnPrecision (column-1), + getColumnScale (column-1)); + } + catch (java.lang.IllegalArgumentException e) { + throw new SqlException (agent_.logWriter_, e, "Decimal value is out of range for conversion to double"); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e, "Encoding is unsupported for conversion to BigDecimal"); + } + } + + // Build a Java long from a fixed point decimal byte representation. + private final long getLongFromDECIMAL (int column) throws SqlException + { + try { + return org.apache.derby.client.am.Decimal.getLong (dataBuffer_, + columnDataPosition_[column-1], + getColumnPrecision (column-1), + getColumnScale (column-1)); + } + catch (java.lang.IllegalArgumentException e) { + throw new SqlException (agent_.logWriter_, e, "Decimal value is out of range for conversion to long"); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e, "Encoding is unsupported for conversion to BigDecimal"); + } + } + + // Build a Java String from a database VARCHAR or LONGVARCHAR field. + // + // Depending on the ccsid, length is the number of chars or number of bytes. + // For 2-byte character ccsids, length is the number of characters, + // for all other cases length is the number of bytes. + // The length does not include the null terminator. + private final String getVARCHAR (int column) throws SqlException + { + String tempString = null; + try { + if(ccsid_[column-1] == 1200) + return getStringWithoutConvert (columnDataPosition_[column-1] + 2, columnDataComputedLength_[column-1] - 2 ); + + // check for null encoding is needed because the net layer + // will no longer throw an exception if the server didn't specify + // a mixed or double byte ccsid (ccsid = 0). this check for null in the + // cursor is only required for types which can have mixed or double + // byte ccsids. + if (charsetName_[column-1] == null) + throw new SqlException (agent_.logWriter_, + "Required character converter not available for data type."); + + tempString = new String (dataBuffer_, + columnDataPosition_[column-1] + 2, + columnDataComputedLength_[column-1] - 2, + charsetName_[column-1]); + return (maxFieldSize_ == 0) ? tempString : + tempString.substring(0, java.lang.Math.min (maxFieldSize_, tempString.length())); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e, "unsupported encoding for result set column " + column); + } + } + + // Build a Java String from a database CHAR field. + private final String getCHAR (int column) throws SqlException + { + String tempString = null; + if (ccsid_[column - 1] == 1200) + return getStringWithoutConvert(columnDataPosition_[column - 1], columnDataComputedLength_[column - 1]); + + try { + // check for null encoding is needed because the net layer + // will no longer throw an exception if the server didn't specify + // a mixed or double byte ccsid (ccsid = 0). this check for null in the + // cursor is only required for types which can have mixed or double + // byte ccsids. + if (charsetName_[column-1] == null) + throw new SqlException (agent_.logWriter_, + "Required character converter not available for data type."); + + tempString = new String (dataBuffer_, + columnDataPosition_[column-1], + columnDataComputedLength_[column-1], + charsetName_[column-1]); + return (maxFieldSize_ == 0) ? tempString : + tempString.substring(0, java.lang.Math.min (maxFieldSize_, tempString.length())); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e, "unsupported encoding for result set column " + column); + } + } + + // Build a JDBC Date object from the DERBY ISO DATE field. + private final java.sql.Date getDATE (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.dateBytesToDate (dataBuffer_, + columnDataPosition_[column-1], + recyclableDate_); + } + + // Build a JDBC Time object from the DERBY ISO TIME field. + private final java.sql.Time getTIME (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.timeBytesToTime (dataBuffer_, + columnDataPosition_[column-1], + recyclableTime_); + } + + // Build a JDBC Timestamp object from the DERBY ISO TIMESTAMP field. + private final java.sql.Timestamp getTIMESTAMP (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.timestampBytesToTimestamp (dataBuffer_, + columnDataPosition_[column-1], + recyclableTimestamp_); + } + + // Build a JDBC Timestamp object from the DERBY ISO DATE field. + private final java.sql.Timestamp getTimestampFromDATE (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.dateBytesToTimestamp (dataBuffer_, + columnDataPosition_[column-1], + recyclableTimestamp_); + } + + // Build a JDBC Timestamp object from the DERBY ISO TIME field. + private final java.sql.Timestamp getTimestampFromTIME (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.timeBytesToTimestamp (dataBuffer_, + columnDataPosition_[column-1], + recyclableTimestamp_); + } + + // Build a JDBC Date object from the DERBY ISO TIMESTAMP field. + private final java.sql.Date getDateFromTIMESTAMP (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.timestampBytesToDate (dataBuffer_, + columnDataPosition_[column-1], + recyclableDate_); + } + + // Build a JDBC Time object from the DERBY ISO TIMESTAMP field. + private final java.sql.Time getTimeFromTIMESTAMP (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.timestampBytesToTime (dataBuffer_, + columnDataPosition_[column-1], + recyclableTime_); + } + + private final String getStringFromDATE (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.dateBytesToDate ( + dataBuffer_, + columnDataPosition_[column-1], + recyclableDate_).toString(); + } + + // Build a string object from the DERBY byte TIME representation. + private final String getStringFromTIME (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.timeBytesToTime ( + dataBuffer_, + columnDataPosition_[column-1], + recyclableTime_).toString(); + } + + // Build a string object from the DERBY byte TIMESTAMP representation. + private final String getStringFromTIMESTAMP (int column) throws SqlException + { + return org.apache.derby.client.am.DateTime.timestampBytesToTimestamp ( + dataBuffer_, + columnDataPosition_[column-1], + recyclableTimestamp_).toString(); + } + + // Extract bytes from a database java.sql.Types.BINARY field. + // This is the DERBY type CHAR(n) FOR BIT DATA. + private final byte[] get_CHAR_FOR_BIT_DATA (int column) throws SqlException + { + // There is no limit to the size of a column if maxFieldSize is zero. + // Otherwise, use the smaller of maxFieldSize and the actual column length. + int columnLength = (maxFieldSize_ == 0) ? columnDataComputedLength_[column-1] : + java.lang.Math.min (maxFieldSize_, columnDataComputedLength_[column-1]); + + byte[] bytes = new byte[columnLength]; + System.arraycopy (dataBuffer_, columnDataPosition_[column-1], bytes, 0, columnLength); + return bytes; + } + + // Extract bytes from a database java.sql.Types.VARBINARY or LONGVARBINARY field. + // This includes the DERBY types: + // VARCHAR(n) FOR BIT DATA + // LONG VARCHAR(n) FOR BIT DATA + private final byte[] get_VARCHAR_FOR_BIT_DATA (int column) throws SqlException + { + byte[] bytes; + int columnLength = 0; + columnLength = (maxFieldSize_ == 0) ? columnDataComputedLength_[column-1]-2 : + java.lang.Math.min (maxFieldSize_, columnDataComputedLength_[column-1]-2); + bytes = new byte[columnLength]; + System.arraycopy (dataBuffer_, columnDataPosition_[column-1] + 2, bytes, 0, bytes.length); + return bytes; + } + + abstract public Blob getBlobColumn_ (int column, Agent agent) throws SqlException; + abstract public Clob getClobColumn_ (int column, Agent agent) throws SqlException; + + // get the raw clob bytes, without translation. dataOffset must be int[1] + abstract public byte[] getClobBytes_ (int column, int[] dataOffset /*output*/) throws SqlException; + + //------- the following getters perform any necessary cross-conversion _------ + + final boolean getBoolean (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.SMALLINT: + return agent_.crossConverters_.getBooleanFromShort (get_SMALLINT (column)); + case java.sql.Types.INTEGER: + return agent_.crossConverters_.getBooleanFromInt (get_INTEGER (column)); + case java.sql.Types.BIGINT: + return agent_.crossConverters_.getBooleanFromLong (get_BIGINT (column)); + case java.sql.Types.REAL: + return agent_.crossConverters_.getBooleanFromFloat (get_FLOAT (column)); + case java.sql.Types.DOUBLE: + return agent_.crossConverters_.getBooleanFromDouble (get_DOUBLE (column)); + case java.sql.Types.DECIMAL: + // For performance we don't materialize the BigDecimal, but convert directly from decimal bytes to a long. + return agent_.crossConverters_.getBooleanFromLong (getLongFromDECIMAL (column)); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getBooleanFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getBooleanFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final byte getByte (int column) throws SqlException + { + // This needs to be changed to use jdbcTypes[] + switch (jdbcTypes_[column-1]) { + case java.sql.Types.SMALLINT: + return agent_.crossConverters_.getByteFromShort (get_SMALLINT (column)); + case java.sql.Types.INTEGER: + return agent_.crossConverters_.getByteFromInt (get_INTEGER (column)); + case java.sql.Types.BIGINT: + return agent_.crossConverters_.getByteFromLong (get_BIGINT (column)); + case java.sql.Types.REAL: + return agent_.crossConverters_.getByteFromFloat (get_FLOAT (column)); + case java.sql.Types.DOUBLE: + return agent_.crossConverters_.getByteFromDouble (get_DOUBLE (column)); + case java.sql.Types.DECIMAL: + // For performance we don't materialize the BigDecimal, but convert directly from decimal bytes to a long. + return agent_.crossConverters_.getByteFromLong (getLongFromDECIMAL (column)); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getByteFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getByteFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final short getShort (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.SMALLINT: + return get_SMALLINT (column); + case java.sql.Types.INTEGER: + return agent_.crossConverters_.getShortFromInt (get_INTEGER (column)); + case java.sql.Types.BIGINT: + return agent_.crossConverters_.getShortFromLong (get_BIGINT (column)); + case java.sql.Types.REAL: + return agent_.crossConverters_.getShortFromFloat (get_FLOAT (column)); + case java.sql.Types.DOUBLE: + return agent_.crossConverters_.getShortFromDouble (get_DOUBLE (column)); + case java.sql.Types.DECIMAL: + // For performance we don't materialize the BigDecimal, but convert directly from decimal bytes to a long. + return agent_.crossConverters_.getShortFromLong (getLongFromDECIMAL (column)); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getShortFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getShortFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final int getInt (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.SMALLINT: + return (int) get_SMALLINT (column); + case java.sql.Types.INTEGER: + return get_INTEGER (column); + case java.sql.Types.BIGINT: + return agent_.crossConverters_.getIntFromLong (get_BIGINT (column)); + case java.sql.Types.REAL: + return agent_.crossConverters_.getIntFromFloat (get_FLOAT (column)); + case java.sql.Types.DOUBLE: + return agent_.crossConverters_.getIntFromDouble (get_DOUBLE (column)); + case java.sql.Types.DECIMAL: + // For performance we don't materialize the BigDecimal, but convert directly from decimal bytes to a long. + return agent_.crossConverters_.getIntFromLong (getLongFromDECIMAL (column)); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getIntFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getIntFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final long getLong (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.SMALLINT: + return (long) get_SMALLINT (column); + case java.sql.Types.INTEGER: + return (long) get_INTEGER (column); + case java.sql.Types.BIGINT: + return get_BIGINT (column); + case java.sql.Types.REAL: + return agent_.crossConverters_.getLongFromFloat (get_FLOAT (column)); + case java.sql.Types.DOUBLE: + return agent_.crossConverters_.getLongFromDouble (get_DOUBLE (column)); + case java.sql.Types.DECIMAL: + // For performance we don't materialize the BigDecimal, but convert directly from decimal bytes to a long. + return getLongFromDECIMAL (column); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getLongFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getLongFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final float getFloat (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.REAL: + return get_FLOAT (column); + case java.sql.Types.DOUBLE: + return agent_.crossConverters_.getFloatFromDouble (get_DOUBLE (column)); + case java.sql.Types.DECIMAL: + // For performance we don't materialize the BigDecimal, but convert directly from decimal bytes to a long. + return agent_.crossConverters_.getFloatFromDouble (getDoubleFromDECIMAL (column)); + case java.sql.Types.SMALLINT: + return (float) get_SMALLINT (column); + case java.sql.Types.INTEGER: + return (float) get_INTEGER (column); + case java.sql.Types.BIGINT: + return (float) get_BIGINT (column); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getFloatFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getFloatFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final double getDouble (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.REAL: + double d = (double) get_FLOAT (column); + return d; + //return (double) get_FLOAT (column); + case java.sql.Types.DOUBLE: + return get_DOUBLE (column); + case java.sql.Types.DECIMAL: + // For performance we don't materialize the BigDecimal, but convert directly from decimal bytes to a long. + return getDoubleFromDECIMAL (column); + case java.sql.Types.SMALLINT: + return (double) get_SMALLINT (column); + case java.sql.Types.INTEGER: + return (double) get_INTEGER (column); + case java.sql.Types.BIGINT: + return (double) get_BIGINT (column); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getDoubleFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getDoubleFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final java.math.BigDecimal getBigDecimal (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.DECIMAL: + return get_DECIMAL (column); + case java.sql.Types.REAL: + // Can't use the following commented out line because it changes precision of the result. + //return new java.math.BigDecimal (get_FLOAT (column)); + float f = get_FLOAT (column); + return new java.math.BigDecimal (String.valueOf(f)); + case java.sql.Types.DOUBLE: + // Can't use the following commented out line because it changes precision of the result. + return new java.math.BigDecimal (String.valueOf (get_DOUBLE (column))); + case java.sql.Types.SMALLINT: + return java.math.BigDecimal.valueOf (get_SMALLINT (column)); + case java.sql.Types.INTEGER: + return java.math.BigDecimal.valueOf (get_INTEGER (column)); + case java.sql.Types.BIGINT: + return java.math.BigDecimal.valueOf (get_BIGINT (column)); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getBigDecimalFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getBigDecimalFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final java.sql.Date getDate (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.DATE: + return getDATE (column); + case java.sql.Types.TIMESTAMP: + return getDateFromTIMESTAMP (column); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getDateFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getDateFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final java.sql.Time getTime (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.TIME: + return getTIME (column); + case java.sql.Types.TIMESTAMP: + return getTimeFromTIMESTAMP (column); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getTimeFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getTimeFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final java.sql.Timestamp getTimestamp (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.TIMESTAMP: + return getTIMESTAMP (column); + case java.sql.Types.DATE: + return getTimestampFromDATE (column); + case java.sql.Types.TIME: + return getTimestampFromTIME (column); + case java.sql.Types.CHAR: + return agent_.crossConverters_.getTimestampFromString (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return agent_.crossConverters_.getTimestampFromString (getVARCHAR (column)); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final String getString (int column) throws SqlException + { + String tempString = null; + switch (jdbcTypes_[column-1]) { + case java.sql.Types.CHAR: + return getCHAR (column); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return getVARCHAR (column); + + case java.sql.Types.SMALLINT: + return String.valueOf (get_SMALLINT (column)); + case java.sql.Types.INTEGER: + return String.valueOf (get_INTEGER (column)); + case java.sql.Types.BIGINT: + return String.valueOf (get_BIGINT (column)); + case java.sql.Types.REAL: + return String.valueOf (get_FLOAT (column)); + case java.sql.Types.DOUBLE: + return String.valueOf (get_DOUBLE (column)); + case java.sql.Types.DECIMAL: + // We could get better performance here if we didn't materialize the BigDecimal, + // but converted directly from decimal bytes to a string. + return String.valueOf (get_DECIMAL (column)); + case java.sql.Types.DATE: + return getStringFromDATE (column); + case java.sql.Types.TIME: + return getStringFromTIME (column); + case java.sql.Types.TIMESTAMP: + return getStringFromTIMESTAMP (column); + case Types.BINARY: + tempString = + agent_.crossConverters_.getStringFromBytes (get_CHAR_FOR_BIT_DATA (column)); + return (maxFieldSize_ == 0) ? tempString : + tempString.substring(0, java.lang.Math.min (maxFieldSize_, tempString.length())); + case java.sql.Types.VARBINARY: + case java.sql.Types.LONGVARBINARY: + tempString = + agent_.crossConverters_.getStringFromBytes (get_VARCHAR_FOR_BIT_DATA (column)); + return (maxFieldSize_ == 0) ? tempString : + tempString.substring(0, java.lang.Math.min (maxFieldSize_, tempString.length())); + case java.sql.Types.BLOB: + Blob b = (Blob) getBlobColumn_ (column, agent_); + return agent_.crossConverters_.getStringFromBytes (b.getBytes(1, (int) b.length())); + case java.sql.Types.CLOB: + Clob c = getClobColumn_ (column, agent_); + return c.getSubString (1, (int) c.length()); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + final byte[] getBytes (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.BINARY: + return get_CHAR_FOR_BIT_DATA (column); + case java.sql.Types.VARBINARY: + case java.sql.Types.LONGVARBINARY: + return get_VARCHAR_FOR_BIT_DATA (column); + case java.sql.Types.BLOB: + Blob b = (Blob) getBlobColumn_ (column, agent_); + return b.getBytes (1, (int) b.length()); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + public final java.io.InputStream getBinaryStream (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.BINARY: + return new java.io.ByteArrayInputStream (get_CHAR_FOR_BIT_DATA (column)); + case java.sql.Types.VARBINARY: + case java.sql.Types.LONGVARBINARY: + return new java.io.ByteArrayInputStream (get_VARCHAR_FOR_BIT_DATA (column)); + case java.sql.Types.BLOB: + Blob b = (Blob) getBlobColumn_ (column, agent_); + return b.getBinaryStream(); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + public final java.io.InputStream getAsciiStream (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.CLOB: + Clob c = getClobColumn_ (column, agent_); + return c.getAsciiStream(); + case java.sql.Types.CHAR: + try { + return new java.io.ByteArrayInputStream (getCHAR(column).getBytes("US-ASCII")); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e.getMessage()); + } + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + try { + return new java.io.ByteArrayInputStream (getVARCHAR(column).getBytes("US-ASCII")); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e.getMessage()); + } + case java.sql.Types.BINARY: + return new java.io.ByteArrayInputStream (get_CHAR_FOR_BIT_DATA (column)); + case java.sql.Types.VARBINARY: + case java.sql.Types.LONGVARBINARY: + return new java.io.ByteArrayInputStream (get_VARCHAR_FOR_BIT_DATA (column)); + case java.sql.Types.BLOB: + Blob b = (Blob) getBlobColumn_ (column, agent_); + return b.getBinaryStream(); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + public final java.io.InputStream getUnicodeStream (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.CLOB: { + Clob c = getClobColumn_ (column, agent_); + String s = c.getSubString (1L, (int) c.length()); + try { + return new java.io.ByteArrayInputStream (s.getBytes ("UTF-8")); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e.getMessage()); + } + } + case java.sql.Types.CHAR: { + try { + return new java.io.ByteArrayInputStream (getCHAR (column).getBytes ("UTF-8")); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e.getMessage()); + } + } + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + try { + return new java.io.ByteArrayInputStream (getVARCHAR(column).getBytes ("UTF-8")); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, e.getMessage()); + } + case java.sql.Types.BINARY: + return new java.io.ByteArrayInputStream (get_CHAR_FOR_BIT_DATA (column)); + case java.sql.Types.VARBINARY: + case java.sql.Types.LONGVARBINARY: + return new java.io.ByteArrayInputStream (get_VARCHAR_FOR_BIT_DATA (column)); + case java.sql.Types.BLOB: + Blob b = (Blob) getBlobColumn_ (column, agent_); + return b.getBinaryStream(); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + public final java.io.Reader getCharacterStream (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.CLOB: + Clob c = getClobColumn_ (column, agent_); + return c.getCharacterStream(); + case java.sql.Types.CHAR: + return new java.io.StringReader (getCHAR (column)); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return new java.io.StringReader (getVARCHAR (column)); + case java.sql.Types.BINARY: + try { + return new java.io.InputStreamReader (new java.io.ByteArrayInputStream (get_CHAR_FOR_BIT_DATA (column)), "UTF-16BE"); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, "UnsupportedEncodingException: " + e.getMessage()); + } + case java.sql.Types.VARBINARY: + case java.sql.Types.LONGVARBINARY: + try { + return new java.io.InputStreamReader (new java.io.ByteArrayInputStream (get_VARCHAR_FOR_BIT_DATA (column)), "UTF-16BE"); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, "UnsupportedEncodingException: " + e.getMessage()); + } + case java.sql.Types.BLOB: + try { + Blob b = (Blob) getBlobColumn_ (column, agent_); + return new java.io.InputStreamReader (b.getBinaryStream(), "UTF-16BE"); + } + catch (java.io.UnsupportedEncodingException e) { + throw new SqlException (agent_.logWriter_, "UnsupportedEncodingException: " + e.getMessage()); + } + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + public final java.sql.Blob getBlob (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case Types.BLOB: + return getBlobColumn_ (column, agent_); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + public final java.sql.Clob getClob (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case Types.CLOB: + return getClobColumn_ (column, agent_); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + public final java.sql.Array getArray (int column) throws SqlException + { + throw new SqlException (agent_.logWriter_, "not yet implemented"); + } + + public final java.sql.Ref getRef (int column) throws SqlException + { + throw new SqlException (agent_.logWriter_, "not yet implemented"); + } + + public final Object getObject (int column) throws SqlException + { + switch (jdbcTypes_[column-1]) { + case java.sql.Types.SMALLINT: + return new Integer (get_SMALLINT (column)); // See Table 4 in JDBC 1 spec (pg. 932 in jdbc book) + case java.sql.Types.INTEGER: + return new Integer (get_INTEGER (column)); + case java.sql.Types.BIGINT: + return new Long (get_BIGINT (column)); + case java.sql.Types.REAL: + return new Float (get_FLOAT (column)); + case java.sql.Types.DOUBLE: + return new Double (get_DOUBLE (column)); + case java.sql.Types.DECIMAL: + return get_DECIMAL (column); + case java.sql.Types.DATE: + return getDATE (column); + case java.sql.Types.TIME: + return getTIME (column); + case java.sql.Types.TIMESTAMP: + return getTIMESTAMP (column); + case java.sql.Types.CHAR: + return getCHAR (column); + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGVARCHAR: + return getVARCHAR (column); + case Types.BINARY: + return get_CHAR_FOR_BIT_DATA (column); + case java.sql.Types.VARBINARY: + case java.sql.Types.LONGVARBINARY: + return get_VARCHAR_FOR_BIT_DATA (column); + case java.sql.Types.BLOB: + return getBlobColumn_ (column, agent_); + case java.sql.Types.CLOB: + return getClobColumn_ (column, agent_); + default: + throw new ColumnTypeConversionException (agent_.logWriter_); + } + } + + public final void allocateCharBuffer () + { + // compute the maximum char length + int maxCharLength = 0; + for (int i=0; i<columns_; i++) { + switch (jdbcTypes_[i]) { + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + if (fdocaLength_[i] > maxCharLength) maxCharLength = fdocaLength_[i]; + } + } + + // allocate char buffer to accomodate largest result column + charBuffer_ = new char[maxCharLength]; + } + + private final String getStringWithoutConvert (int position, int actualLength) throws SqlException + { + int start = position; + int end = position + actualLength; + + int charCount = 0; + while (start < end) + { + charBuffer_[charCount++] = (char) (((dataBuffer_[start]&0xff)<<8) | (dataBuffer_[start+1]&0xff)); + start += 2; + } + + return new String(charBuffer_, 0, charCount); + } + + public void nullDataForGC () + { + dataBuffer_ = null; + dataBufferStream_ = null; + columnDataPosition_ = null; + columnDataComputedLength_ = null; + columnDataPositionCache_ = null; + columnDataLengthCache_ = null; + columnDataIsNullCache_ = null; + jdbcTypes_ = null; + nullable_ = null; + charsetName_ = null; + this.ccsid_ = null; + isUpdateDeleteHoleCache_ = null; + isNull_ = null; + fdocaLength_ = null; + charBuffer_ = null; + } + + private final int getColumnPrecision (int column) + { + return ((fdocaLength_[column] >> 8) & 0xff); + } + + private final int getColumnScale (int column) + { + return (fdocaLength_[column] & 0xff); + } + + // Only used by Sqlca.getMessage() when using a locale encoding + // to convert errror message text instead of relying on server encoding as usual. + final byte[] getBytesFromVARCHAR (int column) throws SqlException + { + byte[] bytes; + bytes = new byte[columnDataComputedLength_[column-1]-2]; + System.arraycopy (dataBuffer_, columnDataPosition_[column-1]+2, bytes, 0, bytes.length); + return bytes; + } +}
Propchange: incubator/derby/code/trunk/java/client/org/apache/derby/client/am/Cursor.java ------------------------------------------------------------------------------ svn:eol-style = native