Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / impl / store / access / btree / BTreeCostController.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/store/access/btree/BTreeCostController.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/store/access/btree/BTreeCostController.java
new file mode 100644 (file)
index 0000000..80a0f98
--- /dev/null
@@ -0,0 +1,675 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.store.access.btree.BTreeCostController\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.btree;\r
+\r
+import org.apache.derby.iapi.reference.Property;\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.LogicalUndo;\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\r
+\r
+import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.ScanController;\r
+import org.apache.derby.iapi.store.access.StoreCostController;\r
+import org.apache.derby.iapi.store.access.StoreCostResult;\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.Transaction;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import java.util.Properties;\r
+\r
+/**\r
+\r
+The StoreCostController interface provides methods that an access client\r
+(most likely the system optimizer) can use to get store's estimated cost of\r
+various operations on the conglomerate the StoreCostController was opened\r
+for.\r
+<p>\r
+It is likely that the implementation of StoreCostController will open \r
+the conglomerate and will leave the conglomerate open until the\r
+StoreCostController is closed.  This represents a significant amount of\r
+work, so the caller if possible should attempt to open the StoreCostController\r
+once per unit of work and rather than close and reopen the controller.  For\r
+instance if the optimizer needs to cost 2 different scans against a single\r
+conglomerate, it should use one instance of the StoreCostController.\r
+<p>\r
+The locking behavior of the implementation of a StoreCostController is\r
+undefined, it may or may not get locks on the underlying conglomerate.  It\r
+may or may not hold locks until end of transaction.  \r
+An optimal implementation will not get any locks on the underlying \r
+conglomerate, thus allowing concurrent access to the table by a executing\r
+query while another query is optimizing.\r
+<p>\r
+@see org.apache.derby.iapi.store.access.TransactionController#openStoreCost\r
+\r
+**/\r
+\r
+public class BTreeCostController extends OpenBTree \r
+    implements StoreCostController\r
+{\r
+\r
+    // 1.5 numbers on mikem old machine:\r
+    //\r
+    // The magic numbers are based on the following benchmark results:\r
+    //\r
+    //                                         no col   one int col  all cols\r
+    //                                         ------   -----------  --------\r
+    //100 byte heap fetch by row loc, cached   0.3625     0.5098     0.6629\r
+    //100 byte heap fetch by row loc, uncached 1.3605769  1.5168269  1.5769231\r
+    //4 byte   heap fetch by row loc, cached   0.3745     0.4016     0.3766\r
+    //4 byte   heap fetch by row loc, uncached 4.1938777  3.5714285  4.4897957\r
+    //\r
+    //                                 no col    one int col  all cols\r
+    //                                 ------    -----------  --------\r
+    //Int col one level btree\r
+    //  fetch by exact key, cached     0.781     1.012         0.42\r
+    //  fetch by exact key, sort merge 1.081     1.221         0.851\r
+    //  fetch by exact key, uncached   0.0       0.0           0.0\r
+    //Int col two level btree\r
+    //  fetch by exact key, cached     1.062     1.342         0.871\r
+    //  fetch by exact key, sort merge 1.893     2.273         1.633\r
+    //  fetch by exact key, uncached   5.7238097 5.3428574     4.7714286\r
+    //String key one level btree\r
+    //  fetch by exact key, cached     1.082     0.811         0.781\r
+    //  fetch by exact key, sort merge 1.572     1.683         1.141\r
+    //  fetch by exact key, uncached   0.0       0.0           0.0\r
+    //String key two level btree\r
+    //  fetch by exact key, cached     2.143     2.664         1.953\r
+    //  fetch by exact key, sort merge 3.775     4.116         3.505\r
+    //  fetch by exact key, uncached   4.639474  5.0052633     4.4289474\r
+\r
+    // mikem new machine - insane, codeline, non-jit 1.1.7 numbers\r
+    //\r
+    //                                         no col   one int col  all cols\r
+    //                                         ------   -----------  --------\r
+    //100 byte heap fetch by row loc, cached   0.1662    0.4597      0.5618\r
+    //100 byte heap fetch by row loc, uncached 0.7565947 1.2601918   1.6690648\r
+    //4 byte   heap fetch by row loc, cached   0.1702    0.1983      0.1903\r
+    //4 byte   heap fetch by row loc, uncached 1.5068493 1.3013699   1.6438357\r
+    //\r
+    //                                 no col    one int col  all cols\r
+    //                                 ------    -----------  --------\r
+    // Int col one level btree\r
+    //   fetch by exact key, cached     0.271    0.511        0.33\r
+    //   fetch by exact key, sort merge 0.691    0.921        0.771\r
+    //   fetch by exact key, uncached   0.0      0.0          0.0\r
+    // Int col two level btree\r
+    //   fetch by exact key, cached     0.541    0.711        0.561\r
+    //   fetch by exact key, sort merge 1.432    1.682        1.533\r
+    //   fetch by exact key, uncached   3.142857 3.6285715    3.2380953\r
+    // String key one level btree\r
+    //   fetch by exact key, cached     0.611    0.851        0.701\r
+    //   fetch by exact key, sort merge 1.051    1.272        1.122\r
+    //   fetch by exact key, uncached   0.0      0.0          0.0\r
+    // String key two level btree\r
+    //   fetch by exact key, cached     1.532    1.843        1.622\r
+    //   fetch by exact key, sort merge 2.844    3.155        2.984\r
+    //   fetch by exact key, uncached   3.4      3.636842     3.531579\r
+    // \r
+\r
+\r
+    // The following costs are search costs to find a row on a leaf, use\r
+    // the heap costs to determine scan costs, for now ignore qualifier \r
+    // application and stop comparisons.\r
+    // I used the int key, 2 level numbers divided by 2 to get per level.\r
+    \r
+    private static final double \r
+        BTREE_CACHED_FETCH_BY_KEY_PER_LEVEL    = (0.541 / 2);\r
+\r
+    private static final double \r
+        BTREE_SORTMERGE_FETCH_BY_KEY_PER_LEVEL = (1.432 / 2);\r
+\r
+    private static final double \r
+        BTREE_UNCACHED_FETCH_BY_KEY_PER_LEVEL  = (3.143 / 2);\r
+\r
+    // saved values passed to init().\r
+    TransactionManager  init_xact_manager;\r
+    Transaction         init_rawtran;\r
+    Conglomerate        init_conglomerate;\r
+\r
+    /**\r
+     * Only lookup these estimates from raw store once.\r
+     **/\r
+    long    num_pages;\r
+    long    num_rows;\r
+    long    page_size;\r
+    int     tree_height;\r
+\r
+    /* Constructors for This class: */\r
+\r
+    public BTreeCostController()\r
+    {\r
+    }\r
+\r
+    /* Private/Protected methods of This class: */\r
+\r
+    /**\r
+     * Initialize the cost controller.\r
+     * <p>\r
+     * Save initialize parameters away, and open the underlying container.\r
+     * <p>\r
+     *\r
+     * @param xact_manager access manager transaction.\r
+     * @param rawtran      Raw store transaction.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public void init(\r
+    TransactionManager  xact_manager,\r
+    BTree               conglomerate,\r
+    Transaction         rawtran)\r
+        throws StandardException\r
+    {\r
+        super.init(\r
+            xact_manager, \r
+            xact_manager, \r
+            (ContainerHandle) null,         // open the btree.\r
+            rawtran, \r
+            false,\r
+            ContainerHandle.MODE_READONLY,\r
+            TransactionManager.MODE_NONE,\r
+            (BTreeLockingPolicy) null,      // RESOLVE (mikem) - this means\r
+                                            // no locks during costing - will\r
+                                            // that work?????\r
+            conglomerate, \r
+            (LogicalUndo) null,             // read only, so no undo necessary\r
+            (DynamicCompiledOpenConglomInfo) null);\r
+\r
+        // look up costs from raw store.  For btrees these numbers are out\r
+        // of whack as they want to be leaf specific numbers but they include\r
+        // every page branch and leafs.\r
+        num_pages = this.container.getEstimatedPageCount(/* unused flag */ 0);\r
+\r
+        // subtract one row for every page to account for internal control row\r
+        // which exists on every page.\r
+        num_rows  = \r
+            this.container.getEstimatedRowCount(/*unused flag*/ 0) - num_pages;\r
+\r
+        Properties prop = new Properties();\r
+        prop.put(Property.PAGE_SIZE_PARAMETER, "");\r
+        this.container.getContainerProperties(prop);\r
+        page_size = \r
+            Integer.parseInt(prop.getProperty(Property.PAGE_SIZE_PARAMETER));\r
+\r
+        tree_height = getHeight();\r
+\r
+        return;\r
+    }\r
+\r
+    /* Public Methods of This class: */\r
+\r
+    /**\r
+     * Close the controller.\r
+     * <p>\r
+     * Close the open controller.  This method always succeeds, and never \r
+     * throws any exceptions. Callers must not use the StoreCostController \r
+     * Cost controller after closing it; they are strongly advised to clear\r
+     * out the scan controller reference after closing.\r
+     * <p>\r
+     **/\r
+    public void close()\r
+        throws StandardException\r
+    {\r
+        super.close();\r
+    }\r
+\r
+    /**\r
+     * Return the cost of calling ConglomerateController.fetch().\r
+     * <p>\r
+     * Return the estimated cost of calling ConglomerateController.fetch()\r
+     * on the current conglomerate.  This gives the cost of finding a record\r
+     * in the conglomerate given the exact RowLocation of the record in\r
+     * question. \r
+     * <p>\r
+     * The validColumns parameter describes what kind of row \r
+     * is being fetched, ie. it may be cheaper to fetch a partial row than a \r
+     * complete row.\r
+     * <p>\r
+     *\r
+     *\r
+        * @param validColumns    A description of which columns to return from\r
+     *                        row on the page into "templateRow."  templateRow,\r
+     *                        and validColumns work together to\r
+     *                        describe the row to be returned by the fetch - \r
+     *                        see RowUtil for description of how these three \r
+     *                        parameters work together to describe a fetched \r
+     *                        "row".\r
+     *\r
+     * @param access_type     Describe the type of access the query will be\r
+     *                        performing to the ConglomerateController.  \r
+     *\r
+     *                        STORECOST_CLUSTERED - The location of one fetch\r
+     *                            is likely clustered "close" to the next \r
+     *                            fetch.  For instance if the query plan were\r
+     *                            to sort the RowLocations of a heap and then\r
+     *                            use those RowLocations sequentially to \r
+     *                            probe into the heap, then this flag should\r
+     *                            be specified.  If this flag is not set then\r
+     *                            access to the table is assumed to be\r
+     *                            random - ie. the type of access one gets \r
+     *                            if you scan an index and probe each row\r
+     *                            in turn into the base table is "random".\r
+     *\r
+     *\r
+        * @return The cost of the fetch.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     *\r
+        * @see org.apache.derby.iapi.store.access.RowUtil\r
+     **/\r
+    public double getFetchFromRowLocationCost(\r
+    FormatableBitSet      validColumns,\r
+    int         access_type)\r
+               throws StandardException\r
+    {\r
+        throw StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE);\r
+    }\r
+\r
+    /**\r
+     * Return the cost of exact key lookup.\r
+     * <p>\r
+     * Return the estimated cost of calling ScanController.fetch()\r
+     * on the current conglomerate, with start and stop positions set such\r
+     * that an exact match is expected.\r
+     * <p>\r
+     * This call returns the cost of a fetchNext() performed on a scan which\r
+     * has been positioned with a start position which specifies exact match\r
+     * on all keys in the row.\r
+     * <p>\r
+     * Example:\r
+     * <p>\r
+     * In the case of a btree this call can be used to determine the cost of\r
+     * doing an exact probe into btree, giving all key columns.  This cost\r
+     * can be used if the client knows it will be doing an exact key probe\r
+     * but does not have the key's at optimize time to use to make a call to\r
+     * getScanCost()\r
+     * <p>\r
+     *\r
+     *\r
+        * @param validColumns    A description of which columns to return from\r
+     *                        row on the page into "templateRow."  templateRow,\r
+     *                        and validColumns work together to\r
+     *                        describe the row to be returned by the fetch - \r
+     *                        see RowUtil for description of how these three \r
+     *                        parameters work together to describe a fetched \r
+     *                        "row".\r
+     *\r
+     * @param access_type     Describe the type of access the query will be\r
+     *                        performing to the ScanController.  \r
+     *\r
+     *                        STORECOST_CLUSTERED - The location of one scan\r
+     *                            is likely clustered "close" to the previous \r
+     *                            scan.  For instance if the query plan were\r
+     *                            to used repeated "reopenScan()'s" to probe\r
+     *                            for the next key in an index, then this flag\r
+     *                            should be be specified.  If this flag is not \r
+     *                            set then each scan will be costed independant\r
+     *                            of any other predicted scan access.\r
+     *\r
+        * @return The cost of the fetch.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     *\r
+        * @see org.apache.derby.iapi.store.access.RowUtil\r
+     **/\r
+    public double getFetchFromFullKeyCost(\r
+    FormatableBitSet      validColumns,\r
+    int         access_type)\r
+               throws StandardException\r
+    {\r
+        double ret_cost;\r
+\r
+        if ((access_type & StoreCostController.STORECOST_CLUSTERED) == 0)\r
+        {\r
+            // uncached fetch\r
+            ret_cost = BTREE_UNCACHED_FETCH_BY_KEY_PER_LEVEL;\r
+        }\r
+        else\r
+        {\r
+            ret_cost = BTREE_SORTMERGE_FETCH_BY_KEY_PER_LEVEL;\r
+        }\r
+        ret_cost *= tree_height;\r
+\r
+        return(ret_cost);\r
+    }\r
+\r
+\r
+    /**\r
+     * Calculate the cost of a scan.\r
+     * <p>\r
+     * Cause this object to calculate the cost of performing the described\r
+     * scan.  The interface is setup such that first a call is made to\r
+     * calcualteScanCost(), and then subsequent calls to accessor routines\r
+     * are made to get various pieces of information about the cost of\r
+     * the scan.\r
+     * <p>\r
+     * For the purposes of costing this routine is going to assume that \r
+     * a page will remain in cache between the time one next()/fetchNext()\r
+     * call and a subsequent next()/fetchNext() call is made within a scan.\r
+     * <p>\r
+     * The result of costing the scan is placed in the "cost_result".  \r
+     * The cost of the scan is stored by calling \r
+     * cost_result.setEstimatedCost(cost).\r
+     * The estimated row count is stored by calling \r
+     * cost_result.setEstimatedRowCount(row_count).\r
+     * <p>\r
+     * The estimated cost of the scan assumes the caller will \r
+     * execute a fetchNext() loop for every row that qualifies between\r
+     * start and stop position.  Note that this cost is different than\r
+     * execution a next(),fetch() loop; or if the scan is going to be\r
+     * terminated by client prior to reaching the stop condition.\r
+     * <p>\r
+     * The estimated number of rows returned from the scan \r
+     * assumes the caller will execute a fetchNext() loop for every \r
+     * row that qualifies between start and stop position.\r
+     * <p>\r
+     *\r
+     *\r
+     * @param scan_type       The type of scan that will be executed.  There\r
+     *                        are currently 2 types:\r
+     *                        STORECOST_SCAN_NORMAL - scans will be executed\r
+     *                        using the standard next/fetch, where each fetch\r
+     *                        can retrieve 1 or many rows (if fetchNextGroup()\r
+     *                        interface is used).\r
+     *\r
+     *                        STORECOST_SCAN_SET - The entire result set will\r
+     *                        be retrieved using the the fetchSet() interface.\r
+     *\r
+     * @param row_count       Estimated total row count of the table.  The \r
+     *                        current system tracks row counts in heaps better\r
+     *                        than btree's (btree's have "rows" which are not\r
+     *                        user rows - branch rows, control rows), so \r
+     *                        if available the client should\r
+     *                        pass in the base table's row count into this\r
+     *                        routine to be used as the index's row count.\r
+     *                        If the caller has no idea, pass in -1.\r
+     *\r
+     * @param group_size      The number of rows to be returned by a single\r
+     *                        fetch call for STORECOST_SCAN_NORMAL scans.\r
+     *\r
+        * @param forUpdate       Should be true if the caller intends to update \r
+     *                        through the scan.\r
+     * \r
+        * @param scanColumnList  A description of which columns to return from \r
+     *                        every fetch in the scan.  template, \r
+     *                        and scanColumnList work together\r
+     *                        to describe the row to be returned by the scan - \r
+     *                        see RowUtil for description of how these three \r
+     *                        parameters work together to describe a "row".\r
+     * \r
+     * @param template        A prototypical row which the scan may use to\r
+        *                        maintain its position in the conglomerate.  Not \r
+     *                        all access method scan types will require this, \r
+     *                        if they don't it's ok to pass in null.\r
+     *                        In order to scan a conglomerate one must \r
+     *                        allocate 2 separate "row" templates.  The "row" \r
+     *                        template passed into openScan is for the private\r
+     *                        use of the scan itself, and no access to it\r
+     *                        should be made by the caller while the scan is \r
+     *                        still open.  Because of this the scanner must \r
+     *                        allocate another "row" template to hold the \r
+     *                        values returned from fetch().  Note that this \r
+     *                        template must be for the full row, whether a \r
+     *                        partial row scan is being executed or not.\r
+     *\r
+        * @param startKeyValue   An indexable row which holds a (partial) key \r
+     *                        value which, in combination with the \r
+     *                        startSearchOperator, defines the starting \r
+     *                        position of the scan.  If null, the starting\r
+     *                        position of the scan is the first row of the \r
+     *                        conglomerate.  The startKeyValue must only\r
+     *                        reference columns included in the scanColumnList.\r
+     *\r
+        * @param startSearchOperator \r
+     *                        an operator which defines how the startKeyValue\r
+     *                        is to be searched for.  If startSearchOperation \r
+     *                        is ScanController.GE, the scan starts on the \r
+     *                        first row which is greater than or equal to the \r
+        *                        startKeyValue.  If startSearchOperation is \r
+     *                        ScanController.GT, the scan starts on the first\r
+     *                        row whose key is greater than startKeyValue.  The\r
+     *                        startSearchOperation parameter is ignored if the\r
+     *                        startKeyValue parameter is null.\r
+     *\r
+        * @param stopKeyValue    An indexable row which holds a (partial) key \r
+     *                        value which, in combination with the \r
+     *                        stopSearchOperator, defines the ending position\r
+     *                        of the scan.  If null, the ending position of the\r
+     *                        scan is the last row of the conglomerate.  The\r
+     *                        stopKeyValue must only reference columns included\r
+     *                        in the scanColumnList.\r
+     *\r
+        * @param stopSearchOperator\r
+     *                        an operator which defines how the stopKeyValue\r
+     *                        is used to determine the scan stopping position. \r
+     *                        If stopSearchOperation is ScanController.GE, the\r
+     *                        scan stops just before the first row which is\r
+     *                        greater than or equal to the stopKeyValue.  If \r
+     *                        stopSearchOperation is ScanController.GT, the \r
+     *                        scan stops just before the first row whose key \r
+     *                        is greater than startKeyValue.  The\r
+     *                        stopSearchOperation parameter is ignored if the\r
+     *                        stopKeyValue parameter is null.\r
+     *\r
+     *                        \r
+     * @param access_type     Describe the type of access the query will be\r
+     *                        performing to the ScanController.  \r
+     *\r
+     *                        STORECOST_CLUSTERED - The location of one scan\r
+     *                            is likely clustered "close" to the previous \r
+     *                            scan.  For instance if the query plan were\r
+     *                            to used repeated "reopenScan()'s" to probe\r
+     *                            for the next key in an index, then this flag\r
+     *                            should be be specified.  If this flag is not \r
+     *                            set then each scan will be costed independant\r
+     *                            of any other predicted scan access.\r
+     *\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     *\r
+        * @see org.apache.derby.iapi.store.access.RowUtil\r
+     **/\r
+       public void getScanCost(\r
+    int                     scan_type,\r
+    long                    row_count,\r
+    int                     group_size,\r
+    boolean                 forUpdate,\r
+    FormatableBitSet                 scanColumnList,\r
+    DataValueDescriptor[]   template,\r
+    DataValueDescriptor[]   startKeyValue,\r
+    int                     startSearchOperator,\r
+    DataValueDescriptor[]   stopKeyValue,\r
+    int                     stopSearchOperator,\r
+    boolean                 reopen_scan,\r
+    int                     access_type,\r
+    StoreCostResult         cost_result)\r
+        throws StandardException\r
+    {\r
+        float       left_of_start;\r
+        float       left_of_stop;\r
+        ControlRow  control_row = null;\r
+        long        input_row_count = (row_count < 0 ? num_rows : row_count);\r
+\r
+        try\r
+        {\r
+            // Find the starting page and row slot.\r
+            if (startKeyValue == null)\r
+            {\r
+                left_of_start = 0;\r
+            }\r
+            else\r
+            {\r
+                // Search for the starting row.\r
+\r
+                SearchParameters sp = new SearchParameters(\r
+                    startKeyValue, \r
+                    ((startSearchOperator == ScanController.GE) ? \r
+                        SearchParameters.POSITION_LEFT_OF_PARTIAL_KEY_MATCH : \r
+                        SearchParameters.POSITION_RIGHT_OF_PARTIAL_KEY_MATCH),\r
+                    template, this, true);\r
+\r
+                control_row =\r
+                    ControlRow.get(this, BTree.ROOTPAGEID).search(sp);\r
+\r
+                control_row.release();\r
+                control_row = null;\r
+\r
+                left_of_start = sp.left_fraction;\r
+            }\r
+\r
+            if (stopKeyValue == null)\r
+            {\r
+                left_of_stop = 1;\r
+            }\r
+            else\r
+            {\r
+                // Search for the stopping row.\r
+\r
+                SearchParameters sp = \r
+                    new SearchParameters(\r
+                        stopKeyValue, \r
+                        ((stopSearchOperator == ScanController.GE) ? \r
+                          SearchParameters.POSITION_LEFT_OF_PARTIAL_KEY_MATCH : \r
+                          SearchParameters.POSITION_RIGHT_OF_PARTIAL_KEY_MATCH),\r
+                        template, this, true);\r
+\r
+                control_row =\r
+                    ControlRow.get(this, BTree.ROOTPAGEID).search(sp);\r
+\r
+                control_row.release();\r
+                control_row = null;\r
+\r
+                left_of_stop = sp.left_fraction;\r
+            }\r
+\r
+            // System.out.println(\r
+              //   "\n\tleft_of_start = " + left_of_start +\r
+                // "\n\tleft_of_stop  = " + left_of_stop);\r
+\r
+            // what percentage of rows are between start and stop?\r
+\r
+            float ret_fraction = left_of_stop - left_of_start;\r
+\r
+            // If for some reason the stop position comes before the start\r
+            // position, assume 0 rows will return from query.\r
+            if (ret_fraction < 0)\r
+                ret_fraction = 0;\r
+\r
+            // Never return estimate of more rows than exist, sometimes \r
+            // the recursive estimation through the btree may return a number\r
+            // like 1.00001.\r
+            if (ret_fraction > 1)\r
+                ret_fraction = 1;\r
+\r
+            float estimated_row_count = input_row_count * ret_fraction;\r
+\r
+            // first the base cost of positioning on the first row in the scan.\r
+            double cost = \r
+                getFetchFromFullKeyCost(scanColumnList, access_type);\r
+\r
+            // add the base cost of bringing each page for the first time into\r
+            // the cache.  This is basically the cost of bringing each leaf\r
+            // uncached into the cache and reading the control row off of it.:\r
+            cost += \r
+                (num_pages * ret_fraction) * BASE_UNCACHED_ROW_FETCH_COST;\r
+\r
+            // Now some magic to try and figure out the cost of doing a\r
+            // scan along the leaf level of the tree.  Mostly just assume\r
+            // the costs are the same as the heap, and ignore qualifier\r
+            // processing and stop row comparisons for now.\r
+\r
+            // the base cost of getting each of the rows from a page assumed\r
+            // to already be cached (by the scan fetch) - this is only for all\r
+            // rows after the initial row on the page has been accounted for\r
+            // under the BASE_UNCACHED_ROW_FETCH_COST cost.:\r
+            long cached_row_count = ((long) estimated_row_count) - num_pages;\r
+            if (cached_row_count < 0)\r
+                cached_row_count = 0;\r
+\r
+            if (scan_type == StoreCostController.STORECOST_SCAN_NORMAL)\r
+                cost += cached_row_count * BASE_GROUPSCAN_ROW_COST;\r
+            else\r
+                cost += cached_row_count * BASE_HASHSCAN_ROW_FETCH_COST;\r
+\r
+            // finally add the cost associated with the number of bytes in row:\r
+            long row_size = \r
+                (input_row_count == 0) ? \r
+                    4 : (num_pages * page_size) / input_row_count;\r
+\r
+            cost += \r
+                (estimated_row_count * row_size) * BASE_ROW_PER_BYTECOST;\r
+\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                if (cost < 0)\r
+                    SanityManager.THROWASSERT("cost " + cost);\r
+\r
+                if (estimated_row_count < 0)\r
+                    SanityManager.THROWASSERT(\r
+                        "estimated_row_count = " + estimated_row_count);\r
+            }\r
+\r
+            // return the cost\r
+            cost_result.setEstimatedCost(cost);\r
+\r
+            // RESOLVE - should we make sure this number is > 0?\r
+            cost_result.setEstimatedRowCount(Math.round(estimated_row_count));\r
+        }\r
+        finally\r
+        {\r
+            if (control_row != null)\r
+                control_row.release();\r
+        }\r
+\r
+        // System.out.println("BTreeCostController.getScanCost():" + \r
+          //   "\n\t cost = " + cost_result.getEstimatedCost() +\r
+            // "\n\t rows = " + cost_result.getEstimatedRowCount());\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * Return an "empty" row location object of the correct type.\r
+     * <p>\r
+     *\r
+        * @return The empty Rowlocation.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       public RowLocation newRowLocationTemplate()\r
+               throws StandardException\r
+       {\r
+        throw StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE);\r
+       }\r
+}\r