--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.access.heap.HeapScan\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.store.access.heap;\r
+\r
+\r
+/**\r
+\r
+ A heap scan object represents an instance of an scan on a heap conglomerate.\r
+\r
+**/\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;\r
+import org.apache.derby.iapi.store.access.conglomerate.ScanManager;\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\r
+\r
+import org.apache.derby.iapi.store.access.BackingStoreHashtable;\r
+import org.apache.derby.iapi.store.access.Qualifier;\r
+import org.apache.derby.iapi.store.access.RowUtil;\r
+import org.apache.derby.iapi.store.access.ScanInfo;\r
+\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.RecordHandle;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import org.apache.derby.impl.store.access.conglomerate.GenericScanController;\r
+import org.apache.derby.impl.store.access.conglomerate.RowPosition;\r
+\r
+class HeapScan \r
+ extends GenericScanController implements ScanManager\r
+{\r
+\r
+ /**************************************************************************\r
+ * Constants of HeapScan\r
+ **************************************************************************\r
+ */\r
+\r
+ /**************************************************************************\r
+ * Fields of HeapScan\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * A 1 element array to turn fetchNext and fetch calls into \r
+ * fetchNextGroup calls.\r
+ **/\r
+ private DataValueDescriptor[][] fetchNext_one_slot_array = \r
+ new DataValueDescriptor[1][];\r
+\r
+\r
+ /**************************************************************************\r
+ * Constructors for This class:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ ** The only constructor for a heap scan returns a scan in the\r
+ ** closed state, the caller must call open.\r
+ **/\r
+ \r
+ public HeapScan()\r
+ {\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Protected concrete impl of abstract methods of \r
+ * GenericController class:\r
+ **************************************************************************\r
+ */\r
+ protected void queueDeletePostCommitWork(\r
+ RowPosition pos)\r
+ throws StandardException\r
+ {\r
+ TransactionManager xact_mgr = open_conglom.getXactMgr();\r
+\r
+ xact_mgr.addPostCommitWork(\r
+ new HeapPostCommit(\r
+ xact_mgr.getAccessManager(), \r
+ (Heap) open_conglom.getConglomerate(),\r
+ pos.current_page.getPageNumber()));\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Private/Protected methods of This class:\r
+ **************************************************************************\r
+ */\r
+ protected void setRowLocationArray(\r
+ RowLocation[] rowloc_array,\r
+ int index,\r
+ RowPosition pos)\r
+ throws StandardException\r
+ {\r
+ if (rowloc_array[index] == null)\r
+ {\r
+ rowloc_array[index] = new HeapRowLocation(pos.current_rh);\r
+ }\r
+ else\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(\r
+ rowloc_array[index] instanceof HeapRowLocation);\r
+ }\r
+\r
+ ((HeapRowLocation)rowloc_array[index]).setFrom(pos.current_rh);\r
+ }\r
+ }\r
+\r
+ protected void setRowLocationArray(\r
+ RowLocation[] rowloc_array,\r
+ int index,\r
+ RecordHandle rh)\r
+ throws StandardException\r
+ {\r
+ if (rowloc_array[index] == null)\r
+ {\r
+ rowloc_array[index] = new HeapRowLocation(rh);\r
+ }\r
+ else\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(\r
+ rowloc_array[index] instanceof HeapRowLocation);\r
+ }\r
+\r
+ ((HeapRowLocation)rowloc_array[index]).setFrom(rh);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Reposition the current scan and sets the necessary locks.\r
+ *\r
+ * @param rh An existing RecordHandle within the conglomerate,\r
+ * at which to position the start of the scan. The scan will begin at this\r
+ * location and continue forward until the end of the conglomerate. \r
+ * Positioning at a non-existent RowLocation (ie. an invalid one or one that\r
+ * had been deleted), will result in an exception being thrown when the \r
+ * first next operation is attempted.\r
+ * @return true if the scan was successfully repositioned\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ */\r
+ private boolean reopenScanByRecordHandleAndSetLocks (RecordHandle rh) \r
+ throws StandardException \r
+ {\r
+ if (rh == null) \r
+ {\r
+ return (false);\r
+ }\r
+ \r
+ // Unlock current position\r
+ if (scan_position.current_rh != null) \r
+ {\r
+ open_conglom.unlockPositionAfterRead(scan_position);\r
+ }\r
+ \r
+ // Position scan at new row\r
+ scan_position.current_rh = rh;\r
+ scan_position.current_rh_qualified = false;\r
+ \r
+ // Latch page and reposition scan\r
+ final boolean rowLocationDisappeared = \r
+ open_conglom.latchPageAndRepositionScan(scan_position);\r
+ \r
+ if (!rowLocationDisappeared)\r
+ {\r
+ setScanState(SCAN_INPROGRESS);\r
+ open_conglom.lockPositionForRead\r
+ (scan_position, null, true, true);\r
+ }\r
+ \r
+ // Unlatch page\r
+ scan_position.unlatch();\r
+ \r
+ return (!rowLocationDisappeared);\r
+ }\r
+\r
+ /**\r
+ Fetch the row at the next position of the Scan.\r
+\r
+ If there is a valid next position in the scan then\r
+ the value in the template storable row is replaced\r
+ with the value of the row at the current scan\r
+ position. The columns of the template row must\r
+ be of the same type as the actual columns in the\r
+ underlying conglomerate.\r
+\r
+ The resulting contents of templateRow after a fetchNext() \r
+ which returns false is undefined.\r
+\r
+ The result of calling fetchNext(row) is exactly logically\r
+ equivalent to making a next() call followed by a fetch(row)\r
+ call. This interface allows implementations to optimize \r
+ the 2 calls if possible.\r
+\r
+ @param fetch_row The template row into which the value\r
+ of the next position in the scan is to be stored.\r
+\r
+ @return True if there is a next position in the scan,\r
+ false if there isn't.\r
+\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public boolean fetchNext(DataValueDescriptor[] fetch_row)\r
+ throws StandardException\r
+ {\r
+ // Turn this call into a group fetch of a 1 element group.\r
+ if (fetch_row == null)\r
+ fetchNext_one_slot_array[0] = RowUtil.EMPTY_ROW;\r
+ else\r
+ fetchNext_one_slot_array[0] = fetch_row;\r
+\r
+ boolean ret_val = \r
+ fetchRows(\r
+ fetchNext_one_slot_array, \r
+ (RowLocation[]) null,\r
+ (BackingStoreHashtable) null,\r
+ 1,\r
+ (int[]) null) == 1;\r
+\r
+ return(ret_val);\r
+ }\r
+\r
+\r
+ /**\r
+ @see org.apache.derby.iapi.store.access.ScanController#next\r
+ **/\r
+ public boolean next()\r
+ throws StandardException\r
+ {\r
+ // if there is no row template from the caller, we need to\r
+ // read the row into something, Use the scratch row.\r
+ // We could optimize this, if there are no qualifiers and read\r
+ // into a zero column row, but callers should be using fetchNext()\r
+ // instead.\r
+ fetchNext_one_slot_array[0] = \r
+ open_conglom.getRuntimeMem().get_scratch_row(\r
+ open_conglom.getRawTran());\r
+\r
+ boolean ret_val = \r
+ fetchRows(\r
+ fetchNext_one_slot_array, \r
+ (RowLocation[]) null,\r
+ (BackingStoreHashtable) null,\r
+ 1,\r
+ (int[]) null) == 1;\r
+\r
+ return(ret_val);\r
+ }\r
+\r
+ /**\r
+ * @see org.apache.derby.iapi.store.access.ScanController#positionAtRowLocation\r
+ */\r
+ public boolean positionAtRowLocation(RowLocation rl) throws StandardException {\r
+ if (open_conglom.isClosed() && !rowLocationsInvalidated) \r
+ {\r
+ reopenAfterEndTransaction();\r
+ }\r
+ \r
+ if (rowLocationsInvalidated) \r
+ {\r
+ return(false);\r
+ \r
+ } else {\r
+ return(reopenScanByRecordHandleAndSetLocks\r
+ (((HeapRowLocation)rl).\r
+ getRecordHandle(open_conglom.getContainer())));\r
+ }\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Public Methods of ScanController interface:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ @see org.apache.derby.iapi.store.access.ScanController#fetchLocation\r
+ **/\r
+ public void fetchLocation(RowLocation templateLocation)\r
+ throws StandardException\r
+ {\r
+ if (open_conglom.getContainer() == null || \r
+ scan_position.current_rh == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_SCAN_NOT_POSITIONED);\r
+ }\r
+ HeapRowLocation hrl = (HeapRowLocation) templateLocation;\r
+ hrl.setFrom(scan_position.current_rh);\r
+ }\r
+\r
+ public int fetchNextGroup(\r
+ DataValueDescriptor[][] row_array,\r
+ RowLocation[] rowloc_array)\r
+ throws StandardException\r
+ {\r
+ return(\r
+ fetchRows(\r
+ row_array, \r
+ rowloc_array,\r
+ (BackingStoreHashtable) null,\r
+ row_array.length,\r
+ (int[]) null));\r
+ }\r
+\r
+ public int fetchNextGroup(\r
+ DataValueDescriptor[][] row_array,\r
+ RowLocation[] old_rowloc_array,\r
+ RowLocation[] new_rowloc_array)\r
+ throws StandardException\r
+ {\r
+ throw(StandardException.newException(\r
+ SQLState.HEAP_UNIMPLEMENTED_FEATURE));\r
+ }\r
+\r
+\r
+ /**\r
+ * Return ScanInfo object which describes performance of scan.\r
+ * <p>\r
+ * Return ScanInfo object which contains information about the current\r
+ * scan.\r
+ * <p>\r
+ *\r
+ * @see ScanInfo\r
+ *\r
+ * @return The ScanInfo object which contains info about current scan.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public ScanInfo getScanInfo()\r
+ throws StandardException\r
+ {\r
+ return(new HeapScanInfo(this));\r
+ }\r
+\r
+ /**\r
+ Reposition the current scan. This call is semantically the same as if\r
+ the current scan had been closed and a openScan() had been called instead.\r
+ The scan is reopened against the same conglomerate, and the scan\r
+ is reopened with the same "scan column list", "hold" and "forUpdate"\r
+ parameters passed in the original openScan. \r
+ <p>\r
+ The statistics gathered by the scan are not reset to 0 by a reopenScan(),\r
+ rather they continue to accumulate.\r
+ <p>\r
+ Note that this operation is currently only supported on Heap conglomerates.\r
+ Also note that order of rows within are heap are not guaranteed, so for\r
+ instance positioning at a RowLocation in the "middle" of a heap, then\r
+ inserting more data, then continuing the scan is not guaranteed to see\r
+ the new rows - they may be put in the "beginning" of the heap.\r
+\r
+ @param startRowLocation An existing RowLocation within the conglomerate,\r
+ at which to position the start of the scan. The scan will begin at this\r
+ location and continue forward until the end of the conglomerate. \r
+ Positioning at a non-existent RowLocation (ie. an invalid one or one that\r
+ had been deleted), will result in an exception being thrown when the \r
+ first next operation is attempted.\r
+\r
+ @param qualifier An array of qualifiers which, applied\r
+ to each key, restrict the rows returned by the scan. Rows\r
+ for which any one of the qualifiers returns false are not\r
+ returned by the scan. If null, all rows are returned.\r
+\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public void reopenScanByRowLocation(\r
+ RowLocation startRowLocation,\r
+ Qualifier qualifier[][])\r
+ throws StandardException\r
+ {\r
+ reopenScanByRecordHandle(\r
+ ((HeapRowLocation) startRowLocation).getRecordHandle(\r
+ open_conglom.getContainer()),\r
+ qualifier);\r
+ }\r
+\r
+\r
+ /*\r
+ ** Methods of ScanManager\r
+ */\r
+\r
+ /**\r
+ * Do work necessary to maintain the current position in the scan.\r
+ * <p>\r
+ * The latched page in the conglomerate "congomid" is changing, do\r
+ * whatever is necessary to maintain the current position of the scan.\r
+ * For some conglomerates this may be a no-op.\r
+ * <p>\r
+ *\r
+ * @param conglom Conglomerate being changed.\r
+ * @param page Page in the conglomerate being changed.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void savePosition(Conglomerate conglom, Page page)\r
+ throws StandardException\r
+ {\r
+ // RESOLVE (mikem), under the current implementation all scans within\r
+ // a transaction are called rather than just the ones with the right\r
+ // conglom. For now just have heaps ignore the call. \r
+ \r
+ // throw HeapOperationException.unimplementedFeature();\r
+ return;\r
+ }\r
+}\r