Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / impl / sql / execute / MultiProbeTableScanResultSet.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/execute/MultiProbeTableScanResultSet.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/execute/MultiProbeTableScanResultSet.java
new file mode 100644 (file)
index 0000000..8e919c6
--- /dev/null
@@ -0,0 +1,425 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.execute.MultiProbeTableScanResultSet\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.sql.execute;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.loader.GeneratedMethod;\r
+\r
+import org.apache.derby.iapi.store.access.Qualifier;\r
+import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.compile.RowOrdering;\r
+import org.apache.derby.iapi.sql.execute.CursorResultSet;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+// These are for javadoc "@see" tags.\r
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;\r
+import org.apache.derby.iapi.sql.execute.ResultSetFactory;\r
+\r
+/**\r
+ * Result set that fetches rows from a scan by "probing" the underlying\r
+ * table with a given list of values.  Repeated calls to getNextRowCore()\r
+ * will first return all rows matching probeValues[0], then all rows matching\r
+ * probeValues[1], and so on (duplicate probe values are ignored).  Once all\r
+ * matching rows for all values in probeValues have been returned, the call\r
+ * to getNextRowCore() will return null, thereby ending the scan. The\r
+ * expectation is that this kind of result set only ever appears beneath\r
+ * some other top-level result set (esp. IndexRowToBaseRowResultSet), in\r
+ * which case all result sets higher up in the result set tree will just\r
+ * see a stream of rows satisfying the list of probe values.\r
+ *\r
+ * Currently this type of result is used for evaluation of IN lists, where\r
+ * the user wants to retrieve all rows for which some target column has a\r
+ * value that equals one of values in the IN list.  In that case the IN list\r
+ * values are represented by the probeValues array.\r
+ *\r
+ * Most of the work for this class is inherited from TableScanResultSet. \r
+ * This class overrides four public methods and two protected methods\r
+ * from TableScanResultSet.  In all cases the methods here set probing\r
+ * state and then call the corresponding methods on "super".\r
+ */\r
+class MultiProbeTableScanResultSet extends TableScanResultSet\r
+    implements CursorResultSet\r
+{\r
+    /** The values with which we will probe the table. */\r
+    protected DataValueDescriptor [] probeValues;\r
+    /**\r
+     * The values with which we will probe the table, as they were passed to\r
+     * the constructor. We need to keep them unchanged in case the result set\r
+     * is reused when a statement is re-executed (see DERBY-827).\r
+     */\r
+    protected DataValueDescriptor [] origProbeValues;\r
+\r
+    /**\r
+     * 0-based position of the <b>next</b> value to lookup w.r.t. the probe\r
+     * values list.\r
+     */\r
+    protected int probeValIndex;\r
+\r
+    /**\r
+     * Indicator as to which type of sort we need: ASCENDING, DESCENDING,\r
+     * or NONE (NONE is represented by "RowOrdering.DONTCARE" and is used\r
+     * for cases where all necessary sorting occurred at compilation time).\r
+     */\r
+    private int sortRequired;\r
+\r
+    /**\r
+     * Constructor.  Just save off the relevant probing state and pass\r
+     * everything else up to TableScanResultSet.\r
+     * \r
+     * @see ResultSetFactory#getMultiProbeTableScanResultSet\r
+     * @exception StandardException thrown on failure to open\r
+     */\r
+    MultiProbeTableScanResultSet(long conglomId,\r
+        StaticCompiledOpenConglomInfo scoci, Activation activation, \r
+        GeneratedMethod resultRowAllocator, \r
+        int resultSetNumber,\r
+        GeneratedMethod startKeyGetter, int startSearchOperator,\r
+        GeneratedMethod stopKeyGetter, int stopSearchOperator,\r
+        boolean sameStartStopPosition,\r
+        Qualifier[][] qualifiers,\r
+        DataValueDescriptor [] probingVals,\r
+        int sortRequired,\r
+        String tableName,\r
+        String userSuppliedOptimizerOverrides,\r
+        String indexName,\r
+        boolean isConstraint,\r
+        boolean forUpdate,\r
+        int colRefItem,\r
+        int indexColItem,\r
+        int lockMode,\r
+        boolean tableLocked,\r
+        int isolationLevel,\r
+        boolean oneRowScan,\r
+        double optimizerEstimatedRowCount,\r
+        double optimizerEstimatedCost)\r
+            throws StandardException\r
+    {\r
+        /* Note: We use '1' as rows per read because we do not currently\r
+         * allow bulk fetching when multi-probing.  If that changes in\r
+         * the future then we will need to update rowsPerRead accordingly.\r
+         */\r
+        super(conglomId,\r
+            scoci,\r
+            activation,\r
+            resultRowAllocator,\r
+            resultSetNumber,\r
+            startKeyGetter,\r
+            startSearchOperator,\r
+            stopKeyGetter,\r
+            stopSearchOperator,\r
+            sameStartStopPosition,\r
+            qualifiers,\r
+            tableName,\r
+            userSuppliedOptimizerOverrides,\r
+            indexName,\r
+            isConstraint,\r
+            forUpdate,\r
+            colRefItem,\r
+            indexColItem,\r
+            lockMode,\r
+            tableLocked,\r
+            isolationLevel,\r
+            1, // rowsPerRead\r
+            oneRowScan,\r
+            optimizerEstimatedRowCount,\r
+            optimizerEstimatedCost);\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            SanityManager.ASSERT(\r
+                (probingVals != null) && (probingVals.length > 0),\r
+                "No probe values found for multi-probe scan.");\r
+        }\r
+\r
+        this.origProbeValues = probingVals;\r
+        this.sortRequired = sortRequired;\r
+    }\r
+\r
+    /**\r
+     * @see NoPutResultSet#openCore\r
+     */\r
+    public void openCore() throws StandardException\r
+    {\r
+        /* If the probe values are not already sorted then sort them now.  This\r
+         * allows us to skip over duplicate probe values (otherwise we could\r
+         * end up with duplicate rows in the result set).\r
+         *\r
+         * Note: If all of the probe values were provided as constants then we\r
+         * sorted them at compile time (during preprocessing) so we don't have\r
+         * to do it now. But if one or more was specified as a param then we\r
+         * have to do the sort here, at execution time, because this is the\r
+         * only point at which we know what values the parameters have.\r
+         */\r
+        if (sortRequired == RowOrdering.DONTCARE)\r
+        {\r
+            /* DONTCARE really means that the values are already sorted\r
+             * in ascending order, and that's good enough.\r
+             */\r
+            probeValues = origProbeValues;\r
+        }\r
+        else\r
+        {\r
+            /* RESOLVE: For some reason sorting the probeValues array\r
+             * directly leads to incorrect parameter value assignment when\r
+             * executing a prepared statement multiple times.  Need to figure\r
+             * out why (maybe related to DERBY-827?).  In the meantime, if\r
+             * we're going to sort the values we use clones.  This is not\r
+             * ideal, but it works for now.\r
+             */\r
+            DataValueDescriptor [] pVals =\r
+                new DataValueDescriptor[origProbeValues.length];\r
+\r
+            for (int i = 0; i < pVals.length; i++)\r
+                pVals[i] = origProbeValues[i].getClone();\r
+\r
+            if (sortRequired == RowOrdering.ASCENDING)\r
+                java.util.Arrays.sort(pVals);\r
+            else\r
+            {\r
+                // Sort the values in DESCENDING order.\r
+                java.util.Arrays.sort(\r
+                    pVals, java.util.Collections.reverseOrder());\r
+            }\r
+\r
+            probeValues = pVals;\r
+        }\r
+\r
+        probeValIndex = 0;\r
+        super.openCore();\r
+    }\r
+\r
+    /**\r
+     * Open the scan controller\r
+     *\r
+     * @param tc transaction controller; will open one if null.\r
+     * @exception StandardException thrown on failure to open\r
+     */\r
+    protected void openScanController(TransactionController tc)\r
+        throws StandardException\r
+    {\r
+        /* If we're opening the scan controller for the first time then\r
+         * we want to use the first value in the (now sorted) list as\r
+         * the start/stop key.  That's what we pass in here.\r
+         */\r
+        openScanController(tc, probeValues[0]);\r
+\r
+        /* probeValIndex should be the index of the *next* value to\r
+         * use.  Since we just positioned ourselves at the 0th probe\r
+         * value with the above call, the next value we want is the\r
+         * one at index "1".\r
+         */\r
+        probeValIndex = 1;\r
+    }\r
+\r
+    /**\r
+     * @see NoPutResultSet#reopenCore\r
+     */\r
+    public void reopenCore() throws StandardException\r
+    {\r
+        reopenCore(false);\r
+    }\r
+\r
+    /**\r
+     * There are two scenarios for which we reopen this kind of scan:\r
+     *\r
+     *   A - The first is for join processing.  In this case we have\r
+     * a(nother) row from some outer table and we want to reopen this\r
+     * scan to look for rows matching the new outer row.\r
+     *\r
+     *   B - The second is for multi-probing.  Here we want to reopen\r
+     * the scan on this table to look for rows matching the next value\r
+     * in the probe list.\r
+     *\r
+     * If we are reopening the scan for scenario A (join processing)\r
+     * then we need to reset our position within the probe list. \r
+     * If we are reopening the scan for scenario B then we do *not*\r
+     * want to reset our position within the probe list because that\r
+     * position tells us where to find the next probe value.\r
+     *\r
+     * That said, this method does the work of reopenCore() using\r
+     * the received boolean to determine which of the two scenarios\r
+     * we are in.  Note that if our current position (i.e. the value\r
+     * of probeValIndex) is beyond the length of the probe list then\r
+     * we know that we are reopening the scan for scenario A.  Or put\r
+     * another away, we should never get here for scenario B if\r
+     * probeValIndex is greater than or equal to the length of the\r
+     * probe list.  The reason is that the call to reopenCore() for\r
+     * scenario B will only ever happen when moreInListVals() returns\r
+     * true--and in that case we know that probeValIndex will be less\r
+     * than the length of the probeValues.  But the opposite is not\r
+     * true: i.e. it is *not* safe to say that a probeValIndex which\r
+     * is less than the length of probe list is always for scenario\r
+     * B.  That's not true because it's possible that the join to\r
+     * which this scan belongs is a "oneRowRightSide" join, meaning\r
+     * that this, the "right" side scan, will be "interrupted" after\r
+     * we return a single row for the current outer row.  If we then\r
+     * come back with a new outer row we need to reset our position--\r
+     * even though probeValIndex will be less than probeValues.length\r
+     * in that case.  DERBY-3603.\r
+     */\r
+    private void reopenCore(boolean forNextProbe) throws StandardException\r
+    {\r
+        if (!forNextProbe)\r
+            probeValIndex = 0;\r
+\r
+        super.reopenCore();\r
+    }\r
+\r
+    /**\r
+     * Reopen the scan controller\r
+     *\r
+     * @exception StandardException thrown on failure to open\r
+     */\r
+    protected void reopenScanController() throws StandardException\r
+    {\r
+        /* If we're looking for the first value in the probe list, then\r
+         * reset the row scan count.  Otherwise leave it unchanged since\r
+         * we're just continuing an already-opened scan.  Note that we\r
+         * have to do this check *before* we call getNextProbeValue()\r
+         * because that method will increment probeValIndex.\r
+         */\r
+        if (probeValIndex == 0)\r
+            rowsThisScan = 0;\r
+\r
+        DataValueDescriptor pv = null;\r
+        if (moreInListVals())\r
+        {\r
+            pv = getNextProbeValue();\r
+            if (pv == null)\r
+            {\r
+                /* We'll get here when we've exhausted the probe list. In\r
+                 * that case leave the scan as it is, which effectively\r
+                 * means we are done.\r
+                 */\r
+                return;\r
+            }\r
+        }\r
+\r
+        reopenScanController(pv);\r
+    }\r
+\r
+    /**\r
+     * Return the next row (if any) from the scan (if open).\r
+     *\r
+     * More specifically we do the following:\r
+     *\r
+     *  1 - See if we have a row to read from the current scan position.\r
+     *    If so, return that row (done).\r
+     *\r
+     *  2 - If there are no more rows to read from the current scan\r
+     *    position AND if there are more probe values to look at,\r
+     *    then a) reposition the scan using the next probe value\r
+     *    as the start/stop key and b) go back to step 1.  Otherwise\r
+     *    proceed to step 3.\r
+     *    \r
+     *  3 - Return null (no more rows).\r
+     *\r
+     * Note that step 1 is important for cases where multiple rows in this\r
+     * table match a single probe value.  In such a scenario we have to\r
+     * be sure that we do *not* move on to the next probe value until\r
+     * we have returned all of the rows for the _current_ probe value.\r
+     *\r
+     * @exception StandardException thrown on failure to get next row\r
+     */\r
+    public ExecRow getNextRowCore() throws StandardException\r
+    {\r
+        checkCancellationFlag();\r
+\r
+        // Step 1.\r
+        ExecRow result = super.getNextRowCore();\r
+\r
+        // Steps 2, 1, 2, 1, 2, ...\r
+        while ((result == null) && moreInListVals())\r
+        {\r
+            /* Repositioning the scan (if needed) is simply a matter of\r
+             * reopening the core scan again. As part of that method we will\r
+             * figure out what the next probe value should be (and thus\r
+             * where to position the scan).\r
+             */\r
+            reopenCore(true);\r
+            result = super.getNextRowCore();\r
+        }\r
+\r
+        // Step 3: result will be null if there are no more rows.\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * @see NoPutResultSet#close\r
+     */\r
+    public void close() throws StandardException\r
+    {\r
+        /* We'll let TableScanResultSet track the time it takes to close up,\r
+         * so no timing here.\r
+         */\r
+        super.close();\r
+\r
+        /* Note: We can't set probeValues == null here because we may end\r
+         * up reopening this scan again later, in which case we'll need the\r
+         * list of probe values.\r
+         */\r
+    }\r
+\r
+    /**\r
+     * Figure out whether or not we can (re-)position the scan\r
+     * controller based on the next value in probeValues.  This\r
+     * will return false when we have exhausted the probe list\r
+     * (i.e. when we've gone through all of the values).\r
+     */\r
+    private boolean moreInListVals()\r
+    {\r
+        return (probeValIndex < probeValues.length);\r
+    }\r
+\r
+    /**\r
+     * Return the next non-duplicate value from the probe list.\r
+     * Assumption is that the list is sorted so that duplicates\r
+     * appear next to each other, and that probeValIndex is the\r
+     * index of the next value. If we've exhausted the probe list\r
+     * then just return null.\r
+     */\r
+    private DataValueDescriptor getNextProbeValue()\r
+        throws StandardException\r
+    {\r
+        int ctr = probeValIndex;\r
+\r
+        // Skip over duplicate values.\r
+        while ((ctr > 0) && (ctr < probeValues.length) &&\r
+            probeValues[probeValIndex-1].equals(probeValues[ctr]))\r
+        {\r
+            ctr++;\r
+        }\r
+\r
+        probeValIndex = ctr;\r
+        if (probeValIndex < probeValues.length)\r
+            return probeValues[probeValIndex++];\r
+\r
+        return null;\r
+    }\r
+}\r