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

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

There is a newer version: 12.8.1.jre11
Show newest version
//---------------------------------------------------------------------------------------------------------------------------------
// File: ScrollWindow.java
//
//
// Microsoft JDBC Driver for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), 
//  to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//  and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
//  IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
 

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 final 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 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