use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class OptimizerImpl method pushPredicates.
/*
** Push predicates from this optimizer's list to the given optimizable,
** as appropriate given the outer tables.
**
** @param curTable The Optimizable to push predicates down to
** @param outerTables A bit map of outer tables
**
** @exception StandardException Thrown on error
*/
void pushPredicates(Optimizable curTable, JBitSet outerTables) throws StandardException {
/*
** Push optimizable clauses to current position in join order.
**
** RESOLVE - We do not push predicates with subqueries not materializable.
*/
int numPreds = predicateList.size();
JBitSet predMap = new JBitSet(numTablesInQuery);
JBitSet curTableNums = null;
BaseTableNumbersVisitor btnVis = null;
int tNum;
Predicate pred;
/* Walk the OptimizablePredicateList. For each OptimizablePredicate,
* see if it can be assigned to the Optimizable at the current join
* position.
*
* NOTE - We walk the OPL backwards since we will hopefully be deleted
* entries as we walk it.
*/
for (int predCtr = numPreds - 1; predCtr >= 0; predCtr--) {
pred = (Predicate) predicateList.getOptPredicate(predCtr);
/* Skip over non-pushable predicates */
if (!isPushable(pred)) {
continue;
}
/* Make copy of referenced map so that we can do destructive
* manipulation on the copy.
*/
predMap.setTo(pred.getReferencedMap());
/* Clear bits representing those tables that have already been
* assigned, except for the current table. The outer table map
* includes the current table, so if the predicate is ready to
* be pushed, predMap will end up with no bits set.
*/
for (int index = 0; index < predMap.size(); index++) {
if (outerTables.get(index)) {
predMap.clear(index);
}
}
/*
** Only consider non-correlated variables when deciding where
** to push predicates down to.
*/
predMap.and(nonCorrelatedTableMap);
/* At this point what we've done is figure out what FromTables
* the predicate references (using the predicate's "referenced
* map") and then: 1) unset the table numbers for any FromTables
* that have already been optimized, 2) unset the table number
* for curTable, which we are about to optimize, and 3) cleared
* out any remaining table numbers which do NOT directly
* correspond to UN-optimized FromTables in this OptimizerImpl's
* optimizableList.
*
* Note: the optimizables in this OptImpl's optimizableList are
* called "non-correlated".
*
* So at this point predMap holds a list of tableNumbers which
* correspond to "non-correlated" FromTables that are referenced
* by the predicate but that have NOT yet been optimized. If any
* such FromTable exists then we canNOT push the predicate yet.
* We can only push the predicate if every FromTable that it
* references either 1) has already been optimized, or 2) is
* about to be optimized (i.e. the FromTable is curTable itself).
* We can check for this condition by seeing if predMap is empty,
* which is what the following line does.
*/
boolean pushPredNow = (predMap.getFirstSetBit() == -1);
/* If the predicate is scoped, there's more work to do. A
* scoped predicate's "referenced map" may not be in sync
* with its actual column references. Or put another way,
* the predicate's referenced map may not actually represent
* the tables that are referenced by the predicate. For
* example, assume the query tree is something like:
*
* SelectNode0
* (PRN0, PRN1)
* | |
* T1 UnionNode
* / |
* PRN2 PRN3
* | |
* SelectNode1 SelectNode2
* (PRN4, PRN5) (PRN6)
* | | |
* T2 T3 T4
*
* Assume further that we have an equijoin predicate between
* T1 and the Union node, and that the column reference that
* points to the Union ultimately maps to T3. The predicate
* will then be scoped to PRN2 and PRN3 and the newly-scoped
* predicates will get passed to the optimizers for SelectNode1
* and SelectNode2--which brings us here. Assume for this
* example that we're here for SelectNode1 and that "curTable"
* is PRN4. Since the predicate has been scoped to SelectNode1,
* its referenced map will hold the table numbers for T1 and
* PRN2--it will NOT hold the table number for PRN5, even
* though PRN5 (T3) is the actual target for the predicate.
* Given that, the above logic will determine that the predicate
* should be pushed to curTable (PRN4)--but that's not correct.
* We said at the start that the predicate ultimately maps to
* T3--so we should NOT be pushing it to T2. And hence the
* need for some additional logic. DERBY-1866.
*/
if (pushPredNow && pred.isScopedForPush() && (numOptimizables > 1)) {
if (btnVis == null) {
curTableNums = new JBitSet(numTablesInQuery);
btnVis = new BaseTableNumbersVisitor(curTableNums);
}
/* What we want to do is find out if the scoped predicate
* is really supposed to be pushed to curTable. We do
* that by getting the base table numbers referenced by
* curTable along with curTable's own table number. Then
* we get the base table numbers referenced by the scoped
* predicate. If the two sets have at least one table
* number in common, then we know that the predicate
* should be pushed to curTable. In the above example
* predMap will end up holding the base table number
* for T3, and thus this check will fail when curTable
* is PRN4 but will pass when it is PRN5, which is what
* we want.
*/
tNum = ((FromTable) curTable).getTableNumber();
curTableNums.clearAll();
btnVis.setTableMap(curTableNums);
((FromTable) curTable).accept(btnVis);
if (tNum >= 0)
curTableNums.set(tNum);
btnVis.setTableMap(predMap);
pred.accept(btnVis);
predMap.and(curTableNums);
if ((predMap.getFirstSetBit() == -1))
pushPredNow = false;
}
/*
** Finally, push the predicate down to the Optimizable at the
** end of the current proposed join order, if it can be evaluated
** there.
*/
if (pushPredNow) {
/* Push the predicate and remove it from the list */
if (curTable.pushOptPredicate(pred)) {
predicateList.removeOptPredicate(predCtr);
}
}
}
}
use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class OptimizerImpl method modifyAccessPaths.
/**
* @see Optimizer#modifyAccessPaths
*
* @exception StandardException Thrown on error
*/
public void modifyAccessPaths() throws StandardException {
if (tracingIsOn()) {
tracer().traceModifyingAccessPaths(hashCode());
}
if (!foundABestPlan) {
if (tracingIsOn()) {
tracer().traceNoBestPlan();
}
throw StandardException.newException(SQLState.LANG_NO_BEST_PLAN_FOUND);
}
/* Change the join order of the list of optimizables */
optimizableList.reOrder(bestJoinOrder);
/* Form a bit map of the tables as they are put into the join order */
JBitSet outerTables = new JBitSet(numOptimizables);
/* Modify the access path of each table, as necessary */
for (int ictr = 0; ictr < numOptimizables; ictr++) {
Optimizable optimizable = optimizableList.getOptimizable(ictr);
/* Current table is treated as an outer table */
outerTables.or(optimizable.getReferencedTableMap());
/*
** Push any appropriate predicates from this optimizer's list
** to the optimizable, as appropriate.
*/
pushPredicates(optimizable, outerTables);
optimizableList.setOptimizable(ictr, optimizable.modifyAccessPath(outerTables));
}
}
use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class RowResultSetNode method preprocess.
/**
* Put a ProjectRestrictNode on top of each FromTable in the FromList.
* ColumnReferences must continue to point to the same ResultColumn, so
* that ResultColumn must percolate up to the new PRN. However,
* that ResultColumn will point to a new expression, a VirtualColumnNode,
* which points to the FromTable and the ResultColumn that is the source for
* the ColumnReference.
* (The new PRN will have the original of the ResultColumnList and
* the ResultColumns from that list. The FromTable will get shallow copies
* of the ResultColumnList and its ResultColumns. ResultColumn.expression
* will remain at the FromTable, with the PRN getting a new
* VirtualColumnNode for each ResultColumn.expression.)
* We then project out the non-referenced columns. If there are no referenced
* columns, then the PRN's ResultColumnList will consist of a single ResultColumn
* whose expression is 1.
*
* @param numTables Number of tables in the DML Statement
* @param gbl The group by list, if any
* @param fromList The from list, if any
*
* @return The generated ProjectRestrictNode atop the original FromTable.
*
* @exception StandardException Thrown on error
*/
@Override
ResultSetNode preprocess(int numTables, GroupByList gbl, FromList fromList) throws StandardException {
getResultColumns().preprocess(numTables, fromList, subquerys, new PredicateList(getContextManager()));
/* Allocate a dummy referenced table map */
setReferencedTableMap(new JBitSet(numTables));
getReferencedTableMap().set(tableNumber);
// but for completeness...
for (int i = 0; i < qec.size(); i++) {
final OrderByList obl = qec.getOrderByList(i);
if (obl != null && obl.size() > 1) {
obl.removeDupColumns();
}
}
return this;
}
use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class OrderByList method requiresDescending.
/**
* Determine whether or not this RequiredRowOrdering has a
* DESCENDING requirement for the column referenced by the
* received ColumnReference.
*/
boolean requiresDescending(ColumnReference cRef, int numOptimizables) throws StandardException {
int size = size();
/* Start by getting the table number and column position for
* the table to which the ColumnReference points.
*/
JBitSet tNum = new JBitSet(numOptimizables);
BaseTableNumbersVisitor btnVis = new BaseTableNumbersVisitor(tNum);
cRef.accept(btnVis);
int crTableNumber = tNum.getFirstSetBit();
int crColPosition = btnVis.getColumnNumber();
if (SanityManager.DEBUG) {
/* We assume that we only ever get here if the column
* reference points to a specific column in a specific
* table...
*/
if ((crTableNumber < 0) || (crColPosition < 0)) {
SanityManager.THROWASSERT("Failed to find table/column number for column '" + cRef.getColumnName() + "' when checking for an " + "ORDER BY requirement.");
}
/* Since we started with a single ColumnReference there
* should be exactly one table number.
*/
if (!tNum.hasSingleBitSet()) {
SanityManager.THROWASSERT("Expected ColumnReference '" + cRef.getColumnName() + "' to reference exactly one table, but tables found " + "were: " + tNum);
}
}
/* Walk through the various ORDER BY elements to see if
* any of them point to the same table and column that
* we found above.
*/
for (int loc = 0; loc < size; loc++) {
OrderByColumn obc = getOrderByColumn(loc);
ResultColumn rcOrderBy = obc.getResultColumn();
btnVis.reset();
rcOrderBy.accept(btnVis);
int obTableNumber = tNum.getFirstSetBit();
int obColPosition = btnVis.getColumnNumber();
/* ORDER BY target should always have a table number and
* a column position. It may not necessarily be a base
* table, but there should be some FromTable for which
* we have a ResultColumnList, and the ORDER BY should
* reference one of the columns in that list (otherwise
* we shouldn't have made it this far).
*/
if (SanityManager.DEBUG) {
/* Since we started with a single ResultColumn there
* should exactly one table number.
*/
if (!tNum.hasSingleBitSet()) {
SanityManager.THROWASSERT("Expected ResultColumn '" + rcOrderBy.getColumnName() + "' to reference " + "exactly one table, but found: " + tNum);
}
if (obColPosition < 0) {
SanityManager.THROWASSERT("Failed to find orderBy column number " + "for ORDER BY check on column '" + cRef.getColumnName() + "'.");
}
}
if (crTableNumber != obTableNumber)
continue;
if (crColPosition == obColPosition) {
/* This ORDER BY element points to the same table
* and column as the received ColumnReference. So
* return whether or not this ORDER BY element is
* descending.
*/
return !obc.isAscending();
}
}
/* None of the ORDER BY elements referenced the same table
* and column as the received ColumnReference, so there
* is no descending requirement for the ColumnReference's
* source (at least not from this OrderByList).
*/
return false;
}
use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class Predicate method pushableToSubqueries.
/**
* Determine whether or not this predicate is eligible for
* push-down into subqueries. Right now the only predicates
* we consider to be eligible are those which 1) are Binary
* Relational operator nodes and 2) have a column reference
* on BOTH sides, each of which has a reference to a base
* table somewhere beneath it.
*
* @return Whether or not this predicate is eligible to be
* pushed into subqueries.
*/
protected boolean pushableToSubqueries() throws StandardException {
if (!isJoinPredicate())
return false;
// Make sure both column references ultimately point to base
// tables. If, for example, either column reference points to a
// a literal or an aggregate, then we do not push the predicate.
// This is because pushing involves remapping the references--
// but if the reference doesn't have a base table beneath it,
// the notion of "remapping" it doesn't (seem to) apply. RESOLVE:
// it might be okay to make the "remap" operation a no-op for
// such column references, but it's not clear whether that's
// always a safe option; further investigation required.
BinaryRelationalOperatorNode opNode = (BinaryRelationalOperatorNode) getAndNode().getLeftOperand();
JBitSet tNums = new JBitSet(getReferencedSet().size());
BaseTableNumbersVisitor btnVis = new BaseTableNumbersVisitor(tNums);
opNode.getLeftOperand().accept(btnVis);
if (tNums.getFirstSetBit() == -1)
return false;
tNums.clearAll();
opNode.getRightOperand().accept(btnVis);
if (tNums.getFirstSetBit() == -1)
return false;
return true;
}
Aggregations