📄 hashtableresultset.java
字号:
/* Derby - Class org.apache.derby.impl.sql.execute.HashTableResultSet Copyright 1999, 2004 The Apache Software Foundation or its licensors, as applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package org.apache.derby.impl.sql.execute;import org.apache.derby.iapi.services.loader.GeneratedMethod;import org.apache.derby.iapi.services.monitor.Monitor;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.services.io.Storable;import org.apache.derby.iapi.services.stream.HeaderPrintWriter;import org.apache.derby.iapi.services.stream.InfoStreams;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;import org.apache.derby.iapi.sql.conn.StatementContext;import org.apache.derby.iapi.sql.execute.CursorResultSet;import org.apache.derby.iapi.sql.execute.ExecRow;import org.apache.derby.iapi.sql.execute.NoPutResultSet;import org.apache.derby.iapi.types.DataValueDescriptor;import org.apache.derby.iapi.sql.Activation;import org.apache.derby.iapi.sql.ResultSet;import org.apache.derby.iapi.store.access.Qualifier;import org.apache.derby.iapi.store.access.RowSource;import org.apache.derby.iapi.store.access.TransactionController;import org.apache.derby.iapi.types.RowLocation;import org.apache.derby.iapi.store.access.BackingStoreHashtable;import org.apache.derby.iapi.services.io.FormatableArrayHolder;import org.apache.derby.iapi.services.io.FormatableIntHolder;import org.apache.derby.iapi.store.access.KeyHasher;import org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl;import java.util.Properties;import java.util.Vector;/** * Builds a hash table on the underlying result set tree. * * @author jerry */public class HashTableResultSet extends NoPutResultSetImpl implements CursorResultSet { /* Run time statistics variables */ public long restrictionTime; public long projectionTime; public int hashtableSize; public Properties scanProperties; // set in constructor and not altered during // life of object. public NoPutResultSet source; public GeneratedMethod singleTableRestriction; public Qualifier[][] nextQualifiers; private GeneratedMethod projection; private int[] projectMapping; private GeneratedMethod closeCleanup; private boolean runTimeStatsOn; private ExecRow mappedResultRow; public boolean reuseResult; public int[] keyColumns; private boolean removeDuplicates; private long maxInMemoryRowCount; private int initialCapacity; private float loadFactor; private boolean skipNullKeyColumns; // Variable for managing next() logic on hash entry private boolean firstNext = true; private int numFetchedOnNext; private int entryVectorSize; private Vector entryVector; private boolean hashTableBuilt; private boolean firstIntoHashtable = true; private ExecRow nextCandidate; private ExecRow projRow; private BackingStoreHashtable ht; // // class interface // public HashTableResultSet(NoPutResultSet s, Activation a, GeneratedMethod str, Qualifier[][] nextQualifiers, GeneratedMethod p, int resultSetNumber, int mapRefItem, boolean reuseResult, int keyColItem, boolean removeDuplicates, long maxInMemoryRowCount, int initialCapacity, float loadFactor, boolean skipNullKeyColumns, double optimizerEstimatedRowCount, double optimizerEstimatedCost, GeneratedMethod c) throws StandardException { super(a, resultSetNumber, optimizerEstimatedRowCount, optimizerEstimatedCost); source = s; // source expected to be non-null, mystery stress test bug // - sometimes get NullPointerException in openCore(). if (SanityManager.DEBUG) { SanityManager.ASSERT(source != null, "HTRS(), source expected to be non-null"); } singleTableRestriction = str; this.nextQualifiers = nextQualifiers; projection = p; projectMapping = ((ReferencedColumnsDescriptorImpl) a.getPreparedStatement().getSavedObject(mapRefItem)).getReferencedColumnPositions(); FormatableArrayHolder fah = (FormatableArrayHolder) a.getPreparedStatement().getSavedObject(keyColItem); FormatableIntHolder[] fihArray = (FormatableIntHolder[]) fah.getArray(FormatableIntHolder.class); keyColumns = new int[fihArray.length]; for (int index = 0; index < fihArray.length; index++) { keyColumns[index] = fihArray[index].getInt(); } this.reuseResult = reuseResult; this.removeDuplicates = removeDuplicates; this.maxInMemoryRowCount = maxInMemoryRowCount; this.initialCapacity = initialCapacity; this.loadFactor = loadFactor; this.skipNullKeyColumns = skipNullKeyColumns; closeCleanup = c; // Allocate a result row if all of the columns are mapped from the source if (projection == null) { mappedResultRow = activation.getExecutionFactory().getValueRow(projectMapping.length); } constructorTime += getElapsedMillis(beginTime); /* Remember whether or not RunTimeStatistics is on */ runTimeStatsOn = getLanguageConnectionContext().getRunTimeStatisticsMode(); } // // NoPutResultSet interface // /** * open a scan on the table. scan parameters are evaluated * at each open, so there is probably some way of altering * their values... * * @exception StandardException thrown if cursor finished. */ public void openCore() throws StandardException { TransactionController tc; beginTime = getCurrentTimeMillis(); // source expected to be non-null, mystery stress test bug // - sometimes get NullPointerException in openCore(). if (SanityManager.DEBUG) { SanityManager.ASSERT(source != null, "HTRS().openCore(), source expected to be non-null"); } // REVISIT: through the direct DB API, this needs to be an // error, not an ASSERT; users can open twice. Only through JDBC // is access to open controlled and ensured valid. if (SanityManager.DEBUG) SanityManager.ASSERT( ! isOpen, "HashTableResultSet already open"); // Get the current transaction controller tc = activation.getTransactionController(); if (! hashTableBuilt) { source.openCore(); /* Create and populate the hash table. We pass * ourself in as the row source. This allows us * to apply the single table predicates to the * rows coming from our child as we build the * hash table. */ ht = new BackingStoreHashtable(tc, this, keyColumns, removeDuplicates, (int) optimizerEstimatedRowCount, maxInMemoryRowCount, (int) initialCapacity, loadFactor, skipNullKeyColumns, false /* Not kept after a commit */); if (runTimeStatsOn) { hashtableSize = ht.size(); if (scanProperties == null) { scanProperties = new Properties(); } try { if (ht != null) { ht.getAllRuntimeStats(scanProperties); } } catch(StandardException se) { // ignore } } isOpen = true; hashTableBuilt = true; } resetProbeVariables(); numOpens++; openTime += getElapsedMillis(beginTime); } /** * reopen a scan on the table. scan parameters are evaluated * at each open, so there is probably some way of altering * their values... * * @exception StandardException thrown if cursor finished. */ public void reopenCore() throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(isOpen, "HashTableResultSet already open"); } beginTime = getCurrentTimeMillis(); resetProbeVariables(); numOpens++; openTime += getElapsedMillis(beginTime); } private void resetProbeVariables() throws StandardException { firstNext = true; numFetchedOnNext = 0; entryVector = null; entryVectorSize = 0; if (nextQualifiers != null) { clearOrderableCache(nextQualifiers); } } /** * Return the requested values computed * from the next row (if any) for which * the restriction evaluates to true. * <p> * restriction and projection parameters * are evaluated for each row. * * @exception StandardException thrown on failure. * @exception StandardException ResultSetNotOpen thrown if not yet open. * * @return the next row in the result */ public ExecRow getNextRowCore() throws StandardException { ExecRow result = null; DataValueDescriptor[] columns = null; beginTime = getCurrentTimeMillis(); if ( isOpen ) { /* We use a do/while loop to ensure that we continue down * the duplicate chain, if one exists, until we find a * row that matches on all probe predicates (or the * duplicate chain is exhausted.) */ do { if (firstNext) { firstNext = false; /* Hash key could be either a single column or multiple * columns. If a single column, then it is the datavalue * wrapper, otherwise it is a KeyHasher. */ Object hashEntry; if (keyColumns.length == 1) { hashEntry = ht.get(nextQualifiers[0][0].getOrderable()); } else { KeyHasher mh = new KeyHasher(keyColumns.length); for (int index = 0; index < keyColumns.length; index++) { // RESOLVE (mikem) - will need to change when we // support OR's in qualifiers. mh.setObject( index, nextQualifiers[0][index].getOrderable()); } hashEntry = ht.get(mh); } if (hashEntry instanceof Vector) { entryVector = (Vector) hashEntry; entryVectorSize = entryVector.size(); columns = (DataValueDescriptor[]) entryVector.firstElement(); } else { entryVector = null; entryVectorSize = 0; columns = (DataValueDescriptor[]) hashEntry; } } else if (numFetchedOnNext < entryVectorSize) { /* We walking a Vector and there's * more rows left in the vector. */ columns = (DataValueDescriptor[]) entryVector.elementAt(numFetchedOnNext); } if (columns != null) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -