📄 scrollinsensitiveresultset.java
字号:
/* Derby - Class org.apache.derby.impl.sql.execute.ScrollInsensitiveResultSet Copyright 1999, 2004 The Apache Software Foundation or its licensors, as 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.impl.sql.execute;import org.apache.derby.iapi.services.loader.GeneratedMethod;import org.apache.derby.iapi.services.monitor.Monitor;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.sql.execute.CursorResultSet;import org.apache.derby.iapi.sql.execute.ExecRow;import org.apache.derby.iapi.sql.execute.ExecutionContext;import org.apache.derby.iapi.sql.execute.NoPutResultSet;import org.apache.derby.iapi.sql.Activation;import org.apache.derby.iapi.sql.Row;import org.apache.derby.iapi.store.access.ConglomerateController;import org.apache.derby.iapi.store.access.ScanController;import org.apache.derby.iapi.store.access.TransactionController;import org.apache.derby.iapi.types.RowLocation;import org.apache.derby.iapi.types.DataValueDescriptor;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.store.access.BackingStoreHashtable;import org.apache.derby.iapi.services.io.FormatableBitSet;import org.apache.derby.iapi.types.SQLInteger;/** * Provide insensitive scrolling functionality for the underlying * result set. We build a hash table of rows as the user scrolls * forward, with the position as the key. */public class ScrollInsensitiveResultSet extends NoPutResultSetImpl implements CursorResultSet{ /* ** Set in constructor and not altered during life of object. */ public NoPutResultSet source; private int sourceRowWidth; private BackingStoreHashtable ht; private ExecRow resultRow; // Scroll tracking private int positionInSource; private int currentPosition; private int lastPosition; private boolean seenFirst; private boolean seenLast; private boolean beforeFirst = true; private boolean afterLast; public int numFromHashTable; public int numToHashTable; private int maxRows; private GeneratedMethod closeCleanup; private boolean keepAfterCommit; /** * Constructor for a ScrollInsensitiveResultSet * * @param source The NoPutResultSet from which to get rows * to scroll through * @param activation The activation for this execution * @param resultSetNumber The resultSetNumber * @param sourceRowWidth # of columns in the source row * * @exception StandardException on error */ public ScrollInsensitiveResultSet(NoPutResultSet source, Activation activation, int resultSetNumber, int sourceRowWidth, double optimizerEstimatedRowCount, double optimizerEstimatedCost, GeneratedMethod c) throws StandardException { super(activation, resultSetNumber, optimizerEstimatedRowCount, optimizerEstimatedCost); this.source = source; this.sourceRowWidth = sourceRowWidth; keepAfterCommit = activation.getResultSetHoldability(); maxRows = activation.getMaxRows(); if (SanityManager.DEBUG) { SanityManager.ASSERT(maxRows != -1, "maxRows not expected to be -1"); } closeCleanup = c; constructorTime += getElapsedMillis(beginTime); } // // ResultSet interface (leftover from NoPutResultSet) // /** * open a scan on the source. scan parameters are evaluated * at each open, so there is probably some way of altering * their values... * * @exception StandardException thrown on failure */ public void openCore() throws StandardException { beginTime = getCurrentTimeMillis(); if (SanityManager.DEBUG) SanityManager.ASSERT( ! isOpen, "ScrollInsensitiveResultSet already open"); source.openCore(); isOpen = true; numOpens++; /* Create the hash table. We pass * null in as the row source as we will * build the hash table on demand as * the user scrolls. * The 1st column, the position in the * scan, will be the key column. */ int[] keyCols = new int[1]; // keyCols[0] = 0; // not req. arrays initialized to zero /* We don't use the optimizer row count for this because it could be * wildly pessimistic. We only use Hash tables when the optimizer row count * is within certain bounds. We have no alternative for scrolling insensitive * cursors so we'll just trust that it will fit. * We need BackingStoreHashtable to actually go to disk when it doesn't fit. * This is a known limitation. */ ht = new BackingStoreHashtable(getTransactionController(), null, keyCols, false, -1, // don't trust optimizer row count HashScanResultSet.DEFAULT_MAX_CAPACITY, HashScanResultSet.DEFAULT_INITIAL_CAPACITY, HashScanResultSet.DEFAULT_MAX_CAPACITY, false, keepAfterCommit); openTime += getElapsedMillis(beginTime); setBeforeFirstRow(); } /** * reopen a scan on the table. scan parameters are evaluated * at each open, so there is probably some way of altering * their values... * * @exception StandardException thrown if cursor finished. */ public void reopenCore() throws StandardException { boolean constantEval = true; beginTime = getCurrentTimeMillis(); if (SanityManager.DEBUG) { SanityManager.ASSERT(isOpen, "ScrollInsensitiveResultSet already open"); SanityManager.THROWASSERT( "reopenCore() not expected to be called"); } setBeforeFirstRow(); } /** * Returns the row at the absolute position from the query, * and returns NULL when there is no such position. * (Negative position means from the end of the result set.) * Moving the cursor to an invalid position leaves the cursor * positioned either before the first row (negative position) * or after the last row (positive position). * NOTE: An exception will be thrown on 0. * * @param row The position. * @return The row at the absolute position, or NULL if no such position. * * @exception StandardException Thrown on failure * @see Row */ public ExecRow getAbsoluteRow(int row) throws StandardException { if ( ! isOpen ) { throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "absolute"); } attachStatementContext(); if (SanityManager.DEBUG) { if (!isTopResultSet) { SanityManager.THROWASSERT( this + "expected to be the top ResultSet"); } } // Absolute 0 is defined to be before first! if (row == 0) { setBeforeFirstRow(); return null; } if (row > 0) { // position is from the start of the result set if (row <= positionInSource) { // We've already seen the row before return getRowFromHashTable(row); } /* We haven't seen the row yet, scan until we find * it or we get to the end. */ int diff = row - positionInSource; ExecRow result = null; while (diff > 0) { if ((result = getNextRowFromSource()) != null) { diff--; } else { break; } } currentRow = result; return result; } else if (row < 0) { // position is from the end of the result set // Get the last row, if we haven't already if (!seenLast) { getLastRow(); } // Note, for negative values position is from beyond the end // of the result set, e.g. absolute(-1) points to the last row int beyondResult = lastPosition + 1; if (beyondResult + row > 0) { // valid row return getRowFromHashTable(beyondResult + row); } else { // position before the beginning of the result set return setBeforeFirstRow(); } } currentRow = null; return null; } /** * Returns the row at the relative position from the current * cursor position, and returns NULL when there is no such position. * (Negative position means toward the beginning of the result set.) * Moving the cursor to an invalid position leaves the cursor * positioned either before the first row (negative position) * or after the last row (positive position). * NOTE: 0 is valid. * NOTE: An exception is thrown if the cursor is not currently * positioned on a row. * * @param row The position. * @return The row at the relative position, or NULL if no such position. * * @exception StandardException Thrown on failure * @see Row */ public ExecRow getRelativeRow(int row) throws StandardException { if ( ! isOpen ) { throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "relative"); } attachStatementContext(); if (SanityManager.DEBUG) { if (!isTopResultSet) { SanityManager.THROWASSERT( this + "expected to be the top ResultSet"); } } // Return the current row for 0 if (row == 0) { if (beforeFirst || afterLast || currentPosition==0) { return null; } else { return getRowFromHashTable(currentPosition); } } else if (row > 0) { return getAbsoluteRow(currentPosition + row); } else { // row < 0 if (currentPosition + row < 0) { return setBeforeFirstRow(); } return getAbsoluteRow(currentPosition + row); } } /** * Sets the current position to before the first row and returns NULL * because there is no current row. * * @return NULL. * * @see Row */ public ExecRow setBeforeFirstRow() { currentPosition = 0; beforeFirst = true; afterLast = false; currentRow = null; return null; } /** * Returns the first row from the query, and returns NULL when there * are no rows. * * @return The first row, or NULL if no rows. * * @exception StandardException Thrown on failure * @see Row */ public ExecRow getFirstRow() throws StandardException { if ( ! isOpen ) { throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "first"); } /* Get the row from the hash table if * we have already seen it before. */ if (seenFirst) { return getRowFromHashTable(1); } attachStatementContext(); if (SanityManager.DEBUG) { if (!isTopResultSet) { SanityManager.THROWASSERT( this + "expected to be the top ResultSet"); } } return getNextRowCore(); } /** * * @exception StandardException thrown on failure */ public ExecRow getNextRowCore() throws StandardException { ExecRow result = null; beginTime = getCurrentTimeMillis(); if (!isOpen) throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "next"); /* Should we get the next row from the source or the hash table? */ if (currentPosition == positionInSource) { /* Current position is same as position in source. * Get row from the source. */ result = getNextRowFromSource(); } else if (currentPosition < positionInSource) { /* Current position is before position in source. * Get row from the hash table. */ result = getRowFromHashTable(currentPosition + 1); } else { result = null; } if (result != null) { rowsSeen++; afterLast = false; } currentRow = result; setCurrentRow(currentRow); beforeFirst = false; nextTime += getElapsedMillis(beginTime); return result; } /** * Returns the previous row from the query, and returns NULL when there * are no more previous rows. * * @return The previous row, or NULL if no more previous rows. * * @exception StandardException Thrown on failure * @see Row
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -