📄 tablescanresultset.java
字号:
/* Derby - Class org.apache.derby.impl.sql.execute.TableScanResultSet Copyright 1997, 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.sql.execute.CursorResultSet;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.services.i18n.MessageService;import org.apache.derby.iapi.sql.Activation;import org.apache.derby.iapi.sql.ResultSet;import org.apache.derby.iapi.sql.execute.ExecRow;import org.apache.derby.iapi.sql.execute.ExecIndexRow;import org.apache.derby.iapi.sql.execute.ExecutionContext;import org.apache.derby.iapi.sql.execute.NoPutResultSet;import org.apache.derby.iapi.sql.execute.TemporaryRowHolder;import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;import org.apache.derby.iapi.store.access.ConglomerateController;import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;import org.apache.derby.iapi.store.access.Qualifier;import org.apache.derby.iapi.store.access.ScanController;import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;import org.apache.derby.iapi.store.access.TransactionController;import org.apache.derby.iapi.types.DataValueDescriptor;import org.apache.derby.iapi.types.Orderable;import org.apache.derby.iapi.types.RowLocation;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.services.stream.HeaderPrintWriter;import org.apache.derby.iapi.services.stream.InfoStreams;import org.apache.derby.iapi.services.monitor.Monitor;import org.apache.derby.iapi.services.loader.GeneratedMethod;import org.apache.derby.iapi.services.io.FormatableBitSet;import org.apache.derby.iapi.reference.SQLState;import java.util.Properties;import java.util.Hashtable;/** * Takes a table and a table filter and returns * the table's rows satisfying the filter as a result set. * * There are several things we could do during object * construction that are done in the open & next calls, to * improve performance. * * @author ames */public class TableScanResultSet extends NoPutResultSetImpl implements CursorResultSet, Cloneable{ protected ScanController scanController; protected boolean scanControllerOpened; protected boolean isKeyed; protected boolean firstScan = true; protected ExecIndexRow startPosition; protected ExecIndexRow stopPosition; protected ExecRow candidate; // set in constructor and not altered during // life of object. protected long conglomId; protected DynamicCompiledOpenConglomInfo dcoci; protected StaticCompiledOpenConglomInfo scoci; protected GeneratedMethod resultRowAllocator; protected GeneratedMethod startKeyGetter; protected int startSearchOperator; protected GeneratedMethod stopKeyGetter; protected int stopSearchOperator; public Qualifier[][] qualifiers; protected GeneratedMethod closeCleanup; public String tableName; public String indexName; protected boolean runTimeStatisticsOn; protected FormatableBitSet accessedCols; protected int[] indexCols; //index keys base column position array public int rowsPerRead; public boolean forUpdate; private boolean sameStartStopPosition; private boolean nextDone; private RowLocation rlTemplate; public int isolationLevel; public int lockMode; // Run time statistics private Properties scanProperties; public String startPositionString; public String stopPositionString; public boolean isConstraint; public boolean coarserLock; public boolean oneRowScan; protected long rowsThisScan; private long estimatedRowCount; /* Following fields are used by beetle 3865, updateable cursor using index. "past2FutureTbl" * is a hash table containing updated rows that are thrown into future direction of the * index scan and as a result we'll hit it again but should skip it. If this hash table * is full, we scan forward and have a virtual memory style temp heap holding future row * id's. */ protected Hashtable past2FutureTbl; protected TemporaryRowHolder futureForUpdateRows; //tmp table for materialized rids protected TemporaryRowHolderResultSet futureRowResultSet; //result set for reading from above protected boolean skipFutureRowHolder; //skip reading rows from above protected boolean sourceDrained; //all row ids materialized protected boolean currentRowPrescanned; //got a row from above tmp table protected boolean compareToLastKey; //see comments in UpdateResultSet protected ExecRow lastCursorKey; private ExecRow sparseRow; //sparse row in heap column order private FormatableBitSet sparseRowMap; //which columns to read // // class interface // public TableScanResultSet(long conglomId, StaticCompiledOpenConglomInfo scoci, Activation activation, GeneratedMethod resultRowAllocator, int resultSetNumber, GeneratedMethod startKeyGetter, int startSearchOperator, GeneratedMethod stopKeyGetter, int stopSearchOperator, boolean sameStartStopPosition, Qualifier[][] qualifiers, String tableName, String indexName, boolean isConstraint, boolean forUpdate, int colRefItem, int indexColItem, int lockMode, boolean tableLocked, int isolationLevel, int rowsPerRead, boolean oneRowScan, double optimizerEstimatedRowCount, double optimizerEstimatedCost, GeneratedMethod closeCleanup) throws StandardException { super(activation, resultSetNumber, optimizerEstimatedRowCount, optimizerEstimatedCost); this.conglomId = conglomId; /* Static info created at compile time and can be shared across * instances of the plan. * Dynamic info created on 1st opening of this ResultSet as * it cannot be shared. */ this.scoci = scoci; if (SanityManager.DEBUG) { SanityManager.ASSERT( activation!=null, "table scan must get activation context"); SanityManager.ASSERT( resultRowAllocator!= null, "table scan must get row allocator"); if (sameStartStopPosition) { SanityManager.ASSERT(stopKeyGetter == null, "stopKeyGetter expected to be null when sameStartStopPosition is true"); } } this.resultRowAllocator = resultRowAllocator; this.startKeyGetter = startKeyGetter; this.startSearchOperator = startSearchOperator; this.stopKeyGetter = stopKeyGetter; this.stopSearchOperator = stopSearchOperator; this.sameStartStopPosition = sameStartStopPosition; this.qualifiers = qualifiers; this.tableName = tableName; this.indexName = indexName; this.isConstraint = isConstraint; this.forUpdate = forUpdate; this.rowsPerRead = rowsPerRead; this.oneRowScan = oneRowScan; // retrieve the valid column list from // the saved objects, if it exists this.accessedCols = null; if (colRefItem != -1) { this.accessedCols = (FormatableBitSet)(activation.getPreparedStatement(). getSavedObject(colRefItem)); } if (indexColItem != -1) { this.indexCols = (int[])(activation.getPreparedStatement(). getSavedObject(indexColItem)); } if (indexCols != null) activation.setForUpdateIndexScan(this); this.lockMode = lockMode; /* Isolation level - translate from language to store */ // If not specified, get current isolation level if (isolationLevel == ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL) { isolationLevel = lcc.getCurrentIsolationLevel(); } if (isolationLevel == ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL) { this.isolationLevel = TransactionController.ISOLATION_SERIALIZABLE; } else { /* NOTE: always do row locking on READ COMMITTED/UNCOMITTED scans, * unless the table is marked as table locked (in sys.systables) * This is to improve concurrency. Also see FromBaseTable's * updateTargetLockMode (KEEP THESE TWO PLACES CONSISTENT! * bug 4318). */ /* NOTE: always do row locking on READ COMMITTED/UNCOMMITTED * and repeatable read scans unless the table is marked as * table locked (in sys.systables). * * We always get instantaneous locks as we will complete * the scan before returning any rows and we will fully * requalify the row if we need to go to the heap on a next(). */ if (! tableLocked) { this.lockMode = TransactionController.MODE_RECORD; } if (isolationLevel == ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL) { /* * Now we see if we can get instantaneous locks * if we are getting share locks. * (For example, we can get instantaneous locks * when doing a bulk fetch.) */ if ((! forUpdate) && canGetInstantaneousLocks()) { this.isolationLevel = TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK; } else { this.isolationLevel = TransactionController.ISOLATION_READ_COMMITTED; } } else if (isolationLevel == ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL) { this.isolationLevel = TransactionController.ISOLATION_READ_UNCOMMITTED; } else if (isolationLevel == ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL) { this.isolationLevel = TransactionController.ISOLATION_REPEATABLE_READ; } } if (SanityManager.DEBUG) { SanityManager.ASSERT( ((isolationLevel == ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL) || (isolationLevel == ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL) || (isolationLevel == ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL) || (isolationLevel == ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL)), "Invalid isolation level - " + isolationLevel); } this.closeCleanup = closeCleanup; runTimeStatisticsOn = (activation != null && activation.getLanguageConnectionContext().getRunTimeStatisticsMode()); /* Only call row allocators once */ candidate = (ExecRow) resultRowAllocator.invoke(activation); constructorTime += getElapsedMillis(beginTime); } // // ResultSet interface (leftover from NoPutResultSet) // /** * open 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 on failure to open */ public void openCore() throws StandardException { if (SanityManager.DEBUG) SanityManager.ASSERT( ! isOpen, "TableScanResultSet already open"); // Get the current transaction controller TransactionController tc = activation.getTransactionController(); if (dcoci == null) dcoci = tc.getDynamicCompiledConglomInfo(conglomId); if (startKeyGetter != null) { startPosition = (ExecIndexRow) startKeyGetter.invoke(activation); if (sameStartStopPosition) { stopPosition = startPosition; } } if (stopKeyGetter != null) { stopPosition = (ExecIndexRow) stopKeyGetter.invoke(activation); } /* NOTE: We always open the ScanController on the 1st open * to do the keyed conglomerate check. */ // Determine whether the conglomerate is keyed. This determines // how we find the RowLocation for the base heap. For non-keyed // conglomerates, we ask the scan. For keyed conglomerates, it // is the last column in the row. // // Do this here, rather than in the constructor, so we can avoid // throwing exceptions from the constructor if (firstScan) { openScanController(tc); isKeyed = scanController.isKeyed(); /* ** If scan tracing is turned on, print information about this ** TableScanResultSet when it is first opened. We would like ** to do this when it is constructed, but it is not always ** possible to get the start and stop positioners at the time ** this object is constructed (because they may depend on outer ** rows). */ if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("ScanTrace")) { //traceScanParameters(); } } } // Check whether there are any comparisons with unordered nulls // on either the start or stop position. If there are, we can // (and must) skip the scan, because no rows can qualify if (skipScan(startPosition, stopPosition)) { scanControllerOpened = false; } /* NOTE: We always open the ScanController on the 1st open * to do the keyed conglomerate check, so we only need to * do it here if not the 1st scan. */ else if (! firstScan) { openScanController(tc); } /* If the scan is on an index and opened for update, * then we cache the scan controller and conglomerate * number in the activation so that the scan controller * can be re-used by the update/delete if the index * that we are scanning also needs to be updated. */ if (forUpdate && isKeyed) { activation.setIndexScanController(scanController); activation.setIndexConglomerateNumber(conglomId); } firstScan = false; isOpen = true; numOpens++; nextDone = false; openTime += getElapsedMillis(beginTime); } /* ** Open the scan controller ** ** @param transaction controller will open one if null */ protected void openScanController(TransactionController tc) throws StandardException { DataValueDescriptor[] startPositionRow = startPosition == null ? null : startPosition.getRowArray(); DataValueDescriptor[] stopPositionRow = stopPosition == null ? null : stopPosition.getRowArray(); // Clear the Qualifiers's Orderable cache if (qualifiers != null) { clearOrderableCache(qualifiers); } // Get the current transaction controller if (tc == null) tc = activation.getTransactionController(); int openMode = 0; if (forUpdate) { openMode = TransactionController.OPENMODE_FORUPDATE; if (activation.isCursorActivation()) openMode |= TransactionController.OPENMODE_USE_UPDATE_LOCKS; } scanController = tc.openCompiledScan( activation.getResultSetHoldability(), openMode, lockMode, isolationLevel, accessedCols, startPositionRow, // not used when giving null start position startSearchOperator, qualifiers, stopPositionRow, // not used when giving null stop position stopSearchOperator, scoci, dcoci); /* Remember that we opened the scan */ scanControllerOpened = true; rowsThisScan = 0; /* ** Inform the activation of the estimated number of rows. Only ** do it here, not in reopen, so that we don't do this costly
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -