001: /*
002:
003: Derby - Class org.apache.derby.impl.store.access.heap.HeapScan
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.store.access.heap;
023:
024: /**
025:
026: A heap scan object represents an instance of an scan on a heap conglomerate.
027:
028: **/
029:
030: import org.apache.derby.iapi.reference.SQLState;
031:
032: import org.apache.derby.iapi.services.sanity.SanityManager;
033:
034: import org.apache.derby.iapi.services.io.Storable;
035:
036: import org.apache.derby.iapi.error.StandardException;
037:
038: import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;
039: import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
040: import org.apache.derby.iapi.store.access.conglomerate.ScanManager;
041: import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
042:
043: import org.apache.derby.iapi.store.access.ConglomerateController;
044: import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
045: import org.apache.derby.iapi.store.access.Qualifier;
046: import org.apache.derby.iapi.store.access.RowUtil;
047: import org.apache.derby.iapi.store.access.ScanInfo;
048: import org.apache.derby.iapi.store.access.ScanController;
049:
050: import org.apache.derby.iapi.types.RowLocation;
051:
052: import org.apache.derby.iapi.store.raw.ContainerHandle;
053: import org.apache.derby.iapi.store.raw.LockingPolicy;
054: import org.apache.derby.iapi.store.raw.Transaction;
055: import org.apache.derby.iapi.store.raw.Page;
056: import org.apache.derby.iapi.store.raw.RecordHandle;
057:
058: import org.apache.derby.iapi.types.DataValueDescriptor;
059:
060: import org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil;
061: import org.apache.derby.impl.store.access.conglomerate.GenericScanController;
062: import org.apache.derby.impl.store.access.conglomerate.RowPosition;
063:
064: import org.apache.derby.iapi.store.access.BackingStoreHashtable;
065: import org.apache.derby.iapi.services.io.FormatableBitSet;
066:
067: import java.util.Hashtable;
068: import java.util.Vector;
069:
070: class HeapScan extends GenericScanController implements ScanManager {
071:
072: /**************************************************************************
073: * Constants of HeapScan
074: **************************************************************************
075: */
076:
077: /**************************************************************************
078: * Fields of HeapScan
079: **************************************************************************
080: */
081:
082: /**
083: * A 1 element array to turn fetchNext and fetch calls into
084: * fetchNextGroup calls.
085: **/
086: private DataValueDescriptor[][] fetchNext_one_slot_array = new DataValueDescriptor[1][];
087:
088: /**************************************************************************
089: * Constructors for This class:
090: **************************************************************************
091: */
092:
093: /**
094: ** The only constructor for a heap scan returns a scan in the
095: ** closed state, the caller must call open.
096: **/
097:
098: public HeapScan() {
099: }
100:
101: /**************************************************************************
102: * Protected concrete impl of abstract methods of
103: * GenericController class:
104: **************************************************************************
105: */
106: protected void queueDeletePostCommitWork(RowPosition pos)
107: throws StandardException {
108: TransactionManager xact_mgr = open_conglom.getXactMgr();
109:
110: xact_mgr.addPostCommitWork(new HeapPostCommit(xact_mgr
111: .getAccessManager(), (Heap) open_conglom
112: .getConglomerate(), pos.current_page.getPageNumber()));
113: }
114:
115: /**************************************************************************
116: * Private/Protected methods of This class:
117: **************************************************************************
118: */
119: protected void setRowLocationArray(RowLocation[] rowloc_array,
120: int index, RowPosition pos) throws StandardException {
121: if (rowloc_array[index] == null) {
122: rowloc_array[index] = new HeapRowLocation(pos.current_rh);
123: } else {
124: if (SanityManager.DEBUG) {
125: SanityManager
126: .ASSERT(rowloc_array[index] instanceof HeapRowLocation);
127: }
128:
129: ((HeapRowLocation) rowloc_array[index])
130: .setFrom(pos.current_rh);
131: }
132: }
133:
134: protected void setRowLocationArray(RowLocation[] rowloc_array,
135: int index, RecordHandle rh) throws StandardException {
136: if (rowloc_array[index] == null) {
137: rowloc_array[index] = new HeapRowLocation(rh);
138: } else {
139: if (SanityManager.DEBUG) {
140: SanityManager
141: .ASSERT(rowloc_array[index] instanceof HeapRowLocation);
142: }
143:
144: ((HeapRowLocation) rowloc_array[index]).setFrom(rh);
145: }
146: }
147:
148: /**
149: * Reposition the current scan and sets the necessary locks.
150: *
151: * @param rh An existing RecordHandle within the conglomerate,
152: * at which to position the start of the scan. The scan will begin at this
153: * location and continue forward until the end of the conglomerate.
154: * Positioning at a non-existent RowLocation (ie. an invalid one or one that
155: * had been deleted), will result in an exception being thrown when the
156: * first next operation is attempted.
157: * @return true if the scan was successfully repositioned
158: *
159: * @exception StandardException Standard exception policy.
160: */
161: private boolean reopenScanByRecordHandleAndSetLocks(RecordHandle rh)
162: throws StandardException {
163: if (rh == null) {
164: return (false);
165: }
166:
167: // Unlock current position
168: if (scan_position.current_rh != null) {
169: open_conglom.unlockPositionAfterRead(scan_position);
170: }
171:
172: // Position scan at new row
173: scan_position.current_rh = rh;
174: scan_position.current_rh_qualified = false;
175:
176: // Latch page and reposition scan
177: final boolean rowLocationDisappeared = open_conglom
178: .latchPageAndRepositionScan(scan_position);
179:
180: if (!rowLocationDisappeared) {
181: setScanState(SCAN_INPROGRESS);
182: open_conglom.lockPositionForRead(scan_position, null, true,
183: true);
184: }
185:
186: // Unlatch page
187: scan_position.unlatch();
188:
189: return (!rowLocationDisappeared);
190: }
191:
192: /**
193: Fetch the row at the next position of the Scan.
194:
195: If there is a valid next position in the scan then
196: the value in the template storable row is replaced
197: with the value of the row at the current scan
198: position. The columns of the template row must
199: be of the same type as the actual columns in the
200: underlying conglomerate.
201:
202: The resulting contents of templateRow after a fetchNext()
203: which returns false is undefined.
204:
205: The result of calling fetchNext(row) is exactly logically
206: equivalent to making a next() call followed by a fetch(row)
207: call. This interface allows implementations to optimize
208: the 2 calls if possible.
209:
210: @param fetch_row The template row into which the value
211: of the next position in the scan is to be stored.
212:
213: @return True if there is a next position in the scan,
214: false if there isn't.
215:
216: @exception StandardException Standard exception policy.
217: **/
218: public boolean fetchNext(DataValueDescriptor[] fetch_row)
219: throws StandardException {
220: // Turn this call into a group fetch of a 1 element group.
221: if (fetch_row == null)
222: fetchNext_one_slot_array[0] = RowUtil.EMPTY_ROW;
223: else
224: fetchNext_one_slot_array[0] = fetch_row;
225:
226: boolean ret_val = fetchRows(fetchNext_one_slot_array,
227: (RowLocation[]) null, (BackingStoreHashtable) null, 1,
228: (int[]) null) == 1;
229:
230: return (ret_val);
231: }
232:
233: /**
234: @see ScanController#next
235: **/
236: public boolean next() throws StandardException {
237: // if there is no row template from the caller, we need to
238: // read the row into something, Use the scratch row.
239: // We could optimize this, if there are no qualifiers and read
240: // into a zero column row, but callers should be using fetchNext()
241: // instead.
242: fetchNext_one_slot_array[0] = open_conglom.getRuntimeMem()
243: .get_scratch_row();
244:
245: boolean ret_val = fetchRows(fetchNext_one_slot_array,
246: (RowLocation[]) null, (BackingStoreHashtable) null, 1,
247: (int[]) null) == 1;
248:
249: return (ret_val);
250: }
251:
252: /**
253: * @see ScanController#positionAtRowLocation
254: */
255: public boolean positionAtRowLocation(RowLocation rl)
256: throws StandardException {
257: if (open_conglom.isClosed() && !rowLocationsInvalidated) {
258: reopenAfterEndTransaction();
259: }
260:
261: if (rowLocationsInvalidated) {
262: return (false);
263:
264: } else {
265: return (reopenScanByRecordHandleAndSetLocks(((HeapRowLocation) rl)
266: .getRecordHandle(open_conglom.getContainer())));
267: }
268: }
269:
270: /**************************************************************************
271: * Public Methods of ScanController interface:
272: **************************************************************************
273: */
274:
275: /**
276: @see ScanController#fetchLocation
277: **/
278: public void fetchLocation(RowLocation templateLocation)
279: throws StandardException {
280: if (open_conglom.getContainer() == null
281: || scan_position.current_rh == null) {
282: throw StandardException
283: .newException(SQLState.HEAP_SCAN_NOT_POSITIONED);
284: }
285: HeapRowLocation hrl = (HeapRowLocation) templateLocation;
286: hrl.setFrom(scan_position.current_rh);
287: }
288:
289: public int fetchNextGroup(DataValueDescriptor[][] row_array,
290: RowLocation[] rowloc_array) throws StandardException {
291: return (fetchRows(row_array, rowloc_array,
292: (BackingStoreHashtable) null, row_array.length,
293: (int[]) null));
294: }
295:
296: public int fetchNextGroup(DataValueDescriptor[][] row_array,
297: RowLocation[] old_rowloc_array,
298: RowLocation[] new_rowloc_array) throws StandardException {
299: throw (StandardException
300: .newException(SQLState.HEAP_UNIMPLEMENTED_FEATURE));
301: }
302:
303: /**
304: * Return ScanInfo object which describes performance of scan.
305: * <p>
306: * Return ScanInfo object which contains information about the current
307: * scan.
308: * <p>
309: *
310: * @see ScanInfo
311: *
312: * @return The ScanInfo object which contains info about current scan.
313: *
314: * @exception StandardException Standard exception policy.
315: **/
316: public ScanInfo getScanInfo() throws StandardException {
317: return (new HeapScanInfo(this ));
318: }
319:
320: /**
321: Reposition the current scan. This call is semantically the same as if
322: the current scan had been closed and a openScan() had been called instead.
323: The scan is reopened against the same conglomerate, and the scan
324: is reopened with the same "scan column list", "hold" and "forUpdate"
325: parameters passed in the original openScan.
326: <p>
327: The statistics gathered by the scan are not reset to 0 by a reopenScan(),
328: rather they continue to accumulate.
329: <p>
330: Note that this operation is currently only supported on Heap conglomerates.
331: Also note that order of rows within are heap are not guaranteed, so for
332: instance positioning at a RowLocation in the "middle" of a heap, then
333: inserting more data, then continuing the scan is not guaranteed to see
334: the new rows - they may be put in the "beginning" of the heap.
335:
336: @param startRowLocation An existing RowLocation within the conglomerate,
337: at which to position the start of the scan. The scan will begin at this
338: location and continue forward until the end of the conglomerate.
339: Positioning at a non-existent RowLocation (ie. an invalid one or one that
340: had been deleted), will result in an exception being thrown when the
341: first next operation is attempted.
342:
343: @param qualifier An array of qualifiers which, applied
344: to each key, restrict the rows returned by the scan. Rows
345: for which any one of the qualifiers returns false are not
346: returned by the scan. If null, all rows are returned.
347:
348: @exception StandardException Standard exception policy.
349: **/
350: public void reopenScanByRowLocation(RowLocation startRowLocation,
351: Qualifier qualifier[][]) throws StandardException {
352: reopenScanByRecordHandle(((HeapRowLocation) startRowLocation)
353: .getRecordHandle(open_conglom.getContainer()),
354: qualifier);
355: }
356:
357: /*
358: ** Methods of ScanManager
359: */
360:
361: /**
362: * Do work necessary to maintain the current position in the scan.
363: * <p>
364: * The latched page in the conglomerate "congomid" is changing, do
365: * whatever is necessary to maintain the current position of the scan.
366: * For some conglomerates this may be a no-op.
367: * <p>
368: *
369: * @param conglom Conglomerate being changed.
370: * @param page Page in the conglomerate being changed.
371: *
372: * @exception StandardException Standard exception policy.
373: **/
374: public void savePosition(Conglomerate conglom, Page page)
375: throws StandardException {
376: // RESOLVE (mikem), under the current implementation all scans within
377: // a transaction are called rather than just the ones with the right
378: // conglom. For now just have heaps ignore the call.
379:
380: // throw HeapOperationException.unimplementedFeature();
381: return;
382: }
383: }
|