Search in sources :

Example 6 with JBitSet

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

Example 7 with JBitSet

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

Example 8 with JBitSet

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

Example 9 with JBitSet

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

Example 10 with JBitSet

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;
}
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