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 / HashScanResultSet.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/execute/HashScanResultSet.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/execute/HashScanResultSet.java
new file mode 100644 (file)
index 0000000..e45322a
--- /dev/null
@@ -0,0 +1,778 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.execute.HashScanResultSet\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 java.util.List;\r
+import java.util.Properties;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.i18n.MessageService;\r
+import org.apache.derby.iapi.services.io.FormatableArrayHolder;\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import org.apache.derby.iapi.services.io.FormatableIntHolder;\r
+import org.apache.derby.iapi.services.io.Storable;\r
+import org.apache.derby.iapi.services.loader.GeneratedMethod;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.execute.CursorResultSet;\r
+import org.apache.derby.iapi.sql.execute.ExecIndexRow;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;\r
+import org.apache.derby.iapi.store.access.BackingStoreHashtable;\r
+import org.apache.derby.iapi.store.access.KeyHasher;\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.ScanController;\r
+import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+/**\r
+ * Takes a conglomerate and a table filter builds a hash table on the \r
+ * specified column of the conglomerate on the 1st open.  Look up into the\r
+ * hash table is done on the hash key column.  The hash table consists of\r
+ * either <code>DataValueDescriptor[]</code>s or <code>List</code>s of\r
+ * <code>DataValueDescriptor[]</code>. The store builds the hash table. When a\r
+ * collision occurs, the store builds a <code>List</code> with the colliding\r
+ * <code>DataValueDescriptor[]</code>s.\r
+ */\r
+public class HashScanResultSet extends ScanResultSet\r
+       implements CursorResultSet\r
+{\r
+       private boolean         hashtableBuilt;\r
+       private ExecIndexRow    startPosition;\r
+       private ExecIndexRow    stopPosition;\r
+       protected       ExecRow         compactRow;\r
+\r
+       // Variable for managing next() logic on hash entry\r
+       protected boolean       firstNext = true;\r
+       private int                     numFetchedOnNext;\r
+       private int                     entryVectorSize;\r
+       private List            entryVector;\r
+\r
+    // set in constructor and not altered during\r
+    // life of object.\r
+    private long conglomId;\r
+    protected StaticCompiledOpenConglomInfo scoci;\r
+       private GeneratedMethod resultRowAllocator;\r
+       private GeneratedMethod startKeyGetter;\r
+       private int startSearchOperator;\r
+       private GeneratedMethod stopKeyGetter;\r
+       private int stopSearchOperator;\r
+       public Qualifier[][] scanQualifiers;\r
+       public Qualifier[][] nextQualifiers;\r
+       private int initialCapacity;\r
+       private float loadFactor;\r
+       private int maxCapacity;\r
+       public String tableName;\r
+       public String userSuppliedOptimizerOverrides;\r
+       public String indexName;\r
+       public boolean forUpdate;\r
+       private boolean runTimeStatisticsOn;\r
+       private FormatableBitSet accessedCols;\r
+       public int[] keyColumns;\r
+       private boolean sameStartStopPosition;\r
+       private boolean skipNullKeyColumns;\r
+       private boolean keepAfterCommit;\r
+\r
+       protected BackingStoreHashtable hashtable;\r
+       protected boolean eliminateDuplicates;          // set to true in DistinctScanResultSet\r
+\r
+       // Run time statistics\r
+       public Properties scanProperties;\r
+       public String startPositionString;\r
+       public String stopPositionString;\r
+       public int hashtableSize;\r
+       public boolean isConstraint;\r
+\r
+       public static final     int     DEFAULT_INITIAL_CAPACITY = -1;\r
+       public static final float DEFAULT_LOADFACTOR = (float) -1.0;\r
+       public static final     int     DEFAULT_MAX_CAPACITY = -1;\r
+\r
+\r
+    //\r
+    // class interface\r
+    //\r
+    HashScanResultSet(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[][] scanQualifiers,\r
+               Qualifier[][] nextQualifiers,\r
+               int initialCapacity,\r
+               float loadFactor,\r
+               int maxCapacity,\r
+               int hashKeyItem,\r
+               String tableName,\r
+               String userSuppliedOptimizerOverrides,\r
+               String indexName,\r
+               boolean isConstraint,\r
+               boolean forUpdate,\r
+               int colRefItem,\r
+               int lockMode,\r
+               boolean tableLocked,\r
+               int isolationLevel,\r
+               boolean skipNullKeyColumns,\r
+               double optimizerEstimatedRowCount,\r
+               double optimizerEstimatedCost)\r
+                       throws StandardException\r
+    {\r
+               super(activation,\r
+                               resultSetNumber,\r
+                               resultRowAllocator,\r
+                               lockMode, tableLocked, isolationLevel,\r
+                               optimizerEstimatedRowCount,\r
+                               optimizerEstimatedCost);\r
+        this.scoci = scoci;\r
+        this.conglomId = conglomId;\r
+\r
+               if (SanityManager.DEBUG) {\r
+                       SanityManager.ASSERT( activation!=null, "hash scan must get activation context");\r
+                       SanityManager.ASSERT( resultRowAllocator!= null, "hash scan must get row allocator");\r
+                       if (sameStartStopPosition)\r
+                       {\r
+                               SanityManager.ASSERT(stopKeyGetter == null,\r
+                                       "stopKeyGetter expected to be null when sameStartStopPosition is true");\r
+                       }\r
+               }\r
+\r
+        this.resultRowAllocator = resultRowAllocator;\r
+\r
+               this.startKeyGetter = startKeyGetter;\r
+               this.startSearchOperator = startSearchOperator;\r
+               this.stopKeyGetter = stopKeyGetter;\r
+               this.stopSearchOperator = stopSearchOperator;\r
+               this.sameStartStopPosition = sameStartStopPosition;\r
+               this.scanQualifiers = scanQualifiers;\r
+               this.nextQualifiers = nextQualifiers;\r
+               this.initialCapacity = initialCapacity;\r
+               this.loadFactor = loadFactor;\r
+               this.maxCapacity = maxCapacity;\r
+        this.tableName = tableName;\r
+        this.userSuppliedOptimizerOverrides = userSuppliedOptimizerOverrides;\r
+        this.indexName = indexName;\r
+               this.isConstraint = isConstraint;\r
+               this.forUpdate = forUpdate;\r
+               this.skipNullKeyColumns = skipNullKeyColumns;\r
+               this.keepAfterCommit = activation.getResultSetHoldability();\r
+\r
+               /* Retrieve the hash key columns */\r
+               FormatableArrayHolder fah = (FormatableArrayHolder)\r
+                                                                               (activation.getPreparedStatement().\r
+                                                                                       getSavedObject(hashKeyItem));\r
+               FormatableIntHolder[] fihArray = (FormatableIntHolder[]) fah.getArray(FormatableIntHolder.class);\r
+               keyColumns = new int[fihArray.length];\r
+               for (int index = 0; index < fihArray.length; index++)\r
+               {\r
+                       keyColumns[index] = fihArray[index].getInt();\r
+               }\r
+\r
+               // retrieve the valid column list from\r
+               // the saved objects, if it exists\r
+               this.accessedCols = null;\r
+               if (colRefItem != -1)\r
+               {\r
+                       this.accessedCols = (FormatableBitSet)(activation.getPreparedStatement().\r
+                                                                                 getSavedObject(colRefItem));\r
+               }\r
+\r
+               runTimeStatisticsOn = \r
+            getLanguageConnectionContext().getRunTimeStatisticsMode();\r
+\r
+               compactRow =\r
+                               getCompactRow(candidate, accessedCols, (FormatableBitSet) null, false);\r
+               constructorTime += getElapsedMillis(beginTime);\r
+    }\r
+\r
+       //\r
+       // ResultSet interface (leftover from NoPutResultSet)\r
+       //\r
+\r
+       /**\r
+        * Can we get instantaneous locks when getting share row\r
+        * locks at READ COMMITTED.\r
+        */\r
+       boolean canGetInstantaneousLocks() {\r
+               return true;\r
+       }\r
+\r
+       /**\r
+     * open a scan on the table. scan parameters are evaluated\r
+     * at each open, so there is probably some way of altering\r
+     * their values...\r
+        *\r
+        * @exception StandardException thrown on failure to open\r
+     */\r
+       public void     openCore() throws StandardException\r
+       {\r
+           TransactionController tc;\r
+\r
+               beginTime = getCurrentTimeMillis();\r
+               if (SanityManager.DEBUG)\r
+                   SanityManager.ASSERT( ! isOpen, "HashScanResultSet already open");\r
+\r
+        // Get the current transaction controller\r
+        tc = activation.getTransactionController();\r
+\r
+               initIsolationLevel();\r
+\r
+               if (startKeyGetter != null)\r
+               {\r
+                       startPosition = (ExecIndexRow) startKeyGetter.invoke(activation);\r
+                       if (sameStartStopPosition)\r
+                       {\r
+                               stopPosition = startPosition;\r
+                       }\r
+               }\r
+               if (stopKeyGetter != null)\r
+               {\r
+                       stopPosition = (ExecIndexRow) stopKeyGetter.invoke(activation);\r
+               }\r
+\r
+               // Check whether there are any comparisons with unordered nulls\r
+               // on either the start or stop position.  If there are, we can\r
+               // (and must) skip the scan, because no rows can qualify\r
+               if (skipScan(startPosition, stopPosition))\r
+               {\r
+                       // Do nothing\r
+                       ;\r
+               }\r
+               else if (! hashtableBuilt)\r
+               {\r
+                       DataValueDescriptor[] startPositionRow = \r
+                startPosition == null ? null : startPosition.getRowArray();\r
+                       DataValueDescriptor[] stopPositionRow = \r
+                stopPosition == null ? null : stopPosition.getRowArray();\r
+\r
+            hashtable = \r
+                tc.createBackingStoreHashtableFromScan(\r
+                    conglomId,          // conglomerate to open\r
+                    (forUpdate ? TransactionController.OPENMODE_FORUPDATE : 0),\r
+                    lockMode,\r
+                    isolationLevel,\r
+                    accessedCols, \r
+                    startPositionRow,   \r
+                    startSearchOperator,\r
+                    scanQualifiers,\r
+                    stopPositionRow,   \r
+                    stopSearchOperator,\r
+                    -1,                 // no limit on total rows.\r
+                    keyColumns,      \r
+                    eliminateDuplicates,// remove duplicates?\r
+                    -1,                 // RESOLVE - is there a row estimate?\r
+                    maxCapacity,\r
+                    initialCapacity,    // in memory Hashtable initial capacity\r
+                    loadFactor,         // in memory Hashtable load factor\r
+                    runTimeStatisticsOn,\r
+                                       skipNullKeyColumns,\r
+                                       keepAfterCommit);\r
+\r
+\r
+                       if (runTimeStatisticsOn)\r
+                       {\r
+                               hashtableSize = hashtable.size();\r
+\r
+                               if (scanProperties == null)\r
+                               {\r
+                                       scanProperties = new Properties();\r
+                               }\r
+\r
+                               try\r
+                               {\r
+                                       if (hashtable != null)\r
+                                       {\r
+                        hashtable.getAllRuntimeStats(scanProperties);\r
+                                       }\r
+                               }\r
+                               catch(StandardException se)\r
+                               {\r
+                                       // ignore\r
+                               }\r
+                       }\r
+\r
+\r
+                       /* Remember that we created the hash table */\r
+                       hashtableBuilt = true;\r
+\r
+                       /*\r
+                       ** Tell the activation about the number of qualifying rows.\r
+                       ** Do this only here, not in reopen, because we don't want\r
+                       ** to do this costly operation too often.\r
+                       */\r
+                       activation.informOfRowCount(this, (long) hashtableSize);\r
+               }\r
+\r
+           isOpen = true;\r
+\r
+               resetProbeVariables();\r
+\r
+               numOpens++;\r
+               openTime += getElapsedMillis(beginTime);\r
+       }\r
+\r
+       /**\r
+        * reopen this ResultSet.\r
+        *\r
+        * @exception StandardException thrown if cursor finished.\r
+        */\r
+       public void     reopenCore() throws StandardException {\r
+               TransactionController           tc;\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(isOpen,\r
+                                       "HashScanResultSet already open");\r
+               }\r
+\r
+               beginTime = getCurrentTimeMillis();\r
+\r
+               resetProbeVariables();\r
+\r
+               numOpens++;\r
+               openTime += getElapsedMillis(beginTime);\r
+       }\r
+\r
+       private void resetProbeVariables() throws StandardException\r
+       {\r
+               firstNext = true;\r
+               numFetchedOnNext = 0;\r
+               entryVector = null;\r
+               entryVectorSize = 0;\r
+\r
+               if (nextQualifiers != null)\r
+               {\r
+                       clearOrderableCache(nextQualifiers);\r
+               }\r
+       }\r
+\r
+\r
+       /**\r
+     * Return the next row (if any) from the scan (if open).\r
+        *\r
+        * @exception StandardException thrown on failure to get next row\r
+        */\r
+       public ExecRow getNextRowCore() throws StandardException\r
+       {\r
+           ExecRow result = null;\r
+               DataValueDescriptor[] columns = null;\r
+\r
+               beginTime = getCurrentTimeMillis();\r
+           if ( isOpen && hashtableBuilt)\r
+           {\r
+                       /* We use a do/while loop to ensure that we continue down\r
+                        * the duplicate chain, if one exists, until we find a\r
+                        * row that matches on all probe predicates (or the\r
+                        * duplicate chain is exhausted.)\r
+                        */\r
+                       do \r
+                       {\r
+                               if (firstNext)\r
+                               {                         \r
+                                       firstNext = false;\r
+\r
+                                       /* Hash key could be either a single column or multiple columns.\r
+                                        * If a single column, then it is the datavalue wrapper, otherwise\r
+                                        * it is a KeyHasher.\r
+                                        */\r
+                                       Object hashEntry;\r
+                                       if (keyColumns.length == 1)\r
+                                       {\r
+                                               hashEntry = hashtable.get(nextQualifiers[0][0].getOrderable());\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               KeyHasher mh = new KeyHasher(keyColumns.length);\r
+\r
+                        if (SanityManager.DEBUG)\r
+                        {\r
+                            SanityManager.ASSERT(nextQualifiers.length == 1);\r
+                        }\r
+\r
+                                               for (int index = 0; index < keyColumns.length; index++)\r
+                                               {\r
+                            // For hashing only use the AND qualifiers \r
+                            // located in nextQualifiers[0][0...N], OR \r
+                            // qualifiers are checked down a bit by calling\r
+                            // qualifyRow on rows returned from hash.\r
+\r
+                            DataValueDescriptor dvd = \r
+                                nextQualifiers[0][index].getOrderable();\r
+\r
+                            if (dvd == null)\r
+                            {\r
+                                mh = null;\r
+                                break;\r
+                            }\r
+                                                       mh.setObject(\r
+                                index, nextQualifiers[0][index].getOrderable());\r
+                                               }\r
+                                               hashEntry = (mh == null) ? null : hashtable.get(mh);\r
+                                       }\r
+\r
+                                       if (hashEntry instanceof List)\r
+                                       {\r
+                                               entryVector = (List) hashEntry;\r
+                                               entryVectorSize = entryVector.size();\r
+                                               columns = \r
+                            (DataValueDescriptor[]) entryVector.get(0);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               entryVector = null;\r
+                                               entryVectorSize = 0;\r
+                                               columns = (DataValueDescriptor[]) hashEntry;\r
+                                       }\r
+                               }\r
+                               else if (numFetchedOnNext < entryVectorSize)\r
+                               {\r
+                                       // We are walking a list and there are more rows left.\r
+                                       columns = (DataValueDescriptor[]) \r
+                        entryVector.get(numFetchedOnNext);\r
+                               }\r
+\r
+                               if (columns != null)\r
+                               {\r
+\r
+                                       // See if the entry satisfies all of the other qualifiers\r
+\r
+                                       /* We've already "evaluated" the 1st keyColumns qualifiers \r
+                     * when we probed into the hash table, but we need to \r
+                     * evaluate them again here because of the behavior of \r
+                     * NULLs.  NULLs are treated as equal when building and \r
+                     * probing the hash table so that we only get a single \r
+                     * entry.  However, NULL does not equal NULL, so the \r
+                     * compare() method below will eliminate any row that\r
+                                        * has a key column containing a NULL.\r
+                     *\r
+                     * The following code will also evaluate any OR clauses\r
+                     * that may exist, while the above hashing does not \r
+                     * include them.\r
+                                        */\r
+\r
+                                       if (RowUtil.qualifyRow(columns, nextQualifiers))\r
+                                       {\r
+                                               setCompatRow(compactRow, columns);\r
+\r
+                                               rowsSeen++;\r
+\r
+                                               result = compactRow;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               result = null;\r
+                                       }\r
+\r
+                                       numFetchedOnNext++;\r
+                               }\r
+                               else\r
+                               {\r
+                                       result = null;\r
+                               }\r
+                       }\r
+                       while (result == null && numFetchedOnNext < entryVectorSize);\r
+\r
+               }\r
+\r
+               currentRow = result;\r
+               setCurrentRow(result);\r
+\r
+               nextTime += getElapsedMillis(beginTime);\r
+           return result;\r
+       }\r
+\r
+       /**\r
+        * If the result set has been opened,\r
+        * close the open scan.\r
+        *\r
+        * @exception StandardException thrown on error\r
+        */\r
+       public void     close() throws StandardException\r
+       {\r
+               beginTime = getCurrentTimeMillis();\r
+               if ( isOpen )\r
+           {\r
+                       // we don't want to keep around a pointer to the\r
+                       // row ... so it can be thrown away.\r
+                       // REVISIT: does this need to be in a finally\r
+                       // block, to ensure that it is executed?\r
+                   clearCurrentRow();\r
+\r
+                       if (hashtableBuilt)\r
+                       {\r
+                               // This is where we get the scan properties for a subquery\r
+                               scanProperties = getScanProperties();\r
+                               // This is where we get the positioner info for inner tables\r
+                               if (runTimeStatisticsOn)\r
+                               {\r
+                                       startPositionString = printStartPosition();\r
+                                       stopPositionString = printStopPosition();\r
+                               }\r
+\r
+                               // close the hash table, eating any exception\r
+                               hashtable.close();\r
+                               hashtable = null;\r
+                               hashtableBuilt = false;\r
+                       }\r
+                       startPosition = null;\r
+                       stopPosition = null;\r
+\r
+                       super.close();\r
+           }\r
+               else\r
+                       if (SanityManager.DEBUG)\r
+                               SanityManager.DEBUG("CloseRepeatInfo","Close of HashScanResultSet repeated");\r
+\r
+               closeTime += getElapsedMillis(beginTime);\r
+       }\r
+\r
+       /**\r
+        * Return the total amount of time spent in this ResultSet\r
+        *\r
+        * @param type  CURRENT_RESULTSET_ONLY - time spent only in this ResultSet\r
+        *                              ENTIRE_RESULTSET_TREE  - time spent in this ResultSet and below.\r
+        *\r
+        * @return long         The total amount of time spent (in milliseconds).\r
+        */\r
+       public long getTimeSpent(int type)\r
+       {\r
+               long totTime = constructorTime + openTime + nextTime + closeTime;\r
+\r
+               /* RESOLVE - subtract out store time later, when available */\r
+               if (type == NoPutResultSet.CURRENT_RESULTSET_ONLY)\r
+               {\r
+                       return  totTime;\r
+               }\r
+               else\r
+               {\r
+                       return totTime;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * @see NoPutResultSet#requiresRelocking\r
+        */\r
+       public boolean requiresRelocking()\r
+       {\r
+               // IndexRowToBaseRow needs to relock if we didn't keep the lock\r
+               return(\r
+            ((isolationLevel == \r
+                 TransactionController.ISOLATION_READ_COMMITTED)            ||\r
+             (isolationLevel == \r
+                 TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK) ||\r
+             (isolationLevel == \r
+                 TransactionController.ISOLATION_READ_UNCOMMITTED)));\r
+\r
+       }\r
+\r
+       //\r
+       // CursorResultSet interface\r
+       //\r
+\r
+       /**\r
+        * This result set has its row location from\r
+        * the last fetch done. If the cursor is closed,\r
+        * a null is returned.\r
+        *\r
+        * @see CursorResultSet\r
+        *\r
+        * @return the row location of the current cursor row.\r
+        * @exception StandardException thrown on failure to get row location\r
+        */\r
+       public RowLocation getRowLocation() throws StandardException\r
+       {\r
+               if (! isOpen) return null;\r
+\r
+               if ( ! hashtableBuilt)\r
+                       return null;\r
+\r
+               /* This method should only be called if the last column\r
+                * in the current row is a RowLocation.\r
+                */\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(currentRow != null,\r
+                         "There must be a current row when fetching the row location");\r
+                       Object rlCandidate =  currentRow.getColumn(\r
+                                                                                                       currentRow.nColumns());\r
+                       if (! (rlCandidate instanceof RowLocation))\r
+                       {\r
+                               SanityManager.THROWASSERT(\r
+                                       "rlCandidate expected to be instanceof RowLocation, not " +\r
+                                       rlCandidate.getClass().getName());\r
+                       }\r
+               }\r
+\r
+               return (RowLocation) currentRow.getColumn(\r
+                                                                                       currentRow.nColumns());\r
+       }\r
+\r
+       /**\r
+        * This result set has its row from the last fetch done. \r
+        * If the cursor is closed, a null is returned.\r
+        *\r
+        * @see CursorResultSet\r
+        *\r
+        * @return the last row returned;\r
+        * @exception StandardException thrown on failure.\r
+        */\r
+       /* RESOLVE - this should return activation.getCurrentRow(resultSetNumber),\r
+        * once there is such a method.  (currentRow is redundant)\r
+        */\r
+       public ExecRow getCurrentRow() throws StandardException \r
+       {\r
+               /* Doesn't make sense to call this method for this node since\r
+                * joins are not updatable.\r
+                */\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.THROWASSERT( \r
+                        "getCurrentRow() not expected to be called for HSRS");\r
+               }\r
+\r
+               return null;\r
+       }\r
+\r
+       public String printStartPosition()\r
+       {\r
+               return printPosition(startSearchOperator, startKeyGetter, startPosition);\r
+       }\r
+\r
+       public String printStopPosition()\r
+       {\r
+               if (sameStartStopPosition)\r
+               {\r
+                       return printPosition(stopSearchOperator, startKeyGetter, startPosition);\r
+               }\r
+               else\r
+               {\r
+                       return printPosition(stopSearchOperator, stopKeyGetter, stopPosition);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Return a start or stop positioner as a String.\r
+        */\r
+       private String printPosition(int searchOperator,\r
+                                                                GeneratedMethod positionGetter,\r
+                                                                ExecIndexRow eiRow)\r
+       {\r
+               String idt = "";\r
+\r
+               String output = "";\r
+               if (positionGetter == null)\r
+               {\r
+                       return "\t" +\r
+                                       MessageService.getTextMessage(SQLState.LANG_NONE) +\r
+                                       "\n";\r
+               }\r
+\r
+               ExecIndexRow    positioner = null;\r
+\r
+               try\r
+               {\r
+                       positioner = (ExecIndexRow) positionGetter.invoke(activation);\r
+               }\r
+               catch (StandardException e)\r
+               {\r
+\r
+                       if (eiRow == null)\r
+                       {\r
+                               return "\t" + MessageService.getTextMessage(\r
+                                                                                       SQLState.LANG_POSITION_NOT_AVAIL);\r
+                       }\r
+                       return "\t" + MessageService.getTextMessage(\r
+                                                       SQLState.LANG_UNEXPECTED_EXC_GETTING_POSITIONER) +\r
+                                                       "\n";\r
+               }\r
+\r
+               if (positioner == null)\r
+               {\r
+                       return "\t" +\r
+                                       MessageService.getTextMessage(SQLState.LANG_NONE) +\r
+                                       "\n";\r
+               }\r
+\r
+               String searchOp = null;\r
+\r
+               switch (searchOperator)\r
+               {\r
+                       case ScanController.GE:\r
+                               searchOp = ">=";\r
+                               break;\r
+\r
+                       case ScanController.GT:\r
+                               searchOp = ">";\r
+                               break;\r
+\r
+                       default:\r
+                               if (SanityManager.DEBUG)\r
+                               {\r
+                                       SanityManager.THROWASSERT("Unknown search operator " +\r
+                                                                                               searchOperator);\r
+                               }\r
+\r
+                               // This is not internationalized because we should never\r
+                               // reach here.\r
+                               searchOp = "unknown value (" + searchOperator + ")";\r
+                               break;\r
+               }\r
+\r
+               output += "\t" + MessageService.getTextMessage(\r
+                                                                               SQLState.LANG_POSITIONER,\r
+                                                                               searchOp,\r
+                                                                               String.valueOf(positioner.nColumns()))\r
+                                                                               + "\n";\r
+                       \r
+               output += "\t" + MessageService.getTextMessage(\r
+                                                                               SQLState.LANG_ORDERED_NULL_SEMANTICS) +\r
+                                                                               "\n";\r
+               for (int position = 0; position < positioner.nColumns(); position++)\r
+               {\r
+                       if (positioner.areNullsOrdered(position))\r
+                       {\r
+                               output = output + position + " ";\r
+                       }\r
+               }\r
+               \r
+               return output + "\n";\r
+       }\r
+\r
+       public Properties getScanProperties()\r
+       {\r
+               return scanProperties;\r
+       }\r
+\r
+       /**\r
+        * Is this ResultSet or it's source result set for update\r
+        * \r
+        * @return Whether or not the result set is for update.\r
+        */\r
+       public boolean isForUpdate()\r
+       {\r
+               return forUpdate;\r
+       }\r
+}\r