001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.BulkTableScanResultSet
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.execute;
023:
024: import org.apache.derby.iapi.sql.execute.CursorResultSet;
025: import org.apache.derby.iapi.error.StandardException;
026:
027: import org.apache.derby.iapi.types.RowLocation;
028: import org.apache.derby.iapi.types.DataValueDescriptor;
029:
030: import org.apache.derby.iapi.sql.ResultSet;
031: import org.apache.derby.iapi.sql.execute.ExecRow;
032: import org.apache.derby.iapi.sql.execute.ExecIndexRow;
033: import org.apache.derby.iapi.sql.execute.NoPutResultSet;
034:
035: import org.apache.derby.iapi.sql.Activation;
036:
037: import org.apache.derby.iapi.store.access.GroupFetchScanController;
038: import org.apache.derby.iapi.store.access.Qualifier;
039: import org.apache.derby.iapi.store.access.ScanController;
040: import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
041: import org.apache.derby.iapi.store.access.TransactionController;
042:
043: import org.apache.derby.iapi.types.RowLocation;
044:
045: import org.apache.derby.iapi.services.sanity.SanityManager;
046: import org.apache.derby.iapi.services.loader.GeneratedMethod;
047:
048: import org.apache.derby.iapi.services.io.FormatableBitSet;
049:
050: /**
051: * Read a base table or index in bulk. Most of the
052: * work for this method is inherited from TableScanResultSet.
053: * This class overrides getNextRowCore (and extends
054: * re/openCore) to use a row array and fetch rows
055: * from the Store in bulk (using fetchNextGroup).
056: * <p>
057: * Since it retrieves rows in bulk, locking is not
058: * as is usual -- locks may have already been released
059: * on rows as they are returned to the user. Hence,
060: * this ResultSet is not suitable for a query running
061: * Isolation Level 1, cursor stability.
062: * <p>
063: * Note that this code is only accessable from an
064: * optimizer override. If it makes sense to have the
065: * optimizer select bulk reads, then this should
066: * probably be rolled into TableScanResultSet.
067: *
068: * @author jamie
069: */
070: class BulkTableScanResultSet extends TableScanResultSet implements
071: CursorResultSet {
072: private DataValueDescriptor[][] rowArray;
073: private int curRowPosition;
074: private int numRowsInArray;
075:
076: private static int OUT_OF_ROWS = 0;
077:
078: /**
079: * Constructor. Just save off the rowsPerRead argument
080: * and pass everything else down to TableScanResultSet
081: *
082: * @see org.apache.derby.iapi.sql.execute.ResultSetFactory#getBulkTableScanResultSet
083: *
084: * @exception StandardException thrown on failure to open
085: */
086: BulkTableScanResultSet(long conglomId,
087: StaticCompiledOpenConglomInfo scoci, Activation activation,
088: GeneratedMethod resultRowAllocator, int resultSetNumber,
089: GeneratedMethod startKeyGetter, int startSearchOperator,
090: GeneratedMethod stopKeyGetter, int stopSearchOperator,
091: boolean sameStartStopPosition, Qualifier[][] qualifiers,
092: String tableName, String userSuppliedOptimizerOverrides,
093: String indexName, boolean isConstraint, boolean forUpdate,
094: int colRefItem, int indexColItem, int lockMode,
095: boolean tableLocked, int isolationLevel, int rowsPerRead,
096: boolean oneRowScan, double optimizerEstimatedRowCount,
097: double optimizerEstimatedCost) throws StandardException {
098: super (conglomId, scoci, activation, resultRowAllocator,
099: resultSetNumber, startKeyGetter, startSearchOperator,
100: stopKeyGetter, stopSearchOperator,
101: sameStartStopPosition, qualifiers, tableName,
102: userSuppliedOptimizerOverrides, indexName,
103: isConstraint, forUpdate, colRefItem, indexColItem,
104: lockMode, tableLocked, isolationLevel, rowsPerRead,
105: oneRowScan, optimizerEstimatedRowCount,
106: optimizerEstimatedCost);
107:
108: if (SanityManager.DEBUG) {
109: /* Bulk fetch of size 1 is same as a regular table scan
110: * and is supposed to be detected at compile time.
111: */
112: if (rowsPerRead == 1) {
113: SanityManager
114: .THROWASSERT("rowsPerRead not expected to be 1");
115: }
116: /* Bulk table scan implies that scan is not
117: * a 1 row scan.
118: */
119: if (oneRowScan) {
120: SanityManager
121: .THROWASSERT("oneRowScan expected to be false - "
122: + "rowsPerRead = " + rowsPerRead);
123: }
124: }
125: }
126:
127: /**
128: * Open the scan controller
129: *
130: * @param tc transaction controller will open one if null
131: *
132: * @exception StandardException thrown on failure to open
133: */
134: protected void openScanController(TransactionController tc)
135: throws StandardException {
136: DataValueDescriptor[] startPositionRow = startPosition == null ? null
137: : startPosition.getRowArray();
138: DataValueDescriptor[] stopPositionRow = stopPosition == null ? null
139: : stopPosition.getRowArray();
140:
141: // Clear the Qualifiers's Orderable cache
142: if (qualifiers != null) {
143: clearOrderableCache(qualifiers);
144: }
145:
146: // Get the current transaction controller
147: if (tc == null)
148: tc = activation.getTransactionController();
149: scanController = tc.openCompiledScan(activation
150: .getResultSetHoldability(),
151: (forUpdate ? TransactionController.OPENMODE_FORUPDATE
152: : 0), lockMode, isolationLevel, accessedCols,
153: startPositionRow,
154: // not used when giving null start position
155: startSearchOperator, qualifiers, stopPositionRow,
156: // not used when giving null stop position
157: stopSearchOperator, scoci, dcoci);
158:
159: /* Remember that we opened the scan */
160: scanControllerOpened = true;
161:
162: rowsThisScan = 0;
163:
164: /*
165: ** Inform the activation of the estimated number of rows. Only
166: ** do it here, not in reopen, so that we don't do this costly
167: ** check too often.
168: */
169: activation.informOfRowCount(this , scanController
170: .getEstimatedRowCount());
171: }
172:
173: /**
174: * Open up the result set. Delegate
175: * most work to TableScanResultSet.openCore().
176: * Create a new array with <rowsPerRead> rows
177: * for use in fetchNextGroup().
178: *
179: * @exception StandardException thrown on failure to open
180: */
181: public void openCore() throws StandardException {
182: super .openCore();
183: /*
184: ** Add the extra time we spent after
185: ** the super class -- TableScanResultSet()
186: ** already added up its time in openCore().
187: */
188: beginTime = getCurrentTimeMillis();
189: rowArray = new DataValueDescriptor[rowsPerRead][];
190:
191: // we only allocate the first row -- the
192: // store clones as needed for the rest
193: // of the rows
194: rowArray[0] = candidate.getRowArrayClone();
195: numRowsInArray = 0;
196: curRowPosition = -1;
197:
198: openTime += getElapsedMillis(beginTime);
199: }
200:
201: /**
202: * Reopen the result set. Delegate
203: * most work to TableScanResultSet.reopenCore().
204: * Reuse the array of rows.
205: *
206: * @exception StandardException thrown on failure to open
207: */
208: public void reopenCore() throws StandardException {
209: super .reopenCore();
210: numRowsInArray = 0;
211: curRowPosition = -1;
212: }
213:
214: /**
215: * Return the next row (if any) from the scan (if open).
216: * Reload the rowArray as necessary.
217: *
218: * @exception StandardException thrown on failure to get next row
219: */
220: public ExecRow getNextRowCore() throws StandardException {
221: ExecRow result = null;
222:
223: checkCancellationFlag();
224:
225: beginTime = getCurrentTimeMillis();
226: if (isOpen && scanControllerOpened) {
227: if (currentRow == null) {
228: currentRow = getCompactRow(candidate, accessedCols,
229: (FormatableBitSet) null, isKeyed);
230: }
231:
232: outer: for (;;) {
233: if (curRowPosition >= numRowsInArray - 1) {
234: if (reloadArray() == OUT_OF_ROWS) {
235: setCurrentRow(null);
236: setRowCountIfPossible(rowsThisScan);
237: return null;
238: }
239: }
240:
241: while (++curRowPosition < numRowsInArray) {
242: candidate.setRowArray(rowArray[curRowPosition]);
243: currentRow = setCompactRow(candidate, currentRow);
244: rowsSeen++;
245: rowsThisScan++;
246:
247: /*
248: ** Skip rows where there are start or stop positioners
249: ** that do not implement ordered null semantics and
250: ** there are columns in those positions that contain
251: ** null.
252: */
253: if (skipRow(candidate)) {
254: rowsFiltered++;
255: continue;
256: }
257:
258: result = currentRow;
259: break outer;
260: }
261: }
262: }
263:
264: setCurrentRow(result);
265: nextTime += getElapsedMillis(beginTime);
266: return result;
267: }
268:
269: /*
270: ** Load up rowArray with a batch of
271: ** rows.
272: */
273: private int reloadArray() throws StandardException {
274: curRowPosition = -1;
275: numRowsInArray = ((GroupFetchScanController) scanController)
276: .fetchNextGroup(rowArray, (RowLocation[]) null);
277:
278: return numRowsInArray;
279:
280: }
281:
282: /**
283: * If the result set has been opened,
284: * close the open scan. Delegate most
285: * of the work to TableScanResultSet.
286: *
287: * @exception StandardException on error
288: */
289: public void close() throws StandardException {
290: /*
291: ** We'll let TableScanResultSet track
292: ** the time it takes to close up, so
293: ** no timing here.
294: */
295: super .close();
296: numRowsInArray = -1;
297: curRowPosition = -1;
298: rowArray = null;
299: }
300:
301: /**
302: * Can we get instantaneous locks when getting share row
303: * locks at READ COMMITTED.
304: */
305: protected boolean canGetInstantaneousLocks() {
306: return true;
307: }
308:
309: /**
310: * @see NoPutResultSet#requiresRelocking
311: */
312: public boolean requiresRelocking() {
313: // IndexRowToBaseRow needs to relock if we didn't keep the lock
314: return (isolationLevel == TransactionController.ISOLATION_READ_COMMITTED
315: || isolationLevel == TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK || isolationLevel == TransactionController.ISOLATION_READ_UNCOMMITTED);
316: }
317: }
|