All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.sqlserver.jdbc.ScrollWindow Maven / Gradle / Ivy

Go to download

Microsoft JDBC Driver for SQL Server. The Azure Key Vault feature in Microsoft JDBC Driver for SQL Server depends on Azure SDK for JAVA and Azure Active Directory Library For Java.

There is a newer version: 12.7.0.jre11-preview
Show newest version
/*
 * Microsoft JDBC Driver for SQL Server
 * 
 * Copyright(c) Microsoft Corporation All rights reserved.
 * 
 * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information.
 */

package com.microsoft.sqlserver.jdbc;

/**
 * ScrollWindow provides an efficient way to scroll around within a limited number of rows, typically the ResultSet fetch size, by saving and
 * restoring row state, such as starting point in the response and updated/deleted status, on movement within the window.
 *
 * Without a scroll window, scrolling backward through a result set would be very costly, requiring reindexing the fetch buffer up to row N-1 for each
 * move to the previous row.
 */
final class ScrollWindow {
    /** Set of marks for the rows in the window */
    private TDSReaderMark[] rowMark;

    /** Set of flags indicating which rows have been updated through the ResultSet */
    private boolean[] updatedRow;

    /** Set of flags indicating which rows have been deleted through the ResultSet */
    private boolean[] deletedRow;

    /** Set of enums indicating the types of rows in a ResultSet */
    private RowType[] rowType;

    /** Size (in rows) of this scroll window */
    private int size = 0;

    /** Max number of rows in the window (less than or equal to size) */
    private int maxRows = 0;

    final int getMaxRows() {
        return maxRows;
    }

    /** Current row in the window (1-indexed) */
    private int currentRow;

    final int getRow() {
        return currentRow;
    }

    ScrollWindow(int size) {
        setSize(size);
        reset();
    }

    private void setSize(int size) {
        assert this.size != size;
        this.size = size;
        this.maxRows = size;
        this.rowMark = new TDSReaderMark[size];
        this.updatedRow = new boolean[size];
        this.deletedRow = new boolean[size];
        this.rowType = new RowType[size];
        for (int i = 0; i < size; i++) {
            rowType[i] = RowType.UNKNOWN;
        }
    }

    final void clear() {
        for (int i = 0; i < rowMark.length; ++i) {
            rowMark[i] = null;
            updatedRow[i] = false;
            deletedRow[i] = false;
            rowType[i] = RowType.UNKNOWN;
        }

        assert size > 0;
        maxRows = size;
        reset();
    }

    final void reset() {
        currentRow = 0;
    }

    final void resize(int newSize) {
        assert newSize > 0;
        if (newSize != size)
            setSize(newSize);
    }

    final String logCursorState() {
        return " currentRow:" + currentRow + " maxRows:" + maxRows;
    }

    final boolean next(SQLServerResultSet rs) throws SQLServerException {
        if (SQLServerResultSet.logger.isLoggable(java.util.logging.Level.FINER))
            SQLServerResultSet.logger.finer(rs.toString() + logCursorState());

        // Precondition:
        // Current position should always be on a row in the window or
        // just before the first row or just after the last row.
        assert 0 <= currentRow && currentRow <= maxRows + 1;

        // If the position is already beyond the end of the window,
        // then it can move no farther forward.
        if (maxRows + 1 == currentRow)
            return false;

        // Otherwise, we are going to attempt to move the current
        // position to the next row. First, save off the row
        // updated/deleted status for the current row so it
        // can be restored later if we ever move to this row again.
        if (currentRow >= 1) {
            updatedRow[currentRow - 1] = rs.getUpdatedCurrentRow();
            deletedRow[currentRow - 1] = rs.getDeletedCurrentRow();
            rowType[currentRow - 1] = rs.getCurrentRowType();
        }

        // Start on the next row
        ++currentRow;

        // If we were on the last row of the window then make sure
        // the move past the last row consumes the remainder of that
        // row from the fetch buffer. The fetch buffer should be
        // left pointing beyond the last row of the window, which
        // is most likely the end of the fetch buffer as well.
        if (maxRows + 1 == currentRow) {
            rs.fetchBufferNext();
            return false;
        }

        // We weren't on the last row of the window. If we already
        // know that there was another row in the fetch buffer,
        // then restore the response buffer position and updated/deleted
        // status for the new row.
        if (null != rowMark[currentRow - 1]) {
            rs.fetchBufferReset(rowMark[currentRow - 1]);
            rs.setCurrentRowType(rowType[currentRow - 1]);
            rs.setUpdatedCurrentRow(updatedRow[currentRow - 1]);
            rs.setDeletedCurrentRow(deletedRow[currentRow - 1]);
            return true;
        }

        // We weren't on the last row of the window and we don't
        // know whether there are additional rows in the fetch
        // buffer, so try to read another row now. If we find
        // one then keep track of its position in the response
        // buffer.
        if (rs.fetchBufferNext()) {
            rowMark[currentRow - 1] = rs.fetchBufferMark();
            rowType[currentRow - 1] = rs.getCurrentRowType();

            if (SQLServerResultSet.logger.isLoggable(java.util.logging.Level.FINEST))
                SQLServerResultSet.logger.finest(
                        rs.toString() + " Set mark " + rowMark[currentRow - 1] + " for row " + currentRow + " of type " + rowType[currentRow - 1]);

            return true;
        }

        // We weren't on the last row of the window and we now
        // know that there are no more rows in the fetch buffer,
        // so adjust maxRows down accordingly.
        maxRows = currentRow - 1;
        return false;
    }

    final void previous(SQLServerResultSet rs) throws SQLServerException {
        if (SQLServerResultSet.logger.isLoggable(java.util.logging.Level.FINER))
            SQLServerResultSet.logger.finer(rs.toString() + logCursorState());

        // Precondition:
        // Current position should always be on a row in the window or
        // just before the first row or just after the last row.
        assert 0 <= currentRow && currentRow <= maxRows + 1;

        // If the position is already before the start of the window,
        // then it can move no farther back.
        if (0 == currentRow)
            return;

        // Otherwise, we are going to attempt to move the current
        // position to the previous row. First, save off the row
        // updated/deleted status for the current row so it
        // can be restored later if we ever move to this row again.
        if (currentRow <= maxRows) {
            assert currentRow >= 1;
            updatedRow[currentRow - 1] = rs.getUpdatedCurrentRow();
            deletedRow[currentRow - 1] = rs.getDeletedCurrentRow();
            rowType[currentRow - 1] = rs.getCurrentRowType();
        }

        // Start on the previous row
        --currentRow;

        // If we were on the first row of the window before moving,
        // then we're now before the first row and we're done.
        if (0 == currentRow)
            return;

        // If we weren't on the first row before moving then we
        // are now on the previous row. Restore the saved
        // position in the response buffer and updated/deleted
        // state for the now current row.
        assert null != rowMark[currentRow - 1];
        rs.fetchBufferReset(rowMark[currentRow - 1]);
        rs.setCurrentRowType(rowType[currentRow - 1]);
        rs.setUpdatedCurrentRow(updatedRow[currentRow - 1]);
        rs.setDeletedCurrentRow(deletedRow[currentRow - 1]);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy