Search in sources :

Example 26 with JBitSet

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);
    }
}
Also used : JBitSet(org.apache.derby.iapi.util.JBitSet) OptimizablePredicate(org.apache.derby.iapi.sql.compile.OptimizablePredicate)

Example 27 with JBitSet

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;
}
Also used : JBitSet(org.apache.derby.iapi.util.JBitSet)

Example 28 with JBitSet

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;
}
Also used : JBitSet(org.apache.derby.iapi.util.JBitSet)

Example 29 with JBitSet

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;
}
Also used : JBitSet(org.apache.derby.iapi.util.JBitSet) HashMap(java.util.HashMap) OptimizablePredicateList(org.apache.derby.iapi.sql.compile.OptimizablePredicateList) OptimizablePredicate(org.apache.derby.iapi.sql.compile.OptimizablePredicate)

Example 30 with JBitSet

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;
}
Also used : JBitSet(org.apache.derby.iapi.util.JBitSet)

Aggregations

JBitSet (org.apache.derby.iapi.util.JBitSet)39 OptimizablePredicate (org.apache.derby.iapi.sql.compile.OptimizablePredicate)12 OptimizablePredicateList (org.apache.derby.iapi.sql.compile.OptimizablePredicateList)7 Optimizable (org.apache.derby.iapi.sql.compile.Optimizable)2 ConglomerateDescriptor (org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 IndexDescriptor (org.apache.derby.catalog.IndexDescriptor)1 ContextManager (org.apache.derby.iapi.services.context.ContextManager)1 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)1 CostEstimate (org.apache.derby.iapi.sql.compile.CostEstimate)1 DataValueDescriptor (org.apache.derby.iapi.types.DataValueDescriptor)1 StandardException (org.apache.derby.shared.common.error.StandardException)1