Search in sources :

Example 21 with JBitSet

use of org.apache.derby.iapi.util.JBitSet in project derby by apache.

the class BinaryRelationalOperatorNode method getScopedOperand.

/**
 * Take a ResultSetNode and return a column reference that is scoped for
 * for the received ResultSetNode, where "scoped" means that the column
 * reference points to a specific column in the RSN.  This is used for
 * remapping predicates from an outer query down to a subquery.
 *
 * For example, assume we have the following query:
 *
 *  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;
 *
 * Then assume that this BinaryRelationalOperatorNode represents the
 * "X1.j = X2.b" predicate and that the childRSN we received as a
 * parameter represents one of the subqueries to which we want to push
 * the predicate; let's say it's:
 *
 *    select i,j from t1
 *
 * Then what we want to do in this method is map one of the operands
 * X1.j or X2.b (depending on the 'whichSide' parameter) to the childRSN,
 * if possible.  Note that in our example, "X2.b" should _NOT_ be mapped
 * because it doesn't apply to the childRSN for the subquery "select i,j
 * from t1"; thus we should leave it as it is.  "X1.j", however, _does_
 * need to be scoped, and so this method will return a ColumnReference
 * pointing to "T1.j" (or whatever the corresponding column in T1 is).
 *
 * ASSUMPTION: We should only get to this method if we know that
 * exactly one operand in the predicate to which this operator belongs
 * can and should be mapped to the received childRSN.
 *
 * @param whichSide The operand are we trying to scope (LEFT or RIGHT)
 * @param parentRSNsTables Set of all table numbers referenced by
 *  the ResultSetNode that is _parent_ to the received childRSN.
 *  We need this to make sure we don't scope the operand to a
 *  ResultSetNode to which it doesn't apply.
 * @param childRSN The result set node to which we want to create
 *  a scoped predicate.
 * @param whichRC If not -1 then this tells us which ResultColumn
 *  in the received childRSN we need to use for the scoped predicate;
 *  if -1 then the column position of the scoped column reference
 *  will be stored in this array and passed back to the caller.
 * @return A column reference scoped to the received childRSN, if possible.
 *  If the operand is a ColumnReference that is not supposed to be scoped,
 *  we return a _clone_ of the reference--this is necessary because the
 *  reference is going to be pushed to two places (left and right children
 *  of the parentRSN) and if both children are referencing the same
 *  instance of the column reference, they'll interfere with each other
 *  during optimization.
 */
ValueNode getScopedOperand(int whichSide, JBitSet parentRSNsTables, ResultSetNode childRSN, int[] whichRC) throws StandardException {
    ResultColumn rc;
    ColumnReference cr = whichSide == LEFT ? (ColumnReference) leftOperand : (ColumnReference) rightOperand;
    /* When we scope a predicate we only scope one side of it--the
		 * side that is to be evaluated against childRSN.  We figure out
		 * if "cr" is that side by using table numbers, as seen below.
		 * This means that for every scoped predicate there will be one
		 * operand that is scoped and one operand that is not scoped.  
		 * When we get here for the operand that will not be scoped,
		 * we'll just return a clone of that operand.  So in the example
		 * mentioned above, the scoped predicate for the left child of
		 * X1 would be
		 *
		 *   T1.j <scoped> = X2.b <clone> 
		 *
		 * That said, the first thing we need to do is see if this
		 * ColumnReference is supposed to be scoped for childRSN.  We
		 * do that by figuring out what underlying base table the column
		 * reference is pointing to and then seeing if that base table
		 * is included in the list of table numbers from the parentRSN.
		 */
    JBitSet crTables = new JBitSet(parentRSNsTables.size());
    BaseTableNumbersVisitor btnVisitor = new BaseTableNumbersVisitor(crTables);
    cr.accept(btnVisitor);
    /* If the column reference in question is not intended for
		 * the received result set node, just leave the operand as
		 * it is (i.e. return a clone).  In the example mentioned at
		 * the start of this method, this will happen when the operand
		 * is X2.b and childRSN is either "select i,j from t1" or
		 * "select i,j from t2", in which case the operand does not
		 * apply to childRSN.  When we get here and try to map the
		 * "X1.j" operand, though, the following "contains" check will
		 * return true and thus we can go ahead and return a scoped
		 * version of that operand.
		 */
    if (!parentRSNsTables.contains(crTables))
        return (ColumnReference) cr.getClone();
    /* Find the target ResultColumn in the received result set.  At
		 * this point we know that we do in fact need to scope the column
		 * reference for childRSN, so go ahead and do it.  The way in
		 * which we get the scope target column differs depending on
		 * if childRSN corresponds to the left or right child of the
		 * UNION node.  Before explaining that, though, note that it's
		 * not good enough to just search for the target column by
		 * name.  The reason is that it's possible the name provided
		 * for the column reference to be scoped doesn't match the
		 * name of the actual underlying column.  Ex.
		 *
		 *  select * from
		 *    (select i,j from t1 union select i,j from t2) X1 (x,y),
		 *    (select a,b from t3 union select a,b from t4) X2
		 *  where X1.x = X2.b;
		 *
		 * If we were scoping "X1.x" and we searched for "x" in the
		 * childRSN "select i,j from t1" we wouldn't find it.
		 *
		 * It is similarly incorrect to search for the target column
		 * by position (DERBY-1633).  This is a bit more subtle, but
		 * if the child to which we're scoping is a subquery whose RCL
		 * does not match the column ordering of the RCL for cr's source
		 * result set, then searching by column position can yield the
		 * wrong results, as well.  For a detailed example of how this
		 * can happen, see the fix description attached to DERBY-1633.
		 * 
		 * So how do we find the target column, then? As mentioned
		 * above, the way in which we get the scope target column
		 * differs depending on if childRSN corresponds to the left
		 * or right child of the parent UNION node.  And that said,
		 * we can tell if we're scoping a left child by looking at
		 * "whichRC" argument: if it is -1 then we know we're scoping
		 * to the left child of a Union; otherwise we're scoping to
		 * the right child.
		 */
    if (whichRC[0] == -1) {
        /*
			 * For the left side we start by figuring out what the source
			 * result set and column position for "cr" are.  Then, since
			 * a) cr must be pointing to a result column in the parentRSN's
			 * ResultColumnList,  b) we know that the parent RSN is a
			 * SetOperatorNode (at least for now, since we only get here
			 * for Union nodes), and c) SetOpNode's RCLs are built from the
			 * left child's RCL (see bindResultColumns() in SetOperatorNode),
			 * we know that if we search the child's RCL for a reference
			 * whose source result column is the same as cr's source result
			 * column, we'll find a match.  Once found, the position of the
			 * matching column w.r.t childRSN's RCL will be stored in the
			 * whichRC parameter.
			 */
        // Find the source result set and source column position of cr.
        int[] sourceColPos = new int[] { -1 };
        ResultSetNode sourceRSN = cr.getSourceResultSet(sourceColPos);
        if (SanityManager.DEBUG) {
            /* We assumed that if we made it here "cr" was pointing
				 * to a base table somewhere down the tree.  If that's
				 * true then sourceRSN won't be null.  Make sure our
				 * assumption was correct.
				 */
            SanityManager.ASSERT(sourceRSN != null, "Failed to find source result set when trying to " + "scope column reference '" + cr.getTableName() + "." + cr.getColumnName());
        }
        // Now search for the corresponding ResultColumn in childRSN.
        rc = childRSN.getResultColumns().getResultColumn(sourceColPos[0], sourceRSN, whichRC);
    } else {
        /*
			 * For the right side the story is slightly different.  If we were
			 * to search the right child's RCL for a reference whose source
			 * result column was the same as cr's, we wouldn't find it.  This
			 * is because cr's source result column comes from the left child's
			 * RCL and thus the right child doesn't know about it.  That said,
			 * though, for set operations like UNION, the left and right RCL's
			 * are correlated by position--i.e. the operation occurs between
			 * the nth column in the left RCL and the nth column in the right
			 * RCL.  So given that we will already have found the scope target
			 * in the left child's RCL at the position in whichRC, we know that
			 * that scope target for the right child's RCL is simply the
			 * whichRC'th column in that RCL.
			 */
        rc = childRSN.getResultColumns().getResultColumn(whichRC[0]);
    }
    // then we shouldn't have made it this far.
    if (SanityManager.DEBUG) {
        SanityManager.ASSERT(rc != null, "Failed to locate scope target result column when trying to " + "scope operand '" + cr.getTableName() + "." + cr.getColumnName() + "'.");
    }
    if (rc.getExpression() instanceof ColumnReference) {
        /* We create a clone of the column reference and mark
			 * the clone as "scoped" so that we can do the right
			 * thing when it comes time to remap the predicate;
			 * see Predicate.remapScopedPred() for more.
			 */
        ColumnReference cRef = (ColumnReference) ((ColumnReference) rc.getExpression()).getClone();
        cRef.markAsScoped();
        return cRef;
    }
    /* Else just return rc's expression.  This means the scoped
		 * predicate will have one operand that is _not_ a column
		 * reference--but that's okay, so long as we account for
		 * that when pushing/remapping the scoped predicate down
		 * the query tree (see esp. "isScopedToSourceResultSet()"
		 * in Predicate.java).
		 */
    return rc.getExpression();
}
Also used : JBitSet(org.apache.derby.iapi.util.JBitSet)

Example 22 with JBitSet

use of org.apache.derby.iapi.util.JBitSet in project derby by apache.

the class BinaryRelationalOperatorNode method isQualifier.

/**
 * @see RelationalOperator#isQualifier
 *
 * @exception StandardException		Thrown on error
 */
public boolean isQualifier(Optimizable optTable, boolean forPush) throws StandardException {
    /* If this rel op is for an IN-list probe predicate then we never
		 * treat it as a qualifer.  The reason is that if we treat it as
		 * a qualifier then we could end up generating it as a qualifier,
		 * which would lead to the generation of an equality qualifier
		 * of the form "col = <val>" (where <val> is the first value in
		 * the IN-list).  That would lead to wrong results (missing rows)
		 * because that restriction is incorrect.
		 */
    if (isInListProbeNode())
        return false;
    FromTable ft;
    ValueNode otherSide = null;
    JBitSet tablesReferenced;
    ColumnReference cr;
    boolean found = false;
    boolean walkSubtree = true;
    ft = (FromTable) optTable;
    if (leftOperand instanceof ColumnReference) {
        /*
			** The left operand is a column reference.
			** Is it the correct column?
			*/
        cr = (ColumnReference) leftOperand;
        if (valNodeReferencesOptTable(cr, ft, forPush, walkSubtree)) {
            otherSide = rightOperand;
            found = true;
        }
        walkSubtree = false;
    }
    if ((!found) && (rightOperand instanceof ColumnReference)) {
        /*
			** The right operand is a column reference.
			** Is it the correct column?
			*/
        cr = (ColumnReference) rightOperand;
        if (valNodeReferencesOptTable(cr, ft, forPush, walkSubtree)) {
            otherSide = leftOperand;
            found = true;
        }
    }
    /* Have we found a ColumnReference on either side? */
    if (!found) {
        /*
			** Neither side is a ColumnReference to the table we're looking
			** for, so it can't be a Qualifier
			*/
        return false;
    }
    /*
		** One side is a ColumnReference to the correct table.  It is a
		** Qualifier if the other side does not refer to the table we are
		** optimizing.
		*/
    return !valNodeReferencesOptTable(otherSide, ft, forPush, true);
}
Also used : JBitSet(org.apache.derby.iapi.util.JBitSet)

Example 23 with JBitSet

use of org.apache.derby.iapi.util.JBitSet in project derby by apache.

the class SubqueryNode method pushNewPredicate.

/**
 * Transform:
 *      expression QuantifiedOperator (select x from ...)
 * into
 *		(select true from .. where expression <BinaryComparisonOperator> x ...)
 *		IS [NOT] NULL
 *
 * or, if we have an aggregate:
 *		(select true from
 *			(select AGG(x) from ...)
 *		where expression <BinaryComparisonOperator> x ...)
 *		IS [NOT] NULL
 *
 * For ANY and IN subqueries:
 *		o  We generate an IS NULL above the SubqueryNode and return the top of
 *		   the new tree to the caller.
 *		o  The operator in the new predicate that is added to the subquery
 *		   will correspond to the operator that modifies the ANY.
 *		   (eg, = for = ANY, with = for IN.)
 * For ALL and NOT IN subqueries:
 *		o  We generate an IS NOT NULL above the SubqueryNode and return the top of
 *		   the new tree to the caller.
 *		o  The operator in the new predicate that is added to the subquery
 *		   will be a BinaryAllOperatorNode whose bcoNodeType corresponds to
 *		   the negation of the operator that modifies the ALL.
 *		   (eg, &lt;&gt; for = ALL, with &lt;&gt; for NOT IN.)
 *
 * NOTE: This method is called after the underlying subquery has been
 * preprocessed, so we build a new Predicate, not just a new expression.
 *
 * @param numTables			Number of tables in DML Statement
 *
 * @return UnaryComparisonOperatorNode	An IS [NOT] NULL above the
 *										transformed subquery.
 *
 * @exception StandardException		Thrown on error
 */
private UnaryComparisonOperatorNode pushNewPredicate(int numTables) throws StandardException {
    AndNode andNode;
    JBitSet tableMap;
    Predicate predicate;
    ResultColumn firstRC;
    ResultColumnList resultColumns;
    UnaryComparisonOperatorNode ucoNode = null;
    ValueNode rightOperand;
    ContextManager cm = getContextManager();
    /* We have to ensure that the resultSet immediately under us has
		 * a PredicateList, otherwise we can't push the predicate down.
		 */
    resultSet = resultSet.ensurePredicateList(numTables);
    /* RESOLVE - once we understand how correlated columns will work, 
		 * we probably want to mark leftOperand as a correlated column
		 */
    resultColumns = resultSet.getResultColumns();
    /*
		** Create a new PR node.  Put it over the original subquery.  resulSet
		** is now the new PR.  We give the chance that things under the PR node
		** can be materialized.  See beetle 4373.
		*/
    ResultColumnList newRCL = resultColumns.copyListAndObjects();
    newRCL.genVirtualColumnNodes(resultSet, resultColumns);
    resultSet = new ProjectRestrictNode(// child
    resultSet, // result columns
    newRCL, // restriction
    null, // restriction list
    null, // project subqueries
    null, // restrict subqueries
    null, null, cm);
    resultColumns = newRCL;
    firstRC = resultColumns.elementAt(0);
    rightOperand = firstRC.getExpression();
    BinaryComparisonOperatorNode bcoNode = getNewJoinCondition(leftOperand, rightOperand);
    ValueNode andLeft = bcoNode;
    /* For NOT IN or ALL, and if either side of the comparison is nullable, and the
		 * subquery can not be flattened (because of that), we need to add IS NULL node
		 * on top of the nullables, such that the behavior is (beetle 5173):
		 *
		 *    (1) If we have nulls in right operand, no row is returned.
		 *    (2) If subquery result is empty before applying join predicate, every
		 *		  left row (including NULLs) is returned.
		 *	  (3) Otherwise, return {all left row} - {NULLs}
		 */
    if (isNOT_IN() || isALL()) {
        boolean leftNullable = leftOperand.getTypeServices().isNullable();
        boolean rightNullable = rightOperand.getTypeServices().isNullable();
        if (leftNullable || rightNullable) {
            /* Create a normalized structure.
				 */
            BooleanConstantNode falseNode = new BooleanConstantNode(false, cm);
            OrNode newOr = new OrNode(bcoNode, falseNode, cm);
            newOr.postBindFixup();
            andLeft = newOr;
            if (leftNullable) {
                UnaryComparisonOperatorNode leftIsNull = new IsNullNode(leftOperand, false, cm);
                leftIsNull.bindComparisonOperator();
                newOr = new OrNode(leftIsNull, andLeft, cm);
                newOr.postBindFixup();
                andLeft = newOr;
            }
            if (rightNullable) {
                UnaryComparisonOperatorNode rightIsNull = new IsNullNode(rightOperand, false, cm);
                rightIsNull.bindComparisonOperator();
                newOr = new OrNode(rightIsNull, andLeft, cm);
                newOr.postBindFixup();
                andLeft = newOr;
            }
        }
    }
    /* Place an AndNode above the <BinaryComparisonOperator> */
    andNode = new AndNode(andLeft, getTrueNode(), cm);
    /* Build the referenced table map for the new predicate */
    tableMap = new JBitSet(numTables);
    andNode.postBindFixup();
    /* Put the AndNode under a Predicate */
    predicate = new Predicate(andNode, tableMap, cm);
    predicate.categorize();
    /* Push the new Predicate to the subquery's list */
    resultSet = resultSet.addNewPredicate(predicate);
    /* Clean up the leftOperand and subquery ResultColumn */
    leftOperand = null;
    firstRC.setType(getTypeServices());
    firstRC.setExpression(getTrueNode());
    /* Add the IS [NOT] NULL above the SubqueryNode */
    switch(subqueryType) {
        case IN_SUBQUERY:
        case EQ_ANY_SUBQUERY:
        case NE_ANY_SUBQUERY:
        case LE_ANY_SUBQUERY:
        case LT_ANY_SUBQUERY:
        case GE_ANY_SUBQUERY:
        case GT_ANY_SUBQUERY:
            ucoNode = new IsNullNode(this, true, cm);
            break;
        case NOT_IN_SUBQUERY:
        case EQ_ALL_SUBQUERY:
        case NE_ALL_SUBQUERY:
        case LE_ALL_SUBQUERY:
        case LT_ALL_SUBQUERY:
        case GE_ALL_SUBQUERY:
        case GT_ALL_SUBQUERY:
            ucoNode = new IsNullNode(this, false, cm);
            break;
        default:
            if (SanityManager.DEBUG) {
                SanityManager.NOTREACHED();
            }
    }
    ucoNode.bindComparisonOperator();
    return ucoNode;
}
Also used : JBitSet(org.apache.derby.iapi.util.JBitSet) ContextManager(org.apache.derby.iapi.services.context.ContextManager)

Example 24 with JBitSet

use of org.apache.derby.iapi.util.JBitSet in project derby by apache.

the class UnaryComparisonOperatorNode method getOperand.

/**
 * @see RelationalOperator#getOperand
 */
public ValueNode getOperand(ColumnReference cRef, int refSetSize, boolean otherSide) {
    if (otherSide)
        // there is no "other" side for Unary, so just return null.
        return null;
    ColumnReference cr;
    if (operand instanceof ColumnReference) {
        /*
			** The operand is a column reference.
			** Is it the correct column?
			*/
        JBitSet cRefTables = new JBitSet(refSetSize);
        JBitSet crTables = new JBitSet(refSetSize);
        BaseTableNumbersVisitor btnVis = new BaseTableNumbersVisitor(crTables);
        cr = (ColumnReference) operand;
        try {
            cr.accept(btnVis);
            btnVis.setTableMap(cRefTables);
            cRef.accept(btnVis);
        } catch (StandardException se) {
            if (SanityManager.DEBUG) {
                SanityManager.THROWASSERT("Failed when trying to " + "find base table number for column reference check:", se);
            }
        }
        crTables.and(cRefTables);
        if (crTables.getFirstSetBit() != -1) {
            /*
				** The table is correct, how about the column position?
				*/
            if (cr.getSource().getColumnPosition() == cRef.getColumnNumber()) {
                /* We've found the correct column - return it. */
                return operand;
            }
        }
    }
    /* Not the column we're looking for */
    return null;
}
Also used : StandardException(org.apache.derby.shared.common.error.StandardException) JBitSet(org.apache.derby.iapi.util.JBitSet)

Example 25 with JBitSet

use of org.apache.derby.iapi.util.JBitSet in project derby by apache.

the class ValueNode method getTablesReferenced.

/**
 * Get a bit map of table references in this expression
 *
 * @return	A bit map of table numbers referred to in this expression
 *
 * @exception StandardException			Thrown on error
 */
JBitSet getTablesReferenced() throws StandardException {
    ReferencedTablesVisitor rtv = new ReferencedTablesVisitor(new JBitSet(0));
    accept(rtv);
    return rtv.getTableMap();
}
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