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 ba...@apache.org on 2006/03/01 02:23:47 UTC

svn commit: r381859 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/compile/ engine/org/apache/derby/impl/sql/compile/ testing/org/apache/derbyTesting/functionTests/master/

Author: bandaram
Date: Tue Feb 28 17:23:44 2006
New Revision: 381859

URL: http://svn.apache.org/viewcvs?rev=381859&view=rev
Log:
DERBY-805: Apply Part I of the fix. Refer to JIRA for complete writeup
on all the phases. This Phase broadly addresses:

When remembering "truly the best" access path for an Optimizable, we have to 
keep track of which OptimizerImpl the "truly the best" access is for.  
In most queries there will only be one OptimizerImpl in question, but in 
cases where there are nested subqueries, there will be one OptimizerImpl
for every level of nesting, and each OptimizerImpl might have its own
idea of what this Optimizable's "truly the best path" access path really is.
So whenever we save a "truly the best" path, we take note of which Optimizer
told us to do so.  Then as each level of subquery finishes optimization,
the corresponding OptimizerImpl can load its preferred access path into this
Optimizable's trulyTheBestAccessPath field and pass it up the tree, until 
eventually the outer-most OptimizerImpl can choose to either use the best path
that it received from below (by calling "rememberAsBest()") or else use the
path that it found to be "best" for itself.

Submitted by Army Brown (qozinx@sbcglobal.net)

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/predicatesIntoViews.out

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java?rev=381859&r1=381858&r2=381859&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/Optimizable.java Tue Feb 28 17:23:44 2006
@@ -231,14 +231,45 @@
 	public int convertAbsoluteToRelativeColumnPosition(int absolutePosition);
 
 	/**
+	 * When remembering "truly the best" access path for an Optimizable, we
+	 * have to keep track of which OptimizerImpl the "truly the best" access
+	 * is for.  In most queries there will only be one OptimizerImpl in
+	 * question, but in cases where there are nested subqueries, there will be
+	 * one OptimizerImpl for every level of nesting, and each OptimizerImpl
+	 * might have its own idea of what this Optimizable's "truly the best path"
+	 * access path really is.  So whenever we save a "truly the best" path,
+	 * we take note of which Optimizer told us to do so.  Then as each level
+	 * of subquery finishes optimization, the corresponding OptimizerImpl
+	 * can load its preferred access path into this Optimizable's
+	 * trulyTheBestAccessPath field and pass it up the tree, until eventually
+	 * the outer-most OptimizerImpl can choose to either use the best path
+	 * that it received from below (by calling "rememberAsBest()") or else
+	 * use the path that it found to be "best" for itself.
+	 *
+	 * This method is what allows us to keep track of which OptimizerImpl
+	 * saved which "best plan", and allows us to load the appropriate plans
+	 * after each round of optimization.
+	 * 
+	 * @param doAdd True if we're saving a best plan for the OptimizerImpl,
+	 *  false if we're loading/retrieving the best plan for the OptimizerImpl.
+	 * @param optimizer The OptimizerImpl for which we're saving/loading
+	 *  the "truly the best" path.
+	 */
+	public void addOrLoadBestPlanMapping(boolean doAdd,
+		Optimizer optimizer) throws StandardException;
+
+	/**
 	 * Remember the current access path as the best one (so far).
 	 *
 	 * @param planType	The type of plan (one of Optimizer.NORMAL_PLAN
 	 *					or Optimizer.SORT_AVOIDANCE_PLAN)
+	 * @param optimizer The OptimizerImpl that is telling this Optimizable
+	 *	to remember its current path as "truly the best".
 	 *
 	 * @exception StandardException thrown on error.
 	 */
-	public void rememberAsBest(int planType) throws StandardException;
+	public void rememberAsBest(int planType, Optimizer optimizer)
+		throws StandardException;
 
 	/**
 	 * Begin the optimization process for this Optimizable.  This can be

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java?rev=381859&r1=381858&r2=381859&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java Tue Feb 28 17:23:44 2006
@@ -52,6 +52,7 @@
 import java.util.Enumeration;
 import java.util.Properties;
 import java.util.Vector;
+import java.util.HashMap;
 
 /**
  * A FromTable represents a table in the FROM clause of a DML statement.
@@ -99,6 +100,14 @@
     
 	private boolean considerSortAvoidancePath;
 
+	// Set of optimizer->trulyTheBestAccessPath mappings used to keep track
+	// of which of this Optimizable's "trulyTheBestAccessPath" was the best
+	// with respect to a specific outer query; the outer query is represented
+	// by an instance of Optimizer.  Each outer query could potentially have
+	// a different idea of what this Optimizable's "best access path" is, so
+	// we have to keep track of them all.
+	HashMap optimizerToBestPlanMap;
+
   //this flag tells you if all the columns from this table are projected using * from it.
   //Used by replication enabled databases where the target-only view failure is detected
   //using this boolean
@@ -123,6 +132,7 @@
 		this.correlationName = (String) correlationName;
 		this.tableProperties = (Properties) tableProperties;
 		tableNumber = -1;
+		optimizerToBestPlanMap = null;
 	}
 
 	/**
@@ -495,8 +505,56 @@
 		return absolutePosition;
 	}
 
+	/** @see Optimizable#addOrLoadBestPlanMapping */
+	public void addOrLoadBestPlanMapping(boolean doAdd,
+		Optimizer optimizer) throws StandardException
+	{
+		AccessPathImpl ap = null;
+		if (doAdd)
+		{
+			// If the optimizerToBestPlanMap already exists, search for an
+			// AccessPath for the target optimizer and use that if we can.
+			if (optimizerToBestPlanMap == null)
+				optimizerToBestPlanMap = new HashMap();
+			else
+				ap = (AccessPathImpl)optimizerToBestPlanMap.get(optimizer);
+
+			// If we don't already have an AccessPath for the optimizer,
+			// create a new one.
+			if (ap == null)
+				ap = new AccessPathImpl(optimizer);
+
+			ap.copy(getTrulyTheBestAccessPath());
+			optimizerToBestPlanMap.put(optimizer, ap);
+			return;
+		}
+
+		// If we get here, we want to load the best plan from our map
+		// into this Optimizable's trulyTheBestAccessPath field.
+
+		// If we don't have any plans saved, then there's nothing to load.
+		// This can happen if the optimizer tried some join order for which
+		// there was no valid plan.
+		if (optimizerToBestPlanMap == null)
+			return;
+
+		ap = (AccessPathImpl)optimizerToBestPlanMap.get(optimizer);
+
+		// Again, might be the case that there is no plan stored for
+		// the optimizer if no valid plans have been discovered for
+		// that optimizer's current join order.
+		if (ap == null)
+			return;
+
+		// We found a best plan in our map, so load it into this Optimizable's
+		// trulyTheBestAccessPath field.
+		getTrulyTheBestAccessPath().copy(ap);
+		return;
+	}
+
 	/** @see Optimizable#rememberAsBest */
-	public void rememberAsBest(int planType) throws StandardException
+	public void rememberAsBest(int planType, Optimizer optimizer)
+		throws StandardException
 	{
 		AccessPath bestPath = null;
 
@@ -519,6 +577,12 @@
 		}
 
 		getTrulyTheBestAccessPath().copy(bestPath);
+
+		// Since we just set trulyTheBestAccessPath for the current
+		// join order of the received optimizer, take note of what
+		// that path is, in case we need to "revert" back to this
+		// path later.  See Optimizable.addOrLoadBestPlanMapping().
+		addOrLoadBestPlanMapping(true, optimizer);
 		 
 		/* also store the name of the access path; i.e index name/constraint
 		 * name if we're using an index to access the base table.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java?rev=381859&r1=381858&r2=381859&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java Tue Feb 28 17:23:44 2006
@@ -48,6 +48,7 @@
 import org.apache.derby.iapi.util.StringUtil;
 
 import java.util.Properties;
+import java.util.HashMap;
 
 /**
  * This will be the Level 1 Optimizer.
@@ -138,6 +139,22 @@
 	// max memory use per table
 	protected int maxMemoryPerTable;
 
+	// Whether or not we need to reload the best plan for an Optimizable
+	// when we "pull" it.  If the latest complete join order was the
+	// best one so far, then the Optimizable will already have the correct
+	// best plan loaded so we don't need to do the extra work.  But if
+	// the most recent join order was _not_ the best, then this flag tells
+	// us that we need to reload the best plan when pulling.
+	private boolean reloadBestPlan;
+
+	// Set of optimizer->bestJoinOrder mappings used to keep track of which
+	// of this OptimizerImpl's "bestJoinOrder"s was the best with respect to a
+	// a specific outer query; the outer query is represented by an instance
+	// of Optimizer.  Each outer query could potentially have a different
+	// idea of what this OptimizerImpl's "best join order" is, so we have
+	// to keep track of them all.
+	private HashMap savedJoinOrders;
+
 	protected  OptimizerImpl(OptimizableList optimizableList, 
 				  OptimizablePredicateList predicateList,
 				  DataDictionary dDictionary,
@@ -213,6 +230,27 @@
 
 		/* Get the time that optimization starts */
 		timeOptimizationStarted = System.currentTimeMillis();
+		reloadBestPlan = false;
+		savedJoinOrders = null;
+	}
+
+	/**
+	 * This method is called before every "round" of optimization, where
+	 * we define a "round" to be the period between the last time a call to
+	 * getOptimizer() (on either a ResultSetNode or an OptimizerFactory)
+	 * returned _this_ OptimizerImpl and the time a call to this OptimizerImpl's
+	 * getNextPermutation() method returns FALSE.  Any re-initialization
+	 * of state that is required before each round should be done in this
+	 * method.
+	 */
+	protected void prepForNextRound()
+	{
+		// We initialize reloadBestPlan to false so that if we end up
+		// pulling an Optimizable before we find a best join order
+		// (which can happen if there is no valid join order for this
+		// round) we won't inadvertently reload the best plans based
+		// on some previous round.
+		reloadBestPlan = false;
 	}
 
     public int getMaxMemoryPerTable()
@@ -700,6 +738,33 @@
 				*/
 				pullMe.pullOptPredicates(predicateList);
 
+				/*
+				** When we pull an Optimizable we need to go through and
+				** load whatever best path we found for that Optimizable
+				** with respect to _this_ OptimizerImpl.  An Optimizable
+				** can have different "best paths" for different Optimizer
+				** Impls if there are subqueries beneath it; we need to make
+				** sure that when we pull it, it's holding the best path as
+				** as we determined it to be for _us_.
+				**
+				** NOTE: We we only reload the best plan if it's necessary
+				** to do so--i.e. if the best plans aren't already loaded.
+				** The plans will already be loaded if the last complete
+				** join order we had was the best one so far, because that
+				** means we called "rememberAsBest" on every Optimizable
+				** in the list and, as part of that call, we will run through
+				** and set trulyTheBestAccessPath for the entire subtree.
+				** So if we haven't tried any other plans since then,
+				** we know that every Optimizable (and its subtree) already
+				** has the correct best plan loaded in its trulyTheBest
+				** path field.  It's good to skip the load in this case
+				** because 'reloading best plans' involves walking the
+				** entire subtree of _every_ Optimizable in the list, which
+				** can be expensive if there are deeply nested subqueries.
+				*/
+				if (reloadBestPlan)
+					pullMe.addOrLoadBestPlanMapping(false, this);
+
 				/* Mark current join position as unused */
 				proposedJoinOrder[joinPosition] = -1;
 			}
@@ -835,6 +900,11 @@
 				}
 				if (finishedCycle)
 				{
+					// We just set proposedJoinOrder[joinPosition] above, so
+					// if we're done we need to put it back to -1 to indicate
+					// that it's an empty slot.  Then we rewind and pull any
+					// other Optimizables at positions < joinPosition.
+					proposedJoinOrder[joinPosition] = -1;
 					joinPosition--;
 					if (joinPosition >= 0)
 					{
@@ -890,6 +960,8 @@
 				optimizableList.getOptimizable(
 									proposedJoinOrder[joinPosition]);
 			pullMe.pullOptPredicates(predicateList);
+			if (reloadBestPlan)
+				pullMe.addOrLoadBestPlanMapping(false, this);
 			proposedJoinOrder[joinPosition] = -1;
 			if (joinPosition == 0) break;
 		}
@@ -1145,7 +1217,14 @@
 				if ((! foundABestPlan) || currentCost.compare(bestCost) < 0)
 				{
 					rememberBestCost(currentCost, Optimizer.NORMAL_PLAN);
+
+					// Since we just remembered all of the best plans,
+					// no need to reload them when pulling Optimizables
+					// from this join order.
+					reloadBestPlan = false;
 				}
+				else
+					reloadBestPlan = true;
 
 				/* Subtract cost of sorting from non-sort-avoidance cost */
 				if (requiredRowOrdering != null)
@@ -1230,7 +1309,8 @@
 		}
 		for (int i = 0; i < numOptimizables; i++)
 		{
-			optimizableList.getOptimizable(bestJoinOrder[i]).rememberAsBest(planType);
+			optimizableList.getOptimizable(bestJoinOrder[i]).
+				rememberAsBest(planType, this);
 		}
 
 		/* Remember if a sort is not needed for this plan */
@@ -1951,4 +2031,72 @@
 	
 	/** @see Optimizer#useStatistics */
 	public boolean useStatistics() { return useStatistics && optimizableList.useStatistics(); }
+
+	/**
+	 * Remember the current best join order as the best one for
+	 * some outer query, represented by another OptimizerImpl. Then
+	 * iterate through our optimizableList and tell each Optimizable
+	 * to remember its best plan with respect to the outer query.
+	 * See Optimizable.addOrLoadBestPlan() for more on why this is
+	 * necessary.
+	 *
+	 * @param doAdd True if we're adding a mapping, false if we're loading.
+	 * @param outerOptimizer OptimizerImpl corresponding to an outer
+	 *  query; we will use this as the key for the mapping.
+	 */
+	protected void addOrLoadBestPlanMappings(boolean doAdd,
+		Optimizer outerOptimizer) throws StandardException
+	{
+		// First we save this OptimizerImpl's best join order.
+		int [] joinOrder = null;
+		if (doAdd)
+		{
+			// If the savedJoinOrder map already exists, search for the
+			// join order for the target optimizer and reuse that.
+			if (savedJoinOrders == null)
+				savedJoinOrders = new HashMap();
+			else
+				joinOrder = (int[])savedJoinOrders.get(outerOptimizer);
+
+			// If we don't already have a join order array for the optimizer,
+			// create a new one.
+			if (joinOrder == null)
+				joinOrder = new int[numOptimizables];
+
+			// Now copy current bestJoinOrder and save it.
+			for (int i = 0; i < bestJoinOrder.length; i++)
+				joinOrder[i] = bestJoinOrder[i];
+
+			savedJoinOrders.put(outerOptimizer, joinOrder);
+		}
+		else
+		{
+			// If we get here, we want to load the best join order from our
+			// map into this OptimizerImpl's bestJoinOrder array.
+
+			// If we don't have any join orders saved, then there's nothing to
+			// load.  This can happen if the optimizer tried some join order
+			// for which there was no valid plan.
+			if (savedJoinOrders == null)
+				return;
+
+			joinOrder = (int[])savedJoinOrders.get(outerOptimizer);
+			if (joinOrder == null)
+				return;
+
+			// Load the join order we found into our bestJoinOrder array.
+			for (int i = 0; i < joinOrder.length; i++)
+				bestJoinOrder[i] = joinOrder[i];
+		}
+
+		// Now iterate through all Optimizables in this OptimizerImpl's list
+	 	// and add/load the best plan "mapping" for each one, as described in
+	 	// in Optimizable.addOrLoadBestPlanMapping().
+		for (int i = optimizableList.size() - 1; i >= 0; i--)
+		{
+			optimizableList.getOptimizable(i).
+				addOrLoadBestPlanMapping(doAdd, outerOptimizer);
+		}
+	}
+
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java?rev=381859&r1=381858&r2=381859&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java Tue Feb 28 17:23:44 2006
@@ -198,12 +198,12 @@
 	/** @see Optimizable#rememberAsBest 
 		@exception StandardException	Thrown on error
 	 */
-	public void rememberAsBest(int planType)
+	public void rememberAsBest(int planType, Optimizer optimizer)
 		throws StandardException
 	{
-		super.rememberAsBest(planType);
+		super.rememberAsBest(planType, optimizer);
 		if (childResult instanceof Optimizable)
-			((Optimizable) childResult).rememberAsBest(planType);
+			((Optimizable) childResult).rememberAsBest(planType, optimizer);
 	}
 
 	/* Don't print anything for a PRN, as their

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java?rev=381859&r1=381858&r2=381859&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java Tue Feb 28 17:23:44 2006
@@ -1608,7 +1608,24 @@
 								getLanguageConnectionContext());
 		}
 
+		((OptimizerImpl)optimizer).prepForNextRound();
 		return optimizer;
+	}
+
+	/**
+	 * Get the optimizer for this result set; assumption is that
+	 * this.optimizer has already been created by the getOptimizer()
+	 * method above.
+	 */
+	protected OptimizerImpl getOptimizerImpl() {
+
+		if (SanityManager.DEBUG) {
+			SanityManager.ASSERT(optimizer != null,
+				"Tried to retrieve optimizer for a result set, but no such " +
+				"optimizer existed.");
+		}
+
+		return (OptimizerImpl)optimizer;
 	}
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java?rev=381859&r1=381858&r2=381859&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java Tue Feb 28 17:23:44 2006
@@ -164,6 +164,29 @@
 	}
 
 	/**
+	 * @see Optimizable#addOrLoadBestPlanMapping
+	 *
+	 * Makes a call to add/load the plan mapping for this node,
+	 * and then makes the necessary call to recurse on this node's
+	 * child, in order to ensure that we have a full plan mapped.
+	 */
+	public void addOrLoadBestPlanMapping(boolean doAdd,
+		Optimizer optimizer) throws StandardException
+	{
+		super.addOrLoadBestPlanMapping(doAdd, optimizer);
+		if (childResult instanceof Optimizable)
+		{
+			((Optimizable)childResult).
+				addOrLoadBestPlanMapping(doAdd, optimizer);
+		}
+		else
+		{
+			childResult.getOptimizerImpl().
+				addOrLoadBestPlanMappings(doAdd, optimizer);
+		}
+	}
+
+	/**
 	 * Prints the sub-nodes of this object.  See QueryTreeNode.java for
 	 * how tree printing is supposed to work.
 	 *

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java?rev=381859&r1=381858&r2=381859&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java Tue Feb 28 17:23:44 2006
@@ -156,6 +156,41 @@
 	}
 
 	/**
+	 * @see Optimizable#addOrLoadBestPlanMapping
+	 *
+	 * Makes a call to add/load the plan mapping for this node,
+	 * and then makes the necessary call to recurse on this node's
+	 * left and right child, in order to ensure that we have a
+	 * full plan mapped.
+	 */
+	public void addOrLoadBestPlanMapping(boolean doAdd,
+		Optimizer optimizer) throws StandardException
+	{
+		super.addOrLoadBestPlanMapping(doAdd, optimizer);
+		if (leftResultSet instanceof Optimizable)
+		{
+			((Optimizable)leftResultSet).
+				addOrLoadBestPlanMapping(doAdd, optimizer);
+		}
+		else
+		{
+			leftResultSet.getOptimizerImpl().
+				addOrLoadBestPlanMappings(doAdd, optimizer);
+		}
+
+		if (rightResultSet instanceof Optimizable)
+		{
+			((Optimizable)rightResultSet).
+				addOrLoadBestPlanMapping(doAdd, optimizer);
+		}
+		else
+		{
+			rightResultSet.getOptimizerImpl().
+				addOrLoadBestPlanMappings(doAdd, optimizer);
+		}
+	}
+
+	/**
 	 * Convert this object to a String.  See comments in QueryTreeNode.java
 	 * for how this should be done for tree printing.
 	 *
@@ -742,6 +777,7 @@
 													(RequiredRowOrdering) null,
 													getCompilerContext().getNumTables(),
 													  lcc);
+			((OptimizerImpl)optimizer).prepForNextRound();
 
 			if (sourceResultSet == leftResultSet)
 			{

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/predicatesIntoViews.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/predicatesIntoViews.out?rev=381859&r1=381858&r2=381859&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/predicatesIntoViews.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/predicatesIntoViews.out Tue Feb 28 17:23:44 2006
@@ -7244,7 +7244,7 @@
 									next time (milliseconds) = 0
 									close time (milliseconds) = 0
 								Left result set:
-									Table Scan ResultSet for CLASSIFICATION_VALUES at serializable isolation level using share table locking chosen by the optimizer
+									Index Scan ResultSet for REPOSITORYOBJECTRESOURCE using constraint ROR_CURRENTVERSION at serializable isolation level using share table locking chosen by the optimizer
 									Number of opens = 0
 									Rows seen = 0
 									Rows filtered = 0
@@ -7255,11 +7255,13 @@
 										close time (milliseconds) = 0
 									scan information: 
 										start position: 
-null										stop position: 
-null										qualifiers:
+	None
+										stop position: 
+	None
+										qualifiers:
 None
 								Right result set:
-									Hash Scan ResultSet for REPOSITORYOBJECTRESOURCE using constraint ROR_CURRENTVERSION at serializable isolation level using share table locking: 
+									Hash Scan ResultSet for CLASSIFICATION_VALUES at serializable isolation level using share table locking: 
 									Number of opens = 0
 									Hash table size = 0
 									Hash key is column number 0
@@ -7271,10 +7273,8 @@
 										close time (milliseconds) = 0
 									scan information: 
 										start position: 
-	None
-										stop position: 
-	None
-										scan qualifiers:
+null										stop position: 
+null										scan qualifiers:
 None
 										next qualifiers:
 Column[0][0] Id: 0