You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by mi...@apache.org on 2006/08/18 00:34:00 UTC

svn commit: r432414 - /db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java

Author: mikem
Date: Thu Aug 17 15:33:59 2006
New Revision: 432414

URL: http://svn.apache.org/viewvc?rev=432414&view=rev
Log:
DERBY-1681, submitted by Army Brown

Backporting svn r432367 from trunk into 10.1.  

Fixes the following issue:
If Derby chooses to do a join between two FromTables and the right table is a 
chain of UNIONs, then the optimizer may choose to push the join predicate (if
provided) down into the UNION and to both children of every UNION in the chain. 
But if the predicate cannot be pushed to the children of any of the UNIONs 
(except the top-level one) the predicate can end up being ignored altogether 
with respect to that UNION's children. The result is that query execution can 
return rows that do not satisfy the predicate.

This is a regression introduced in 10.1.2.4 and thus it affects 10.1.3 and 10.2.
I came across this while tracing through code for DERBY-1633.

For more detailed explanation of problem and solution see html doc attached to
DERBY-1681.


Modified:
    db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java

Modified: db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java?rev=432414&r1=432413&r2=432414&view=diff
==============================================================================
--- db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java (original)
+++ db/derby/code/branches/10.1/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java Thu Aug 17 15:33:59 2006
@@ -170,10 +170,14 @@
 		// Modify this node's access paths.
 		ResultSetNode topNode = (ResultSetNode)modifyAccessPath(outerTables);
 
-		// Now see if there are any left over predicates; if so, then we
-		// have to generate a ProjectRestrictNode.
-		if (((leftOptPredicates != null) && (leftOptPredicates.size() > 0)) ||
-			((rightOptPredicates != null) && (rightOptPredicates.size() > 0)))
+		/* Now see if there are any left over predicates; if so, then we
+		 * have to generate a ProjectRestrictNode.  Note: we walk the
+		 * entire chain of UnionNodes (if there is a chain) and see if
+		 * any UnionNode at any level has un-pushed predicates; if so, then
+		 * we use a PRN to enforce the predicate at this, the top-most
+		 * UnionNode.
+		 */
+		if (hasUnPushedPredicates())
 		{
 			// When we generate the project restrict node, we pass in the
 			// "pushedPredicates" list because that has the predicates in
@@ -459,6 +463,42 @@
 		// We're done with the pushedPredicates list, so clear it out
 		// in preparation for another phase of optimization.
 		pushedPredicates.removeAllElements();
+	}
+
+	/**
+	 * It's possible that we tried to push predicates to this node's
+	 * children but failed to do so. This can happen if this node's
+	 * children both satisfy the criteria for pushing a predicate
+	 * (namely, they reference base tables) but the children's
+	 * children do not (see modifyAccessPaths() above for an example
+	 * of how that can happen).  So this method will walk the chain
+	 * of nodes beneath this one and determine if any SetOperatorNode
+	 * at any level has predicates that were not successfully pushed
+	 * to both of its children (note: this currently only applies
+	 * to UnionNodes).
+	 *
+	 * @return True if any UnionNode (or actually, any SetOperatorNode)
+	 *  in the chain of SetOperatorNodes (starting with this one) has
+	 *  unpushed predicates; false otherwise.
+	 */
+	protected boolean hasUnPushedPredicates()
+	{
+		// Check this node.
+		if (((leftOptPredicates != null) && (leftOptPredicates.size() > 0)) ||
+			((rightOptPredicates != null) && (rightOptPredicates.size() > 0)))
+		{
+			return true;
+		}
+
+		// Now check the children.
+		if ((leftResultSet instanceof SetOperatorNode) &&
+			((SetOperatorNode)leftResultSet).hasUnPushedPredicates())
+		{
+			return true;
+		}
+
+		return ((rightResultSet instanceof SetOperatorNode) &&
+			((SetOperatorNode)rightResultSet).hasUnPushedPredicates());
 	}
 
 	/**