boolean calculateColumnOffsetsForRow_()

in java/org.apache.derby.client/org/apache/derby/client/net/NetCursor.java [130:376]


        boolean calculateColumnOffsetsForRow_(int rowIndex,
                                              boolean allowServerFetch)
        throws SqlException, DisconnectException
    {
        int daNullIndicator = CodePoint.NULLDATA;
        int colNullIndicator = CodePoint.NULLDATA;
        int length;

        int[] columnDataPosition = null;
        int[] columnDataComputedLength = null;
        boolean[] columnDataIsNull = null;
        boolean receivedDeleteHoleWarning = false;
        boolean receivedRowUpdatedWarning = false;

        if ((position_ == lastValidBytePosition_) &&
                (netResultSet_ != null) && (netResultSet_.scrollable_)) {
            return false;
        }

        if (hasLobs_) {
            extdtaPositions_.clear();  // reset positions for this row
        }

        NetSqlca[] netSqlca = this.parseSQLCARD(qrydscTypdef_);
        // If we don't have at least one byte in the buffer for the DA null indicator,
        // then we need to send a CNTQRY request to fetch the next block of data.
        // Read the DA null indicator. Do this before we close mark the statement
        // closed on the server. DERBY-3230
        daNullIndicator = readFdocaOneByte();
        
        if (netSqlca != null) {
            for (int i=0;i<netSqlca.length; i++) {
                int sqlcode = netSqlca[i].getSqlCode();
                if (sqlcode < 0) {
                    throw new SqlException(netAgent_.logWriter_, 
                            netSqlca[i]);
                } else {
                    if (sqlcode == SqlCode.END_OF_DATA.getCode()) {
                        setAllRowsReceivedFromServer(true);
                        if (netResultSet_ != null && 
                                netSqlca[i].containsSqlcax()) {
                            netResultSet_.setRowCountEvent(
                                    netSqlca[i].getRowCount());
                        }
                    } else if (netResultSet_ != null && sqlcode > 0) {
                        String sqlState = netSqlca[i].getSqlState();
                        if (!sqlState.equals(SQLState.ROW_DELETED) && 
                                !sqlState.equals(SQLState.ROW_UPDATED)) {
                            netResultSet_.accumulateWarning(
                                    new SqlWarning(agent_.logWriter_, 
                                        netSqlca[i]));
                        } else {
                            receivedDeleteHoleWarning 
                                    |= sqlState.equals(SQLState.ROW_DELETED);
                            receivedRowUpdatedWarning 
                                    |= sqlState.equals(SQLState.ROW_UPDATED);
                        }
                    }
                }
            }
        }

        setIsUpdataDeleteHole(rowIndex, receivedDeleteHoleWarning);
        setIsRowUpdated(receivedRowUpdatedWarning);
        
        

        // In the case for held cursors, the +100 comes back as part of the QRYDTA, and as
        // we are parsing through the row that contains the SQLCA with +100, we mark the
        // nextRowPosition_ which is the lastValidBytePosition_, but we don't mark the
        // currentRowPosition_ until the next time next() is called causing the check
        // cursor_.currentRowPositionIsEqualToNextRowPosition () to fail in getRow() and thus
        // not returning 0 when it should. So we need to mark the current row position immediately
        // in order for getRow() to be able to pick it up.

        // markNextRowPosition() is called again once this method returns, but it is ok
        // since it's only resetting nextRowPosition_ to position_ and position_ will
        // not change again from this point.

        if (allRowsReceivedFromServer() &&
            (position_ == lastValidBytePosition_)) {
            markNextRowPosition();
            makeNextRowPositionCurrent();
            return false;
        }

        // If data flows....
        if (daNullIndicator == 0x0) {

        if (SanityManager.DEBUG && receivedDeleteHoleWarning) {
        SanityManager.THROWASSERT("Delete hole warning received: nulldata expected");
        }
            incrementRowsReadEvent();

            // netResultSet_ is null if this method is invoked from Lob.position()
            // If row has exceeded the size of the ArrayList, new up a new int[] and add it to the
            // ArrayList, otherwise just reuse the int[].
            if (netResultSet_ != null && netResultSet_.scrollable_) {
                columnDataPosition = allocateColumnDataPositionArray(rowIndex);
                columnDataComputedLength = allocateColumnDataComputedLengthArray(rowIndex);
                columnDataIsNull = allocateColumnDataIsNullArray(rowIndex);
                // Since we are no longer setting the int[]'s to null for a delete/update hole, we need
                // another way of keeping track of the delete/update holes.
                setIsUpdataDeleteHole(rowIndex, false);
            } else {
                // Use the arrays defined on the Cursor for forward-only cursors.
                // can they ever be null
                if (columnDataPosition_ == null || columnDataComputedLength_ == null || isNull_ == null) {
                    allocateColumnOffsetAndLengthArrays();
                }
                columnDataPosition = columnDataPosition_;
                columnDataComputedLength = columnDataComputedLength_;
                columnDataIsNull = isNull_;
            }

            // Loop through the columns
            for (int index = 0; index < columns_; index++) {
                // If column is nullable, read the 1-byte null indicator.
                if (nullable_[index])
                // Need to pass the column index so all previously calculated offsets can be
                // readjusted if the query block splits on a column null indicator.

                // null indicators from FD:OCA data
                // 0 to 127: a data value will flow.
                // -1 to -128: no data value will flow.
                {
                    colNullIndicator = readFdocaOneByte(index);
                }

                // If non-null column data
                if (!nullable_[index] || (colNullIndicator >= 0 && colNullIndicator <= 127)) {

                    // Set the isNull indicator to false
                    columnDataIsNull[index] = false;

                    switch (typeToUseForComputingDataLength_[index]) {
                    // for fixed length data
                    case Typdef.FIXEDLENGTH:
                        columnDataPosition[index] = position_;
                        if (isGraphic_[index]) {
                            columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index] * 2, index);
                        } else {
                            columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index], index);
                        }
                        break;

                        // for variable character string and variable byte string,
                        // there are 2-byte of length in front of the data
                    case Typdef.TWOBYTELENGTH:
                        columnDataPosition[index] = position_;
                        length = readFdocaTwoByteLength(index);
                        // skip length + the 2-byte length field
                        if (isGraphic_[index]) {
                            columnDataComputedLength[index] = skipFdocaBytes(length * 2, index) + 2;
                        } else {
                            columnDataComputedLength[index] = skipFdocaBytes(length, index) + 2;
                        }
                        break;

                        // For decimal columns, determine the precision, scale, and the representation
                    case Typdef.DECIMALLENGTH:
                        columnDataPosition[index] = position_;
                        columnDataComputedLength[index] = skipFdocaBytes(getDecimalLength(index), index);
                        break;

                    case Typdef.LOBLENGTH:
                        columnDataPosition[index] = position_;
                        columnDataComputedLength[index] = this.skipFdocaBytes(fdocaLength_[index] & 0x7fff, index);
                        break;

                        // for short variable character string and short variable byte string,
                        // there is a 1-byte length in front of the data
                    case Typdef.ONEBYTELENGTH:
                        columnDataPosition[index] = position_;
                        length = readFdocaOneByte(index);
                        // skip length + the 1-byte length field
                        if (isGraphic_[index]) {
                            columnDataComputedLength[index] = skipFdocaBytes(length * 2, index) + 1;
                        } else {
                            columnDataComputedLength[index] = skipFdocaBytes(length, index) + 1;
                        }
                        break;

                    default:
                        columnDataPosition[index] = position_;
                        if (isGraphic_[index]) {
                            columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index] * 2, index);
                        } else {
                            columnDataComputedLength[index] = skipFdocaBytes(fdocaLength_[index], index);
                        }
                        break;
                    }
                } else if ((colNullIndicator & 0x80) == 0x80) {
                    // Null data. Set the isNull indicator to true.
                    columnDataIsNull[index] = true;
                }
            }

            // set column offsets for the current row.
            columnDataPosition_ = columnDataPosition;
            columnDataComputedLength_ = columnDataComputedLength;
            isNull_ = columnDataIsNull;

            if (!allRowsReceivedFromServer()) {
                calculateLobColumnPositionsForRow();
                // Flow another CNTQRY if we are blocking, are using rtnextrow, and expect
                // non-trivial EXTDTAs for forward only cursors.  Note we do not support
                // EXTDTA retrieval for scrollable cursors.
                // if qryrowset was sent on excsqlstt for a sp call, which is only the case
                if (blocking_ && rtnextrow_ &&
                    !netResultSet_.scrollable_ &&
                    !extdtaPositions_.isEmpty()) {
                    if (allowServerFetch) {
                        netResultSet_.flowFetch();
                    } else {
                        return false;
                    }
                }
            }
        } else {
            if (netResultSet_ != null && netResultSet_.scrollable_) {
        if (receivedDeleteHoleWarning) {
            setIsUpdataDeleteHole(rowIndex, true);
        } else {
            if (SanityManager.DEBUG) {
            // Invariant: for SUR, we introduced the warning
            // in addition to null data.
            SanityManager
                .THROWASSERT("Delete hole warning expected");
            }
        }
            }
        }

        // If blocking protocol is used, we could have already received an ENDQRYRM,
        // which sets allRowsReceivedFromServer_ to true.  It's safe to assume that all of
        // our QRYDTA's have been successfully copied to the dataBuffer.  And even though
        // the flag for allRowsReceivedFromServer_ is set, we still want to continue to parse through
        // the data in the dataBuffer.
        // But in the case where fixed row protocol is used,
        if (!blocking_ && allRowsReceivedFromServer() &&
            daNullIndicator == 0xFF) {
            return false;
        } else {
            return true;
        }
    }