use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class PredicateList method pullExpressions.
/**
* Break apart the search clause into matching a PredicateList
* where each top level predicate is a separate element in the list.
* Build a bit map to represent the FromTables referenced within each
* top level predicate.
* NOTE: We want the rightOperand of every AndNode to be true, in order
* to simplify the algorithm for putting the predicates back into the tree.
* (As we put an AndNode back into the tree, we can ignore it's rightOperand.)
*
* @param numTables Number of tables in the DML Statement
* @param searchClause The search clause to operate on.
*
* @exception StandardException Thrown on error
*/
void pullExpressions(int numTables, ValueNode searchClause) throws StandardException {
AndNode thisAnd;
AndNode topAnd;
JBitSet newJBitSet;
Predicate newPred;
if (searchClause != null) {
topAnd = (AndNode) searchClause;
BooleanConstantNode trueNode = new BooleanConstantNode(true, getContextManager());
while (topAnd.getRightOperand() instanceof AndNode) {
/* Break out the next top AndNode */
thisAnd = topAnd;
topAnd = (AndNode) topAnd.getRightOperand();
thisAnd.setRightOperand(null);
/* Set the rightOperand to true */
thisAnd.setRightOperand(trueNode);
/* Add the top AndNode to the PredicateList */
newJBitSet = new JBitSet(numTables);
newPred = new Predicate(thisAnd, newJBitSet, getContextManager());
addPredicate(newPred);
}
/* Add the last top AndNode to the PredicateList */
newJBitSet = new JBitSet(numTables);
newPred = new Predicate(topAnd, newJBitSet, getContextManager());
addPredicate(newPred);
}
}
use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class SubqueryNode method rightOperandFlattenableToNotExists.
/**
* <p>
* Check if the right operand is on a form that makes it possible to
* flatten this query to a NOT EXISTS join. We don't allow flattening if
* the right operand doesn't reference the base table of the subquery.
* (Requirement added as part of DERBY-4001.)
* </p>
*
* <p>
* The problem with the right operand not referencing the base table of the
* subquery, is that the join condition may then be used to filter rows
* from the right side (outer) table in the NOT EXISTS join. In a NOT
* EXISTS join, the join condition can only safely be applied to the
* left side (inner) table of the join. Otherwise, it will filter out all
* the interesting rows too early.
* </p>
*
* <p>Take the query below as an example:</p>
*
* <pre><code>
* SELECT * FROM T1 WHERE X NOT IN (SELECT 1 FROM T2)
* </code></pre>
*
* <p>
* Here, the right operand is 1, and the join condition is {@code T1.X=1}.
* If flattened, the join condition will be used directly on the outer
* table, and hide all rows with {@code X<>1}, although those are the only
* rows we're interested in. If the join condition had only been used on
* the inner table, the NOT EXISTS join logic would do the correct thing.
* </p>
*
* <p>
* If the join condition references the inner table, the condition cannot
* be used directly on the outer table, so it is safe to flatten the query.
* </p>
*
* @param numTables the number of tables in this statement
* @param fbt the only {@code FromBaseTable} in this subquery
* @return {@code true} if it is OK to flatten this query to a NOT EXISTS
* join, {@code false} otherwise
*/
private boolean rightOperandFlattenableToNotExists(int numTables, FromBaseTable fbt) throws StandardException {
boolean flattenable = true;
// no right operand, it cannot cause any problems for the flattening.
if (leftOperand != null) {
JBitSet tableSet = new JBitSet(numTables);
getRightOperand().categorize(tableSet, false);
// The query can be flattened to NOT EXISTS join only if the right
// operand references the base table.
flattenable = tableSet.get(fbt.getTableNumber());
}
return flattenable;
}
use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class UnaryComparisonOperatorNode method selfComparison.
/**
* @see RelationalOperator#selfComparison
*/
public boolean selfComparison(ColumnReference cr) {
ValueNode otherSide;
JBitSet tablesReferenced;
if (SanityManager.DEBUG) {
SanityManager.ASSERT(cr == operand, "ColumnReference not found in IsNullNode.");
}
/* An IsNullNode is not a comparison with any other column */
return false;
}
use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class SetOperatorNode method pushOptPredicate.
/**
* @see org.apache.derby.iapi.sql.compile.Optimizable#pushOptPredicate
*
* Take a predicate and push it down to both the left AND right result
* sets. Return "true" if we successfully pushed it to both sides,
* and "false" otherwise. The assumption is that if we return "true",
* the caller will take the predicate and remove it from its own list
* of predicates to evaluate; if we return false, then the predicate
* will be evaluated at the level of the caller. So returning "false"
* means that the left and right result sets for this node will be fully
* returned, and then the predicate will be evaluated against the
* <set-operator> of those result sets (as of DERBY-805, the only set
* operator calling this method is UnionNode). If we can push the
* predicate down to both children, though, we can evaluate it closer
* to store, which means that each child result set returns only the
* correctly qualified rows, and thus the calling set operator will
* have a smaller result set on which to operate, which can boost
* performance.
*
* That said, if we can't push the predicate to _both_ sides, we don't
* push it at all. The reason is that if we push to one side but not
* to the other, we would have to ask the question of whether we should
* return "true" (meaning that the predicate would be removed from the
* caller's list and thus would _not_ be evaluated at the <set-operator>
* level) or "false" (meaning that the caller would keep the predicate
* and evaluate it at the <set-operator> level). Depending on the query
* in question, both answers could end up returning incorrect results.
*
* For example, if we push it to the right but not to the left, then
* leave it in the caller's list, the optimizer for the caller might
* decide to use the predicate to do a hash join with some outer result
* set (if the predicate is an equijoin predicate). That would result
* in materialization of the calling node and of its children--but since
* we pushed a predicate that depends on the outer table down into the
* right child, materialization of the right child will only return the
* rows that join with the _first_ row of the outer result set, which
* is wrong.
*
* If, on the other hand, we push the predicate to one side and then tell
* the caller to remove it from its list, the side to which we did _not_
* push the predicate could return rows that aren't qualified. Then,
* since the caller removed the predicate from its list, it (the caller)
* will not evaluate the predicate on its own result set--and thus we
* can end up returning rows that we weren't supposed to return.
*
* So all of that said, only push (and return "true") if we think we
* can push the predicate to both sides.
*
* @exception StandardException Thrown on error
*/
@Override
public boolean pushOptPredicate(OptimizablePredicate optimizablePredicate) throws StandardException {
// when support for other SetOperators is added.
if (!(this instanceof UnionNode))
return false;
// We only handle certain types of predicates here; if the received
// predicate doesn't qualify, then don't push it.
Predicate pred = (Predicate) optimizablePredicate;
if (!pred.pushableToSubqueries())
return false;
// Check to see if the child nodes reference any base tables; if either
// child does not reference at least one base table, then we don't try
// to push the predicate.
JBitSet tableNums = new JBitSet(getReferencedTableMap().size());
BaseTableNumbersVisitor btnVis = new BaseTableNumbersVisitor(tableNums);
// Check the left child.
leftResultSet.accept(btnVis);
boolean canPush = (tableNums.getFirstSetBit() != -1);
/* If we can't push it to _both_ children, then we don't push at all.
* RESOLVE: We can add the ability to push a predicate to one side
* only by putting a ProjectRestrictNode between the union node and
* the child as a place to park the predicate. To make things simple,
* we might want to always put ProjectRestrictNodes under both sides
* of the union during preprocessing (i.e. after binding but before
* optimization). In some cases the extra nodes won't be needed, but
* PRNs (and the corresponding ProjectRestrictResultSets) are cheap.
* Also, we could eliminate unnecessary ProjectRestrictNodes at the
* end of optimization (possibly in modifyAccessPaths()). Until all
* of that is implemented, though, we only push if we can push to
* both sides...
*/
if (!canPush)
return false;
// Check the right child.
tableNums.clearAll();
rightResultSet.accept(btnVis);
canPush = (tableNums.getFirstSetBit() != -1);
if (!canPush)
return false;
// Get a list of all of the underlying base tables that this node
// references. We pass this down when scoping so that we can tell
// if the operands are actually supposed to be scoped to _this_
// node's children. Note that in order for the predicate to
// have been pushed this far, at least one of its operands must
// apply to this node--we don't know which one it is, though,
// so we use this tableNums info to figure that out.
tableNums.clearAll();
this.accept(btnVis);
/* What we want to do here is push the predicate to the left/right
* child. That means that we need to find the equivalent column(s)
* in each child.
* Ex:
*
* select * from
* (select i,j from t1 union select i,j from t2) X1,
* (select a,b from t3 union select a,b from t4) X2
* where X1.j = X2.b;
*
* In this example, X1.j maps to "t1" for the left side of the
* union (X1) and "t2" for the right side of the union. So we have
* to get versions of the predicate that are appropriate to each
* side. That's what the call to getPredScopedForResultSet()
* in the following code does.
*/
// For details on how this whichRC variable is used, see the
// comments in BinaryRelationalOperatorNode.getScopedOperand().
int[] whichRC = new int[] { -1 };
// See if we already have a scoped version of the predicate cached,
// and if so just use that.
Predicate scopedPred = null;
if (leftScopedPreds == null)
leftScopedPreds = new HashMap<Predicate, Predicate>();
else
scopedPred = leftScopedPreds.get(pred);
if (scopedPred == null) {
scopedPred = pred.getPredScopedForResultSet(tableNums, leftResultSet, whichRC);
leftScopedPreds.put(pred, scopedPred);
}
// Add the scoped predicate to our list for the left child.
getLeftOptPredicateList().addOptPredicate(scopedPred);
scopedPred = null;
if (rightScopedPreds == null)
rightScopedPreds = new HashMap<Predicate, Predicate>();
else
scopedPred = rightScopedPreds.get(pred);
if (scopedPred == null) {
scopedPred = pred.getPredScopedForResultSet(tableNums, rightResultSet, whichRC);
rightScopedPreds.put(pred, scopedPred);
}
// Add the scoped predicate to our list for the right child.
getRightOptPredicateList().addOptPredicate(scopedPred);
// modifyAccessPaths() in this class for more.
if (pushedPredicates == null)
pushedPredicates = new PredicateList(getContextManager());
pushedPredicates.addOptPredicate(pred);
return true;
}
use of org.apache.derby.iapi.util.JBitSet in project derby by apache.
the class ResultSetNode method LOJgetReferencedTables.
// It may be we have a SELECT view underneath a LOJ.
// Return null for now.. we don't do any optimization.
JBitSet LOJgetReferencedTables(int numTables) throws StandardException {
if (this instanceof FromTable) {
if (((FromTable) this).tableNumber != -1) {
JBitSet map = new JBitSet(numTables);
map.set(((FromTable) this).tableNumber);
return map;
}
}
return null;
}
Aggregations