📄 tablescanresultset.java
字号:
** check too often. */ estimatedRowCount = scanController.getEstimatedRowCount(); activation.informOfRowCount( this, scanController.getEstimatedRowCount() ); } /* ** reopen the scan controller */ private void reopenScanController() 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); } scanController.reopenScan( startPositionRow, startSearchOperator, qualifiers, stopPositionRow, stopSearchOperator); /* Remember that we opened the scan */ scanControllerOpened = true; rowsThisScan = 0; } /** * Reopen a table scan. Here we take advantage * of the reopenScan() interface on scanController * for optimimal performance on joins where we are * an inner table. * * @exception StandardException thrown on failure to open */ public void reopenCore() throws StandardException { beginTime = getCurrentTimeMillis(); if (SanityManager.DEBUG) SanityManager.ASSERT(isOpen, "TableScanResultSet not open, cannot reopen"); if (startKeyGetter != null) { startPosition = (ExecIndexRow) startKeyGetter.invoke(activation); if (sameStartStopPosition) { stopPosition = startPosition; } } if (stopKeyGetter != null) { stopPosition = (ExecIndexRow) stopKeyGetter.invoke(activation); } // 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; } else { if (scanController == null) openScanController((TransactionController)null); else reopenScanController(); } numOpens++; nextDone = false; openTime += getElapsedMillis(beginTime); } /** * Check and make sure sparse heap row and accessed bit map are created. * beetle 3865, update cursor using index. * * @exception StandardException thrown on failure */ private void getSparseRowAndMap() throws StandardException { int numCols = 1, colPos; for (int i = 0; i < indexCols.length; i++) { colPos = (indexCols[i] > 0) ? indexCols[i] : -indexCols[i]; if (colPos > numCols) numCols = colPos; } sparseRow = new ValueRow(numCols); sparseRowMap = new FormatableBitSet(numCols); for (int i = 0; i < indexCols.length; i++) { if (accessedCols.get(i)) { colPos = (indexCols[i] > 0) ? indexCols[i] : -indexCols[i]; sparseRow.setColumn(colPos, candidate.getColumn(i + 1)); sparseRowMap.set(colPos - 1); } } } /** * Return the next row (if any) from the scan (if open). * * @exception StandardException thrown on failure to get next row */ public ExecRow getNextRowCore() throws StandardException { if (currentRow == null) { currentRow = getCompactRow(candidate, accessedCols, (FormatableBitSet) null, isKeyed); } beginTime = getCurrentTimeMillis(); ExecRow result = null; /* beetle 3865, updateable cursor using index. We first saved updated rows with new value * falling into future direction of index scan in hash table, if it's full, we scanned * forward and saved future row ids in a virtual mem heap. */ if (futureForUpdateRows != null) { currentRowPrescanned = false; if (! skipFutureRowHolder) { if (futureRowResultSet == null) { futureRowResultSet = (TemporaryRowHolderResultSet) futureForUpdateRows.getResultSet(); futureRowResultSet.openCore(); } ExecRow ridRow = futureRowResultSet.getNextRowCore(); if (ridRow != null) { /* to boost performance, we used virtual mem heap, and we can insert after * we start retrieving results. The assumption is to * delete current row right after we retrieve it. */ futureRowResultSet.deleteCurrentRow(); RowLocation rl = (RowLocation) ridRow.getColumn(1); ConglomerateController baseCC = activation.getHeapConglomerateController(); if (sparseRow == null) getSparseRowAndMap(); baseCC.fetch( rl, sparseRow.getRowArray(), sparseRowMap); RowLocation rl2 = (RowLocation) rl.getClone(); currentRow.setColumn(currentRow.nColumns(), rl2); candidate.setColumn(candidate.nColumns(), rl2); // have to be consistent! result = currentRow; currentRowPrescanned = true; } else if (sourceDrained) { currentRowPrescanned = true; currentRow = null; } if (currentRowPrescanned) { setCurrentRow(result); nextTime += getElapsedMillis(beginTime); return result; } } } if ( isOpen && !nextDone) { /* Only need to do 1 next per scan * for 1 row scans. */ nextDone = oneRowScan; if (scanControllerOpened) { boolean moreRows; while (moreRows = scanController.fetchNext(candidate.getRowArray())) { rowsSeen++; rowsThisScan++; /* ** Skip rows where there are start or stop positioners ** that do not implement ordered null semantics and ** there are columns in those positions that contain ** null. ** No need to check if start and stop positions are the ** same, since all predicates in both will be ='s, ** and hence evaluated in the store. */ if ((! sameStartStopPosition) && skipRow(candidate)) { rowsFiltered++; continue; } /* beetle 3865, updateable cursor use index. If we have a hash table that * holds updated records, and we hit it again, skip it, and remove it from * hash since we can't hit it again, and we have a space in hash, so can * stop scanning forward. */ if (past2FutureTbl != null) { RowLocation rowLoc = (RowLocation) currentRow.getColumn(currentRow.nColumns()); if (past2FutureTbl.get(rowLoc) != null) { past2FutureTbl.remove(rowLoc); continue; } } result = currentRow; break; } /* ** If we just finished a full scan of the heap, update ** the number of rows in the scan controller. ** ** NOTE: It would be more efficient to only update the ** scan controller if the optimizer's estimated number of ** rows were wrong by more than some threshold (like 10%). ** This would require a little more work than I have the ** time for now, however, as the row estimate that is given ** to this result set is the total number of rows for all ** scans, not the number of rows per scan. */ if (! moreRows) { setRowCountIfPossible(rowsThisScan); currentRow = null; } } } setCurrentRow(result); nextTime += getElapsedMillis(beginTime); return result; } /** * If the result set has been opened, * close the open scan. * @exception StandardException on error */ public void close() throws StandardException { beginTime = getCurrentTimeMillis(); if ( isOpen ) { /* ** If scan tracing is turned on, print information about this ** TableScanResultSet when it is closed. */ if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("ScanTrace")) { //traceClose(); } } // we don't want to keep around a pointer to the // row ... so it can be thrown away. // REVISIT: does this need to be in a finally // block, to ensure that it is executed? clearCurrentRow(); if (closeCleanup != null) { try { closeCleanup.invoke(activation); // let activation tidy up } catch (StandardException se) { if (SanityManager.DEBUG) SanityManager.THROWASSERT(se); } } currentRow = null; if (scanController != null) { // This is where we get the positioner info for inner tables if (runTimeStatisticsOn) { // This is where we get the scan properties for a subquery scanProperties = getScanProperties(); startPositionString = printStartPosition(); stopPositionString = printStopPosition(); } scanController.close(); scanController = null; // should not access after close activation.clearIndexScanInfo(); } scanControllerOpened = false; startPosition = null; stopPosition = null; super.close(); if (indexCols != null) { ConglomerateController borrowedBaseCC = activation.getHeapConglomerateController(); if (borrowedBaseCC != null) { borrowedBaseCC.close(); activation.clearHeapConglomerateController(); } } if (futureRowResultSet != null) futureRowResultSet.close(); } else if (SanityManager.DEBUG) SanityManager.DEBUG("CloseRepeatInfo","Close of TableScanResultSet repeated"); closeTime += getElapsedMillis(beginTime); } /** * Return the total amount of time spent in this ResultSet * * @param type CURRENT_RESULTSET_ONLY - time spent only in this ResultSet * ENTIRE_RESULTSET_TREE - time spent in this ResultSet and below. * * @return long The total amount of time spent (in milliseconds). */ public long getTimeSpent(int type) { long totTime = constructorTime + openTime + nextTime + closeTime; /* RESOLVE - subtract out store time later, when available */ if (type == NoPutResultSet.CURRENT_RESULTSET_ONLY) { return totTime; } else { return totTime; } } // // CursorResultSet interface // /** * This result set has its row location from * the last fetch done. If the cursor is closed, * a null is returned. * * @see CursorResultSet * * @return the row location of the current cursor row. * @exception StandardException thrown on failure to get row location */ public RowLocation getRowLocation() throws StandardException { RowLocation rl; if (! isOpen) return null; if ( ! scanControllerOpened) return null; /* ** If the conglomerate is keyed, the row location of the base row ** is in the last column of the current row. If it's not keyed, ** we get the row location from the scan of the heap. */ if (isKeyed) { if (SanityManager.DEBUG) { SanityManager.ASSERT(currentRow != null, "There must be a current row when fetching the row location"); } rl = (RowLocation) currentRow.getColumn( currentRow.nColumns()); } else { // we reuse the same rowlocation object across several calls. if (rlTemplate == null) rlTemplate = scanController.newRowLocationTemplate(); rl = rlTemplate; scanController.fetchLocation(rl); } return rl; } /** * This result set has its row from the last fetch done. * If the cursor is closed, a null is returned. * * @see CursorResultSet * * @return the last row returned; * @exception StandardException thrown on failure. */ /* RESOLVE - this should return activation.getCurrentRow(resultSetNumber), * once there is such a method. (currentRow is redundant) */ public ExecRow getCurrentRow() throws StandardException { ExecRow result = null; if (SanityManager.DEBUG) SanityManager.ASSERT(isOpen, "TSRS expected to be open"); if (currentRowPrescanned) return currentRow; /* Nothing to do if we're not currently on a row or * if the current row get deleted out from under us * or if there is no current scan (can happen if the * scan is being skipped) or if the current position * no longer qualifies. */ try { if ((currentRow == null) || (!scanControllerOpened) || (scanController.isCurrentPositionDeleted()) || (!scanController.doesCurrentPositionQualify())) { return null; } } catch (StandardException se) { if (se.getMessageId().equals(SQLState.AM_SCAN_NOT_POSITIONED)) { //bug 4515 - Have a easier to understand error message than what we get from store se=StandardException.newException(SQLState.NO_CURRENT_ROW); throw se; } } result = (ExecRow) resultRowAllocator.invoke(activation); currentRow = getCompactRow(result, accessedCols, (FormatableBitSet) null, isKeyed); try { scanController.fetch(result.getRowArray()); } catch (StandardException se) { if (se.getMessageId().equals(SQLState.AM_RECORD_NOT_FOUND)) { // Somehow the row got deleted between the above // doesCurrentPositionQualify() call and here (one way is if // this scan is read uncommitted isolation level).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -