use of org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor in project derby by apache.
the class FromBaseTable method supersetOfUniqueIndex.
/**
* Determine whether or not the columns marked as true in
* the passed in join table matrix are a superset of any single column unique index
* on this table.
* This is useful for distinct elimination
* based on a uniqueness condition.
*
* @param tableColMap The columns to consider
*
* @return Whether or not the columns marked as true for one at least
* one table are a superset
*/
protected boolean supersetOfUniqueIndex(JBitSet[] tableColMap) throws StandardException {
ConglomerateDescriptor[] cds = tableDescriptor.getConglomerateDescriptors();
/* Cycle through the ConglomerateDescriptors */
for (int index = 0; index < cds.length; index++) {
ConglomerateDescriptor cd = cds[index];
if (!cd.isIndex()) {
continue;
}
IndexDescriptor id = cd.getIndexDescriptor();
if (!id.isUnique()) {
continue;
}
int[] keyColumns = id.baseColumnPositions();
int numBits = tableColMap[0].size();
JBitSet keyMap = new JBitSet(numBits);
JBitSet resMap = new JBitSet(numBits);
int inner = 0;
for (; inner < keyColumns.length; inner++) {
keyMap.set(keyColumns[inner]);
}
int table = 0;
for (; table < tableColMap.length; table++) {
resMap.setTo(tableColMap[table]);
resMap.and(keyMap);
if (keyMap.equals(resMap)) {
tableColMap[table].set(0);
return true;
}
}
}
return false;
}
use of org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor in project derby by apache.
the class LockTableNode method bindStatement.
/**
* Bind this LockTableNode. This means looking up the table,
* verifying it exists and getting the heap conglomerate number.
*
* @exception StandardException Thrown on error
*/
@Override
public void bindStatement() throws StandardException {
CompilerContext cc = getCompilerContext();
ConglomerateDescriptor cd;
SchemaDescriptor sd;
String schemaName = tableName.getSchemaName();
sd = getSchemaDescriptor(schemaName);
// Users are not allowed to lock system tables
if (sd.isSystemSchema()) {
throw StandardException.newException(SQLState.LANG_NO_USER_DDL_IN_SYSTEM_SCHEMA, statementToString(), schemaName);
}
lockTableDescriptor = getTableDescriptor(tableName.getTableName(), sd);
if (lockTableDescriptor == null) {
// Check if the reference is for a synonym.
TableName synonymTab = resolveTableToSynonym(tableName);
if (synonymTab == null)
throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, tableName);
tableName = synonymTab;
sd = getSchemaDescriptor(tableName.getSchemaName());
lockTableDescriptor = getTableDescriptor(synonymTab.getTableName(), sd);
if (lockTableDescriptor == null)
throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, tableName);
}
// throw an exception if user is attempting to lock a temporary table
if (lockTableDescriptor.getTableType() == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
throw StandardException.newException(SQLState.LANG_NOT_ALLOWED_FOR_DECLARED_GLOBAL_TEMP_TABLE);
}
conglomerateNumber = lockTableDescriptor.getHeapConglomerateId();
/* Get the base conglomerate descriptor */
cd = lockTableDescriptor.getConglomerateDescriptor(conglomerateNumber);
/* Statement is dependent on the TableDescriptor and ConglomerateDescriptor */
cc.createDependency(lockTableDescriptor);
cc.createDependency(cd);
if (isPrivilegeCollectionRequired()) {
// need SELECT privilege to perform lock table statement.
cc.pushCurrentPrivType(Authorizer.SELECT_PRIV);
cc.addRequiredTablePriv(lockTableDescriptor);
cc.popCurrentPrivType();
}
}
use of org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor in project derby by apache.
the class OptimizerImpl method ruleBasedCostOptimizable.
/**
* This method decides whether the given conglomerate descriptor is
* cheapest based on rules, rather than based on cost estimates.
* The rules are:
*
* Covering matching indexes are preferred above all
* Non-covering matching indexes are next in order of preference
* Covering non-matching indexes are next in order of preference
* Heap scans are next in order of preference
* Non-covering, non-matching indexes are last in order of
* preference.
*
* In the current language architecture, there will always be a
* heap, so a non-covering, non-matching index scan will never be
* chosen. However, the optimizer may see a non-covering, non-matching
* index first, in which case it will choose it temporarily as the
* best conglomerate seen so far.
*
* NOTE: This method sets the cost in the optimizable, even though it
* doesn't use the cost to determine which access path to choose. There
* are two reasons for this: the cost might be needed to determine join
* order, and the cost information is copied to the query plan.
*/
private void ruleBasedCostOptimizable(Optimizable optimizable, TableDescriptor td, ConglomerateDescriptor cd, OptimizablePredicateList predList, CostEstimate outerCost) throws StandardException {
/* CHOOSE BEST CONGLOMERATE HERE */
AccessPath bestAp = optimizable.getBestAccessPath();
/*
** If there is more than one conglomerate descriptor
** choose any index that is potentially useful.
*/
if (predList != null && predList.useful(optimizable, cd)) {
/*
** Do not let a non-covering matching index scan supplant a
** covering matching index scan.
*/
boolean newCoveringIndex = optimizable.isCoveringIndex(cd);
if ((!bestAp.getCoveringIndexScan()) || bestAp.getNonMatchingIndexScan() || newCoveringIndex) {
bestAp.setCostEstimate(estimateTotalCost(predList, cd, outerCost, optimizable));
bestAp.setConglomerateDescriptor(cd);
bestAp.setNonMatchingIndexScan(false);
bestAp.setCoveringIndexScan(newCoveringIndex);
bestAp.setLockMode(optimizable.getCurrentAccessPath().getLockMode());
optimizable.rememberJoinStrategyAsBest(bestAp);
}
return;
}
/* Remember the "last" covering index.
* NOTE - Since we don't have costing, we just go for the
* last one since that's as good as any
*/
if (optimizable.isCoveringIndex(cd)) {
bestAp.setCostEstimate(estimateTotalCost(predList, cd, outerCost, optimizable));
bestAp.setConglomerateDescriptor(cd);
bestAp.setNonMatchingIndexScan(true);
bestAp.setCoveringIndexScan(true);
bestAp.setLockMode(optimizable.getCurrentAccessPath().getLockMode());
optimizable.rememberJoinStrategyAsBest(bestAp);
return;
}
/*
** If this is the heap, and the best conglomerate so far is a
** non-covering, non-matching index scan, pick the heap.
*/
if ((!bestAp.getCoveringIndexScan()) && bestAp.getNonMatchingIndexScan() && (!cd.isIndex())) {
bestAp.setCostEstimate(estimateTotalCost(predList, cd, outerCost, optimizable));
bestAp.setConglomerateDescriptor(cd);
bestAp.setLockMode(optimizable.getCurrentAccessPath().getLockMode());
optimizable.rememberJoinStrategyAsBest(bestAp);
/*
** No need to set non-matching index scan and covering
** index scan, as these are already correct.
*/
return;
}
/*
** If all else fails, and no conglomerate has been picked yet,
** pick this one.
*/
ConglomerateDescriptor bestConglomerateDescriptor = bestAp.getConglomerateDescriptor();
if (bestConglomerateDescriptor == null) {
bestAp.setCostEstimate(estimateTotalCost(predList, cd, outerCost, optimizable));
bestAp.setConglomerateDescriptor(cd);
/*
** We have determined above that this index is neither covering
** nor matching.
*/
bestAp.setCoveringIndexScan(false);
bestAp.setNonMatchingIndexScan(cd.isIndex());
bestAp.setLockMode(optimizable.getCurrentAccessPath().getLockMode());
optimizable.rememberJoinStrategyAsBest(bestAp);
}
}
use of org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor in project derby by apache.
the class HashJoinStrategy method feasible.
/**
* @see JoinStrategy#feasible
*
* @exception StandardException Thrown on error
*/
public boolean feasible(Optimizable innerTable, OptimizablePredicateList predList, Optimizer optimizer) throws StandardException {
ConglomerateDescriptor cd = null;
/* If the innerTable is a VTI, then we
* must check to see if there are any
* join columns in the VTI's parameters.
* If so, then hash join is not feasible.
*/
if (!innerTable.isMaterializable()) {
if (innerTable.optimizerTracingIsOn()) {
innerTable.getOptimizerTracer().traceSkipUnmaterializableHashJoin();
}
return false;
}
/* Don't consider hash join on the target table of an update/delete.
* RESOLVE - this is a temporary restriction. Problem is that we
* do not put RIDs into the row in the hash table when scanning
* the heap and we need them for a target table.
*/
if (innerTable.isTargetTable()) {
return false;
}
/* If the predicate given by the user _directly_ references
* any of the base tables _beneath_ this node, then we
* cannot safely use the predicate for a hash because the
* predicate correlates two nodes at different nesting levels.
* If we did a hash join in this case, materialization of
* innerTable could lead to incorrect results--and in particular,
* results that are missing rows. We can check for this by
* looking at the predicates' reference maps, which are set based
* on the initial query (as part of pre-processing). Note that
* by the time we get here, it's possible that a predicate's
* reference map holds table numbers that do not agree with the
* table numbers of the column references used by the predicate.
* That's okay--this occurs as a result of "remapping" predicates
* that have been pushed down the query tree. And in fact
* it's a good thing because, by looking at the column reference's
* own table numbers instead of the predicate's referenced map,
* we are more readily able to find equijoin predicates that
* we otherwise would not have found.
*
* Note: do not perform this check if innerTable is a FromBaseTable
* because a base table does not have a "subtree" to speak of.
*/
if ((predList != null) && (predList.size() > 0) && !(innerTable instanceof FromBaseTable)) {
FromTable ft = (FromTable) innerTable;
// First get a list of all of the base tables in the subtree
// below innerTable.
JBitSet tNums = new JBitSet(ft.getReferencedTableMap().size());
BaseTableNumbersVisitor btnVis = new BaseTableNumbersVisitor(tNums);
ft.accept(btnVis);
// Now get a list of all table numbers referenced by the
// join predicates that we'll be searching.
JBitSet pNums = new JBitSet(tNums.size());
for (int i = 0; i < predList.size(); i++) {
Predicate pred = (Predicate) predList.getOptPredicate(i);
if (pred.isJoinPredicate())
pNums.or(pred.getReferencedSet());
}
// If tNums and pNums have anything in common, then at
// least one predicate in the list refers directly to
// a base table beneath this node (as opposed to referring
// just to this node), which means it's not safe to do a
// hash join.
tNums.and(pNums);
if (tNums.getFirstSetBit() != -1)
return false;
}
if (innerTable.isBaseTable()) {
/* Must have an equijoin on a column in the conglomerate */
cd = innerTable.getCurrentAccessPath().getConglomerateDescriptor();
}
/* Look for equijoins in the predicate list */
int[] hashKeyColumns = findHashKeyColumns(innerTable, cd, predList);
if (SanityManager.DEBUG) {
if (innerTable.optimizerTracingIsOn()) {
if (hashKeyColumns == null) {
innerTable.getOptimizerTracer().traceSkipHashJoinNoHashKeys();
} else {
innerTable.getOptimizerTracer().traceHashKeyColumns(ArrayUtil.copy(hashKeyColumns));
}
}
}
if (hashKeyColumns == null) {
return false;
}
return true;
}
use of org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor in project derby by apache.
the class InsertNode method getAffectedIndexes.
/**
* Get the list of indexes on the table being inserted into. This
* is used by INSERT. This is an optimized version of what
* UPDATE and DELETE use.
*
* @param td TableDescriptor for the table being inserted into
* or deleted from
*
* @exception StandardException Thrown on error
*/
private void getAffectedIndexes(TableDescriptor td) throws StandardException {
IndexLister indexLister = td.getIndexLister();
indicesToMaintain = indexLister.getDistinctIndexRowGenerators();
indexConglomerateNumbers = indexLister.getDistinctIndexConglomerateNumbers();
indexNames = indexLister.getDistinctIndexNames();
/* Add dependencies on all indexes in the list */
ConglomerateDescriptor[] cds = td.getConglomerateDescriptors();
CompilerContext cc = getCompilerContext();
for (int index = 0; index < cds.length; index++) {
cc.createDependency(cds[index]);
}
}
Aggregations