[teiid-commits] teiid SVN: r808 - in trunk/engine/src: main/java/com/metamatrix/query/optimizer/batch and 9 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Mon Apr 20 17:02:03 EDT 2009


Author: shawkins
Date: 2009-04-20 17:02:03 -0400 (Mon, 20 Apr 2009)
New Revision: 808

Removed:
   trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/NeedsEvaluationVisitor.java
Modified:
   trunk/engine/src/main/java/com/metamatrix/query/function/FunctionLibrary.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/batch/BatchedUpdatePlanner.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/PlanToProcessConverter.java
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
   trunk/engine/src/main/java/com/metamatrix/query/parser/ParseInfo.java
   trunk/engine/src/main/java/com/metamatrix/query/resolver/command/SimpleQueryResolver.java
   trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/EvaluatableVisitor.java
   trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/EvaluateExpressionVisitor.java
   trunk/engine/src/main/java/com/metamatrix/query/util/CommandContext.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/MetaDataProcessor.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedPlanCache.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedStatementRequest.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/Request.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestAccessNode.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestBatchedUpdateNode.java
   trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedPlanCache.java
   trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java
Log:
TEIID-81, TEIID-512 updating the planning logic to promote non-session specific commands to be globally reusable

Modified: trunk/engine/src/main/java/com/metamatrix/query/function/FunctionLibrary.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/function/FunctionLibrary.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/function/FunctionLibrary.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -36,6 +36,7 @@
 import com.metamatrix.query.function.metadata.FunctionParameter;
 import com.metamatrix.query.sql.symbol.Expression;
 import com.metamatrix.query.sql.symbol.Function;
+import com.metamatrix.query.util.CommandContext;
 import com.metamatrix.query.util.ErrorMessageKeys;
 
 
@@ -348,6 +349,11 @@
                 throw new FunctionExecutionException(ErrorMessageKeys.FUNCTION_0002, QueryPlugin.Util.getString(ErrorMessageKeys.FUNCTION_0002, localDescriptor.getName()));
             }
         }
+        
+        if (fd.getDeterministic() >= FunctionMethod.SESSION_DETERMINISTIC && values.length > 0 && values[0] instanceof CommandContext) {
+        	CommandContext cc = (CommandContext)values[0];
+        	cc.setSessionFunctionEvaluated(true);
+        }
         
         // Invoke the method and return the result
         try {

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/batch/BatchedUpdatePlanner.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/batch/BatchedUpdatePlanner.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/batch/BatchedUpdatePlanner.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -53,7 +53,7 @@
 import com.metamatrix.query.sql.lang.Update;
 import com.metamatrix.query.sql.symbol.GroupSymbol;
 import com.metamatrix.query.sql.util.VariableContext;
-import com.metamatrix.query.sql.visitor.NeedsEvaluationVisitor;
+import com.metamatrix.query.sql.visitor.EvaluatableVisitor;
 import com.metamatrix.query.util.CommandContext;
 
 
@@ -131,7 +131,7 @@
                     	contexts.add(allContexts.get(commandIndex));
                     	shouldEvaluate.add(Boolean.TRUE);
                     } else {
-                    	shouldEvaluate.add(NeedsEvaluationVisitor.needsEvaluation(updateCommand));
+                    	shouldEvaluate.add(EvaluatableVisitor.needsProcessingEvaluation(updateCommand));
                     }
                     // Find out if there are other commands called on the same physical model
                     // immediately and contiguously after this one
@@ -144,7 +144,7 @@
                             	contexts.add(allContexts.get(batchIndex));
                             	shouldEvaluate.add(Boolean.TRUE);
                             } else {
-                            	shouldEvaluate.add(NeedsEvaluationVisitor.needsEvaluation(batchingCandidate));
+                            	shouldEvaluate.add(EvaluatableVisitor.needsProcessingEvaluation(batchingCandidate));
                             }
                         } else { // Otherwise, stop batching at this point. The next command may well be the start of a new batch
                             break batchLoop;

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/PlanToProcessConverter.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/PlanToProcessConverter.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/PlanToProcessConverter.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -82,8 +82,8 @@
 import com.metamatrix.query.sql.symbol.Expression;
 import com.metamatrix.query.sql.symbol.GroupSymbol;
 import com.metamatrix.query.sql.util.SymbolMap;
+import com.metamatrix.query.sql.visitor.EvaluatableVisitor;
 import com.metamatrix.query.sql.visitor.GroupCollectorVisitor;
-import com.metamatrix.query.sql.visitor.NeedsEvaluationVisitor;
 import com.metamatrix.query.util.ErrorMessageKeys;
 
 public class PlanToProcessConverter {
@@ -306,7 +306,7 @@
                         } catch (QueryMetadataException err) {
                             throw new MetaMatrixComponentException(err);
                         }
-                        aNode.setShouldEvaluateExpressions(NeedsEvaluationVisitor.needsEvaluation(command));
+                        aNode.setShouldEvaluateExpressions(EvaluatableVisitor.needsProcessingEvaluation(command));
                     }
                     
                     try {

Modified: trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -54,7 +54,7 @@
 import com.metamatrix.query.sql.symbol.Function;
 import com.metamatrix.query.sql.symbol.SearchedCaseExpression;
 import com.metamatrix.query.sql.visitor.ElementCollectorVisitor;
-import com.metamatrix.query.sql.visitor.EvaluateExpressionVisitor;
+import com.metamatrix.query.sql.visitor.EvaluatableVisitor;
 
 /**
  */
@@ -228,7 +228,7 @@
     public void visit(Function obj) {
         try {
             //if the function can be evaluated then return as it will get replaced during the final rewrite 
-            if (EvaluateExpressionVisitor.willBecomeConstant(obj, true)) { 
+            if (EvaluatableVisitor.willBecomeConstant(obj, true)) { 
                 return; 
             }
             if(obj.getFunctionDescriptor().getPushdown() == FunctionMethod.CANNOT_PUSHDOWN || ! CapabilitiesUtil.supportsScalarFunction(modelID, obj, metadata, capFinder)) {

Modified: trunk/engine/src/main/java/com/metamatrix/query/parser/ParseInfo.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/parser/ParseInfo.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/parser/ParseInfo.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -44,4 +44,21 @@
 	public boolean allowDoubleQuotedVariable() {
 	    return allowDoubleQuotedVariable;
 	}
+	
+	@Override
+	public int hashCode() {
+		return allowDoubleQuotedVariable?1:0;
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (!(obj instanceof ParseInfo)) {
+			return false;
+		}
+		ParseInfo other = (ParseInfo)obj;
+		return this.allowDoubleQuotedVariable == other.allowDoubleQuotedVariable;
+	}
 }
\ No newline at end of file

Modified: trunk/engine/src/main/java/com/metamatrix/query/resolver/command/SimpleQueryResolver.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/resolver/command/SimpleQueryResolver.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/resolver/command/SimpleQueryResolver.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -92,7 +92,7 @@
     private static final String ALL_IN_GROUP_SUFFIX = ".*"; //$NON-NLS-1$
 
     private static Command resolveVirtualGroup(GroupSymbol virtualGroup, Command parentCommand, QueryMetadataInterface metadata, AnalysisRecord analysis)
-    throws QueryMetadataException, QueryResolverException, MetaMatrixComponentException, QueryParserException {
+    throws QueryMetadataException, QueryResolverException, MetaMatrixComponentException {
         QueryNode qnode = null;
         
         Object metadataID = virtualGroup.getMetadataID();
@@ -253,7 +253,7 @@
     }
 
     private static Command convertToSubquery(QueryNode qnode, boolean nocache, QueryMetadataInterface metadata)
-    throws QueryResolverException, MetaMatrixComponentException, QueryParserException {
+    throws QueryResolverException, MetaMatrixComponentException {
 
         // Parse this node's command
         Command command = qnode.getCommand();
@@ -605,8 +605,6 @@
                 throw new MetaMatrixRuntimeException(e);
             } catch(MetaMatrixComponentException e) {
                 throw new MetaMatrixRuntimeException(e);                        
-            } catch (QueryParserException e) {
-            	throw new MetaMatrixRuntimeException(e);
 			}
         }
         

Modified: trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/EvaluatableVisitor.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/EvaluatableVisitor.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/EvaluatableVisitor.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -25,6 +25,8 @@
  */
 package com.metamatrix.query.sql.visitor;
 
+import java.util.TreeSet;
+
 import com.metamatrix.query.function.FunctionLibrary;
 import com.metamatrix.query.function.metadata.FunctionMethod;
 import com.metamatrix.query.metadata.TempMetadataID;
@@ -46,118 +48,124 @@
 /**
  * <p>This visitor class will traverse a language object tree, and determine
  * if the current expression can be evaluated</p>
- * 
- * <p>The public visit() methods should NOT be called directly.</p>
- * 
- * There are three possible scenarios:
- * 
- * duringPlanning | fullyEvaluatable
- * ---------------------------------
- * false          | false            = will become processing time constant
- * false          | true             = processing time evaluation possible
- * true           | true             = planning time evaluation possible (should always be deterministic)
- * 
  */
 public class EvaluatableVisitor extends LanguageVisitor {
+	
+	public enum EvaluationLevel {
+		PLANNING,
+		PROCESSING,
+		PUSH_DOWN,
+	}
 
-    protected boolean evaluationPossible = true;
-    
-    //TODO: there aren't really 16 states here, this should be minimized
-    private boolean duringPlanning = false;
-    private boolean fullyEvaluatable = false;
-    private boolean deterministic = false;
-    private boolean pushdown = false;
-    
-    public EvaluatableVisitor(boolean duringPlanning, boolean fullyEvaluatable) {
-        this.duringPlanning = duringPlanning;
-        this.fullyEvaluatable = fullyEvaluatable;
-    }
-
+	private TreeSet<EvaluationLevel> levels = new TreeSet<EvaluationLevel>();
+	private EvaluationLevel targetLevel;
+	private int determinismLevel;
+	private boolean hasCorrelatedReferences;
+	    
     public void visit(Function obj) {
+        this.setDeterminismLevel(obj.getFunctionDescriptor().getDeterministic());
         if (obj.getFunctionDescriptor().getPushdown() == FunctionMethod.MUST_PUSHDOWN) {
-            evaluationNotPossible();
-        } else if (duringPlanning) {
-            if (obj.getName().equalsIgnoreCase(FunctionLibrary.LOOKUP)) {
-                evaluationNotPossible();
-            } else if (obj.getFunctionDescriptor().getDeterministic() >= FunctionMethod.COMMAND_DETERMINISTIC) {
-                evaluationNotPossible();
-            }
-        } else if (deterministic && obj.getFunctionDescriptor().getDeterministic() == FunctionMethod.NONDETERMINISTIC) {
-            evaluationNotPossible();
+            evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
+        } else if (obj.getName().equalsIgnoreCase(FunctionLibrary.LOOKUP)
+        		//TODO: if we had the context here we could plan better for non-prepared requests
+        		|| obj.getFunctionDescriptor().getDeterministic() >= FunctionMethod.COMMAND_DETERMINISTIC) {
+            evaluationNotPossible(EvaluationLevel.PROCESSING);
         }
     }
     
-    private boolean evaluationNotPossible() {
-        evaluationPossible = false;
-        setAbort(true);
-        return evaluationPossible;
+    private void setDeterminismLevel(int value) {
+    	determinismLevel = Math.max(determinismLevel, value);
     }
+    
+    private void evaluationNotPossible(EvaluationLevel newLevel) {
+    	levels.add(newLevel);
+    	EvaluationLevel level = levels.last();
+    	if (targetLevel != null && level.compareTo(targetLevel) > 0) {
+    		setAbort(true);
+    	}
+    }
         
     public void visit(ElementSymbol obj) {
     	//if the element is a variable, or an element that will have a value, it will be evaluatable at runtime
-    	if (duringPlanning || fullyEvaluatable) {
-    		evaluationNotPossible();
-    	} else {
-    		//begin hack for not having the metadata passed in
-    		if (obj.getGroupSymbol().getMetadataID() instanceof TempMetadataID) {
-    			TempMetadataID tid = (TempMetadataID)obj.getGroupSymbol().getMetadataID();
-    			if (tid.isScalarGroup()) {
-    				return;
-    			}
-    		}
-    		evaluationNotPossible();
-    	}
+		//begin hack for not having the metadata passed in
+		if (obj.getGroupSymbol().getMetadataID() instanceof TempMetadataID) {
+			TempMetadataID tid = (TempMetadataID)obj.getGroupSymbol().getMetadataID();
+			if (tid.isScalarGroup()) {
+				evaluationNotPossible(EvaluationLevel.PROCESSING);
+				return;
+			}
+		}
+		evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
     }
     
     public void visit(ExpressionSymbol obj) {
-        evaluationNotPossible();
+		evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
     }
     
     public void visit(AggregateSymbol obj) {
-        evaluationNotPossible();
+		evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
     }
     
+    /**
+     * We assume the non-push down for correlation variables,
+     * then make specific checks when correlated variables are allowed.
+     */
     public void visit(Reference obj) {
-        if (duringPlanning || fullyEvaluatable) {
-            evaluationNotPossible();
-        } else if (pushdown && obj.isCorrelated()) {
-        	evaluationNotPossible();
-        }
+        hasCorrelatedReferences |= obj.isCorrelated();
+    	evaluationNotPossible(EvaluationLevel.PROCESSING);
     }
     
     public void visit(StoredProcedure proc){
-        evaluationNotPossible();  
+		evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
     }
     
     public void visit(ScalarSubquery obj){
-        evaluationNotPossible();  
+		evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
     }
     
     public void visit(DependentSetCriteria obj) {
-        evaluationNotPossible();
+		evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
     }
     
     public void visit(ExistsCriteria obj) {
-        evaluationNotPossible(); 
+		evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
     }        
 
     public void visit(SubquerySetCriteria obj) {
-        evaluationNotPossible(); 
+		evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
     }        
 
     public void visit(SubqueryCompareCriteria obj) {
-        evaluationNotPossible(); 
+		evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
     }
     
-    public boolean isEvaluationPossible() {
-        return evaluationPossible;
+    private boolean isEvaluationPossible() {
+    	if (levels.isEmpty()) {
+    		return true;
+    	}
+    	return levels.last().compareTo(targetLevel) <= 0;
     }
     
-    static final boolean isEvaluatable(LanguageObject obj, boolean duringPlanning, boolean fullyEvaluatable, boolean deterministic, boolean pushdown) {
-        EvaluatableVisitor visitor = new EvaluatableVisitor(duringPlanning, fullyEvaluatable);
-        visitor.deterministic = deterministic;
-        visitor.pushdown = pushdown;
+    public static final boolean isEvaluatable(LanguageObject obj, EvaluationLevel target) {
+        EvaluatableVisitor visitor = new EvaluatableVisitor();
+        visitor.targetLevel = target;
         PreOrderNavigator.doVisit(obj, visitor);
         return visitor.isEvaluationPossible();
     }
+    
+    public static final boolean willBecomeConstant(LanguageObject obj, boolean pushdown) {
+        EvaluatableVisitor visitor = new EvaluatableVisitor();
+        visitor.targetLevel = EvaluationLevel.PROCESSING;
+        PreOrderNavigator.doVisit(obj, visitor);
+        if (pushdown && (visitor.hasCorrelatedReferences || visitor.determinismLevel >= FunctionMethod.NONDETERMINISTIC)) {
+        	return false;
+        }
+        return visitor.isEvaluationPossible();
+    }
+    
+    public static final boolean needsProcessingEvaluation(LanguageObject obj) {
+        EvaluatableVisitor visitor = new EvaluatableVisitor();
+        PreOrderNavigator.doVisit(obj, visitor);
+        return visitor.levels.contains(EvaluationLevel.PROCESSING);
+    }
 }

Modified: trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/EvaluateExpressionVisitor.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/EvaluateExpressionVisitor.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/EvaluateExpressionVisitor.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -37,6 +37,7 @@
 import com.metamatrix.query.sql.symbol.Expression;
 import com.metamatrix.query.sql.symbol.Reference;
 import com.metamatrix.query.sql.symbol.ScalarSubquery;
+import com.metamatrix.query.sql.visitor.EvaluatableVisitor.EvaluationLevel;
 import com.metamatrix.query.util.CommandContext;
 
 /**
@@ -74,7 +75,7 @@
      */
     public Expression replaceExpression(Expression expr) {
         //if the expression is a constant or is not evaluatable, just return
-        if (expr instanceof Constant || expr instanceof ScalarSubquery || (!(expr instanceof Reference) && !EvaluatableVisitor.isEvaluatable(expr, false, true, false, false))) {
+        if (expr instanceof Constant || expr instanceof ScalarSubquery || (!(expr instanceof Reference) && !EvaluatableVisitor.isEvaluatable(expr, EvaluationLevel.PROCESSING))) {
             return expr;
         }
 
@@ -95,18 +96,14 @@
      *  evaluatable during planning
      */
     public static final boolean willBecomeConstant(LanguageObject obj) {
-        return willBecomeConstant(obj, false);
+        return EvaluatableVisitor.willBecomeConstant(obj, false);
     }
     
-    public static final boolean willBecomeConstant(LanguageObject obj, boolean pushdown) {
-        return EvaluatableVisitor.isEvaluatable(obj, false, false, true, pushdown);
-    }
-    
     /**
      *  Should be called to check if the object can fully evaluated
      */
     public static final boolean isFullyEvaluatable(LanguageObject obj, boolean duringPlanning) {
-        return EvaluatableVisitor.isEvaluatable(obj, duringPlanning, true, true, false);
+        return EvaluatableVisitor.isEvaluatable(obj, duringPlanning?EvaluationLevel.PLANNING:EvaluationLevel.PROCESSING);
     }
         
     public static final void replaceExpressions(LanguageObject obj, boolean deep, LookupEvaluator dataMgr, CommandContext context)

Deleted: trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/NeedsEvaluationVisitor.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/NeedsEvaluationVisitor.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/sql/visitor/NeedsEvaluationVisitor.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -1,76 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-package com.metamatrix.query.sql.visitor;
-
-import com.metamatrix.query.sql.LanguageObject;
-import com.metamatrix.query.sql.LanguageVisitor;
-import com.metamatrix.query.sql.lang.DependentSetCriteria;
-import com.metamatrix.query.sql.navigator.DeepPreOrderNavigator;
-import com.metamatrix.query.sql.symbol.Function;
-import com.metamatrix.query.sql.symbol.Reference;
-
-/**
- * Checks the language object for expressions or criteria that need to be evaluated at execution time
- */
-public class NeedsEvaluationVisitor extends LanguageVisitor {
-    
-    private boolean needsEvaluation = false;
-    
-    /** 
-     * @see com.metamatrix.query.sql.LanguageVisitor#visit(com.metamatrix.query.sql.symbol.Reference)
-     */
-    @Override
-    public void visit(Reference obj) {
-        setNeedsEvaluation();
-    }
-    
-    /** 
-     * @see com.metamatrix.query.sql.LanguageVisitor#visit(com.metamatrix.query.sql.lang.DependentSetCriteria)
-     */
-    @Override
-    public void visit(DependentSetCriteria obj) {
-        setNeedsEvaluation();
-    }
-    
-    /** 
-     * @see com.metamatrix.query.sql.LanguageVisitor#visit(com.metamatrix.query.sql.symbol.Function)
-     */
-    @Override
-    public void visit(Function obj) {
-        if (EvaluatableVisitor.isEvaluatable(obj, false, true, false, false)) {
-            setNeedsEvaluation();
-        }
-    }
-
-    public void setNeedsEvaluation() {
-        this.needsEvaluation = true;
-        setAbort(true);
-    }
-    
-    public static boolean needsEvaluation(LanguageObject obj) {
-        NeedsEvaluationVisitor visitor = new NeedsEvaluationVisitor();
-        DeepPreOrderNavigator.doVisit(obj, visitor);
-        return visitor.needsEvaluation;
-    }
-    
-}

Modified: trunk/engine/src/main/java/com/metamatrix/query/util/CommandContext.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/util/CommandContext.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/com/metamatrix/query/util/CommandContext.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -98,6 +98,10 @@
     
     private VariableContext variableContext = new VariableContext();
     
+    private CommandContext parent;
+    
+    private boolean sessionFunctionEvaluated;
+    
     /**
      * Construct a new context.
      * @param collectNodeStatistics TODO
@@ -149,11 +153,27 @@
         this.planToProcessConverter = context.planToProcessConverter;
         this.queryProcessorFactory = context.queryProcessorFactory;
         this.variableContext = context.variableContext;
+        this.parent = context;
     }
         
     public CommandContext() {        
     }
     
+    public boolean isSessionFunctionEvaluated() {
+    	if (parent != null) {
+    		return parent.isSessionFunctionEvaluated();
+    	}
+		return sessionFunctionEvaluated;
+	}
+    
+    public void setSessionFunctionEvaluated(boolean sessionFunctionEvaluated) {
+    	if (parent != null) {
+    		parent.setCollectNodeStatistics(sessionFunctionEvaluated);
+    	} else {
+    		this.sessionFunctionEvaluated = sessionFunctionEvaluated;
+    	}
+	}
+    
     /**
      * @return
      */
@@ -301,6 +321,9 @@
     }
     
     public double getNextRand() {
+    	if (parent != null) {
+    		return parent.getNextRand();
+    	}
         if (random == null) {
             random = new Random();
         }
@@ -308,6 +331,9 @@
     }
     
     public double getNextRand(long seed) {
+    	if (parent != null) {
+    		return parent.getNextRand(seed);
+    	}
         if (random == null) {
             random = new Random();
         }

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -37,7 +37,6 @@
 import javax.transaction.SystemException;
 import javax.transaction.xa.Xid;
 
-import org.teiid.connector.api.CacheScope;
 import org.teiid.dqp.internal.cache.CacheID;
 import org.teiid.dqp.internal.cache.DQPContextCache;
 import org.teiid.dqp.internal.cache.ResultSetCache;
@@ -426,8 +425,6 @@
         } catch (Exception e) {
             LogManager.logWarning(LogConstants.CTX_DQP, e, "Failed to remove buffered tuples for connection " + sessionId); //$NON-NLS-1$
         }
-        // cleanup the prepared plan cache
-        this.prepPlanCache.clear(sessionId);
         
         if (transactionService != null) {
             try {

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/MetaDataProcessor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/MetaDataProcessor.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/MetaDataProcessor.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -29,6 +29,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.teiid.dqp.internal.process.PreparedPlanCache.CacheID;
 import org.teiid.dqp.internal.process.multisource.MultiSourceMetadataWrapper;
 
 import com.metamatrix.api.exception.MetaMatrixComponentException;
@@ -133,7 +134,7 @@
         	RequestWorkItem workItem = requestManager.getRequestWorkItem(requestID);
             return getMetadataForCommand(workItem.getOriginalCommand());
         } 
-        return obtainMetadataForPreparedSql(preparedSql, workContext.getConnectionID(), allowDoubleQuotedVariable);
+        return obtainMetadataForPreparedSql(preparedSql, workContext, allowDoubleQuotedVariable);
     }
     
     // For each projected symbol, construct a metadata map
@@ -204,17 +205,18 @@
         return columnMetadata;
     }
 
-    private MetadataResult obtainMetadataForPreparedSql(String sql, String sessionId, boolean isDoubleQuotedVariablesAllowed) throws QueryParserException, QueryResolverException, MetaMatrixComponentException {
+    private MetadataResult obtainMetadataForPreparedSql(String sql, DQPWorkContext workContext, boolean isDoubleQuotedVariablesAllowed) throws QueryParserException, QueryResolverException, MetaMatrixComponentException {
         Command command = null;
         
-        PreparedPlanCache.PreparedPlan plan = planCache.getPreparedPlan(sessionId, sql);
+        ParseInfo info = new ParseInfo();
+        // Defect 19747 - the parser needs the following connection property to decide whether to treat double-quoted strings as variable names
+        info.allowDoubleQuotedVariable = isDoubleQuotedVariablesAllowed;
+        CacheID id = new PreparedPlanCache.CacheID(workContext, info, sql);
+        PreparedPlanCache.PreparedPlan plan = planCache.getPreparedPlan(id);
         if(plan != null) {
             command = plan.getCommand();
         } else {
             QueryParser parser = QueryParser.getQueryParser();
-            ParseInfo info = new ParseInfo();
-            // Defect 19747 - the parser needs the following connection property to decide whether to treat double-quoted strings as variable names
-            info.allowDoubleQuotedVariable = isDoubleQuotedVariablesAllowed;
             command = parser.parseCommand(sql, info);
             QueryResolver.resolveCommand(command, Collections.EMPTY_MAP, false, this.metadata, AnalysisRecord.createNonRecordingRecord());                        
         }

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedPlanCache.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedPlanCache.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedPlanCache.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -22,15 +22,18 @@
 
 package org.teiid.dqp.internal.process;
 
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
-import com.metamatrix.core.util.ArgCheck;
 import com.metamatrix.core.util.HashCodeUtil;
 import com.metamatrix.core.util.LRUCache;
 import com.metamatrix.query.analysis.AnalysisRecord;
+import com.metamatrix.query.parser.ParseInfo;
 import com.metamatrix.query.processor.ProcessorPlan;
 import com.metamatrix.query.sql.lang.Command;
 import com.metamatrix.query.sql.symbol.Reference;
+import com.metamatrix.vdb.runtime.VDBKey;
 
 /**
  * This class is used to cahce plan and related objects for prepared statement
@@ -38,7 +41,8 @@
 public class PreparedPlanCache {
 	public static final int DEFAULT_MAX_SIZE_TOTAL = 100;
 
-	private LRUCache<CacheID, PreparedPlan> cache;
+	private Map<CacheID, PreparedPlan> cache;
+	private int maxSize;
 	
 	PreparedPlanCache(){
 		this(DEFAULT_MAX_SIZE_TOTAL);
@@ -48,7 +52,8 @@
 		if(maxSize < 0){
 			maxSize = DEFAULT_MAX_SIZE_TOTAL;
 		}
-		cache = new LRUCache<CacheID, PreparedPlan>(maxSize);
+		this.maxSize = maxSize;
+		cache = Collections.synchronizedMap(new LRUCache<CacheID, PreparedPlan>(maxSize));
 	}	
 	
 	/**
@@ -57,71 +62,65 @@
 	 * @param session ClientConnection
 	 * @return PreparedPlan for the given clientConn and SQl query. Null if not exist.
 	 */
-	public synchronized PreparedPlan getPreparedPlan(String sessionId, String sql){
-		ArgCheck.isNotNull(sessionId);
-		ArgCheck.isNotNull(sql);
-		
-		CacheID cID = new CacheID(sessionId, sql);
-		
-		return cache.get(cID);
+	public PreparedPlan getPreparedPlan(CacheID id){
+		id.setSessionId(id.originalSessionId);
+		PreparedPlan result = cache.get(id);
+		if (result == null) {
+			id.setSessionId(null);
+		}
+		return cache.get(id);
 	}
 	
 	/**
 	 * Create PreparedPlan for the given clientConn and SQl query
 	 */
-	public synchronized PreparedPlan createPreparedPlan(String sessionId, String sql){
-		ArgCheck.isNotNull(sessionId);
-		ArgCheck.isNotNull(sql);
-		
-		CacheID cID = new CacheID(sessionId, sql);
-		PreparedPlan preparedPlan = cache.get(cID);
-		if(preparedPlan == null){
-			preparedPlan = new PreparedPlan();
-			cache.put(cID, preparedPlan);
+	public void putPreparedPlan(CacheID id, boolean sessionSpecific, PreparedPlan plan){
+		if (sessionSpecific) {
+			id.setSessionId(id.originalSessionId);
+		} else {
+			id.setSessionId(null);
 		}
-		return preparedPlan;
+		this.cache.put(id, plan);
 	}
 	
 	/**
-	 * Clear the cahced plans for the given clientConn
+	 * Clear all the cached plans for all the clientConns
 	 * @param clientConn ClientConnection
 	 */
-	public synchronized void clear(String sessionId){
-		ArgCheck.isNotNull(sessionId);
-		//do not do anything
-	}
-
-	/**
-	 * Clear all the cahced plans for all the clientConns
-	 * @param clientConn ClientConnection
-	 */
-	public synchronized void clearAll(){
+	public void clearAll(){
 		cache.clear();
 	}	
 	
 	static class CacheID{
-		private String sessionId;
 		private String sql;
-		int hashCode;
-		private boolean isPreparedBatchUpdate;
-		
-		CacheID(String sessionId, String sql){
-			this.sessionId = sessionId;
+		private VDBKey vdbInfo;
+		private ParseInfo pi;
+		private String sessionId;
+		private String originalSessionId;
+		private int hashCode;
+				
+		CacheID(DQPWorkContext context, ParseInfo pi, String sql){
 			this.sql = sql;
-			hashCode = HashCodeUtil.hashCode(HashCodeUtil.hashCode(0, sessionId), sql);
+			this.vdbInfo = new VDBKey(context.getVdbName(), context.getVdbVersion());
+			this.pi = pi;
+			this.originalSessionId = context.getConnectionID();
 		}
 		
+		private void setSessionId(String sessionId) {
+			this.sessionId = sessionId;
+			hashCode = HashCodeUtil.hashCode(HashCodeUtil.hashCode(HashCodeUtil.hashCode(HashCodeUtil.hashCode(0, vdbInfo), sql), pi), sessionId);
+		}
+						
 		public boolean equals(Object obj){
 	        if(obj == this) {
 	            return true;
-	        } else if(obj == null || ! (obj instanceof CacheID)) {
+	        } 
+	        if(! (obj instanceof CacheID)) {
 	            return false;
-	        } else {
-	        	CacheID that = (CacheID)obj;
-	            return this.sessionId.equals(that.sessionId)
-	            && this.isPreparedBatchUpdate == that.isPreparedBatchUpdate
-					&& this.sql.equals(that.sql);
-			}
+	        } 
+        	CacheID that = (CacheID)obj;
+            return this.pi.equals(that.pi) && this.vdbInfo.equals(that.vdbInfo) && this.sql.equals(that.sql) 
+            	&& ((this.sessionId == null && that.sessionId == null) || this.sessionId.equals(that.sessionId));
 		}
 		
 	    public int hashCode() {
@@ -207,7 +206,7 @@
 		return cache.size();
 	}
     int getSpaceAllowed() {
-        return cache.getSpaceLimit();
+        return maxSize;
     }
     
 }

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedStatementRequest.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedStatementRequest.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedStatementRequest.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -26,6 +26,8 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.teiid.dqp.internal.process.PreparedPlanCache.CacheID;
+
 import com.metamatrix.api.exception.MetaMatrixComponentException;
 import com.metamatrix.api.exception.query.ExpressionEvaluationException;
 import com.metamatrix.api.exception.query.QueryMetadataException;
@@ -138,12 +140,12 @@
      * @see org.teiid.dqp.internal.process.Request#generatePlan()
      */
     protected Command generatePlan() throws QueryPlannerException, QueryParserException, QueryResolverException, QueryValidatorException, MetaMatrixComponentException {
-    	
     	String sqlQuery = requestMsg.getCommands()[0];
-        prepPlan = prepPlanCache.getPreparedPlan(this.workContext.getConnectionID(), sqlQuery);
+    	CacheID id = new PreparedPlanCache.CacheID(this.workContext, Request.createParseInfo(this.requestMsg), sqlQuery);
+        prepPlan = prepPlanCache.getPreparedPlan(id);
         if (prepPlan == null) {
             //if prepared plan does not exist, create one
-            prepPlan = prepPlanCache.createPreparedPlan(this.workContext.getConnectionID(), sqlQuery);
+            prepPlan = new PreparedPlanCache.PreparedPlan();
             LogManager.logTrace(LogConstants.CTX_DQP, new Object[] { "Query does not exist in cache: ", sqlQuery}); //$NON-NLS-1$
         }
 
@@ -153,10 +155,11 @@
         if (cachedPlan == null) {
         	prepPlan.setRewritenCommand(super.generatePlan());
         	
-        	if (!this.addedLimit) { //TODO: this is a little problematic 
+        	if (!this.addedLimit) { //TODO: this is a little problematic
 		        // Defect 13751: Clone the plan in its current state (i.e. before processing) so that it can be used for later queries
 		        prepPlan.setPlan((ProcessorPlan)processPlan.clone());
 		        prepPlan.setAnalysisRecord(analysisRecord);
+		        this.prepPlanCache.putPreparedPlan(id, this.context.isSessionFunctionEvaluated(), prepPlan);
         	}
         	command = prepPlan.getCommand();
         } else {

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/Request.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/Request.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/Request.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -335,8 +335,7 @@
 
     private Command parseCommand() throws QueryParserException {
         String[] commands = requestMsg.getCommands();
-        ParseInfo parseInfo = new ParseInfo();
-    	parseInfo.allowDoubleQuotedVariable = requestMsg.isDoubleQuotedVariableAllowed();
+        ParseInfo parseInfo = createParseInfo(this.requestMsg);
         if (!requestMsg.isBatchedUpdate()) {
         	String commandStr = commands[0];
             return QueryParser.getQueryParser().parseCommand(commandStr, parseInfo);
@@ -349,6 +348,12 @@
         return new BatchedUpdateCommand(parsedCommands);
     }
 
+	public static ParseInfo createParseInfo(RequestMessage requestMsg) {
+		ParseInfo parseInfo = new ParseInfo();
+    	parseInfo.allowDoubleQuotedVariable = requestMsg.isDoubleQuotedVariableAllowed();
+		return parseInfo;
+	}
+
     public static void validateWithVisitor(
         AbstractValidationVisitor visitor,
         QueryMetadataInterface metadata,

Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestAccessNode.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestAccessNode.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestAccessNode.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -31,6 +31,7 @@
 import com.metamatrix.common.buffer.TupleSource;
 import com.metamatrix.query.parser.QueryParser;
 import com.metamatrix.query.processor.ProcessorDataManager;
+import com.metamatrix.query.resolver.TestResolver;
 import com.metamatrix.query.sql.lang.Command;
 import com.metamatrix.query.sql.lang.CompoundCriteria;
 import com.metamatrix.query.sql.lang.IsNullCriteria;
@@ -40,6 +41,7 @@
 import com.metamatrix.query.sql.symbol.Constant;
 import com.metamatrix.query.sql.symbol.ElementSymbol;
 import com.metamatrix.query.sql.symbol.GroupSymbol;
+import com.metamatrix.query.unittest.FakeMetadataFactory;
 import com.metamatrix.query.util.CommandContext;
 
 
@@ -66,7 +68,7 @@
     }
     
     public void testOpen_Defect16059() throws Exception {
-        Query query = (Query)QueryParser.getQueryParser().parseCommand("SELECT e1, e2 FROM pm1.g1 WHERE e2 = 5 AND ? IS NULL"); //$NON-NLS-1$
+    	Query query = (Query)TestResolver.helpResolve("SELECT e1, e2 FROM pm1.g1 WHERE e2 = 5 AND ? IS NULL", FakeMetadataFactory.example1Cached(), null); //$NON-NLS-1$
         IsNullCriteria nullCrit = (IsNullCriteria)((CompoundCriteria)query.getCriteria()).getCriteria(1);
         nullCrit.setExpression(new Constant(null));
         
@@ -74,7 +76,7 @@
     }
     
     public void testOpen_Defect16059_2() throws Exception {
-        Query query = (Query)QueryParser.getQueryParser().parseCommand("SELECT e1, e2 FROM pm1.g1 WHERE e2 = 5 AND ? IS NOT NULL"); //$NON-NLS-1$
+    	Query query = (Query)TestResolver.helpResolve("SELECT e1, e2 FROM pm1.g1 WHERE e2 = 5 AND ? IS NOT NULL", FakeMetadataFactory.example1Cached(), null); //$NON-NLS-1$
         IsNullCriteria nullCrit = (IsNullCriteria)((CompoundCriteria)query.getCriteria()).getCriteria(1);
         nullCrit.setExpression(new Constant(null));
         
@@ -84,7 +86,7 @@
     public void testExecCount()throws Exception{
         // Setup
         AccessNode node = new AccessNode(1);
-        Query query = (Query)QueryParser.getQueryParser().parseCommand("SELECT e1, e2 FROM pm1.g1 WHERE e2 = 5"); //$NON-NLS-1$
+    	Query query = (Query)TestResolver.helpResolve("SELECT e1, e2 FROM pm1.g1 WHERE e2 = 5", FakeMetadataFactory.example1Cached(), null); //$NON-NLS-1$
         node.setCommand(query);
         CommandContext context = new CommandContext();
         context.setProcessorID("processorID"); //$NON-NLS-1$

Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestBatchedUpdateNode.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestBatchedUpdateNode.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/relational/TestBatchedUpdateNode.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -41,7 +41,7 @@
 import com.metamatrix.query.processor.ProcessorDataManager;
 import com.metamatrix.query.sql.lang.BatchedUpdateCommand;
 import com.metamatrix.query.sql.lang.Command;
-import com.metamatrix.query.sql.visitor.NeedsEvaluationVisitor;
+import com.metamatrix.query.sql.visitor.EvaluatableVisitor;
 import com.metamatrix.query.unittest.FakeMetadataFactory;
 import com.metamatrix.query.util.CommandContext;
 
@@ -55,7 +55,7 @@
     	List<Command> commands = TestBatchedUpdatePlanner.helpGetCommands(sql, md);
     	List<Boolean> shouldEvaluate = new ArrayList<Boolean>(commands.size());
     	for (Command command : commands) {
-			shouldEvaluate.add(NeedsEvaluationVisitor.needsEvaluation(command));
+			shouldEvaluate.add(EvaluatableVisitor.needsProcessingEvaluation(command));
 		}
         BatchedUpdateNode node = new BatchedUpdateNode(1, commands, null, shouldEvaluate, "myModelName"); //$NON-NLS-1$
         CommandContext context = new CommandContext();

Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedPlanCache.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedPlanCache.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedPlanCache.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -26,46 +26,56 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import static org.junit.Assert.*;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
 import org.teiid.dqp.internal.process.PreparedPlanCache;
+import org.teiid.dqp.internal.process.PreparedPlanCache.CacheID;
 
-import junit.framework.TestCase;
-
 import com.metamatrix.api.exception.query.QueryParserException;
 import com.metamatrix.query.analysis.AnalysisRecord;
+import com.metamatrix.query.parser.ParseInfo;
 import com.metamatrix.query.parser.QueryParser;
 import com.metamatrix.query.processor.relational.ProjectNode;
 import com.metamatrix.query.processor.relational.RelationalPlan;
 import com.metamatrix.query.sql.lang.Command;
 
-
-public class TestPreparedPlanCache extends TestCase{
+public class TestPreparedPlanCache {
     private static final String EXAMPLE_QUERY = "SELECT * FROM table"; //$NON-NLS-1$
-	private final static String token = "1"; //$NON-NLS-1$
-	private final static  String token2 = "2"; //$NON-NLS-1$
-
-	public TestPreparedPlanCache(String name) {
-        super(name);
-    }
+	private final static DQPWorkContext token = new DQPWorkContext();
+	private final static  DQPWorkContext token2 = new DQPWorkContext();
+	
+	private final static ParseInfo pi = new ParseInfo();
+	
+	@BeforeClass public static void setUpOnce() {
+		token.setVdbName("foo"); //$NON-NLS-1$
+		token.setVdbVersion("1"); //$NON-NLS-1$
+		token2.setVdbName("foo"); //$NON-NLS-1$
+		token2.setVdbVersion("2"); //$NON-NLS-1$
+	}
     
     //====Tests====//
-    public void testCreatePreparedPlan(){
+    @Test public void testPutPreparedPlan(){
     	PreparedPlanCache cache = new PreparedPlanCache();
     	
+    	CacheID id = new PreparedPlanCache.CacheID(token, pi, EXAMPLE_QUERY + 1);
+    	
     	//No PreparedPlan at the begining
-    	assertNull(cache.getPreparedPlan(token, EXAMPLE_QUERY + 1));
+    	assertNull(cache.getPreparedPlan(id));
     	//create one
-    	cache.createPreparedPlan(token, EXAMPLE_QUERY + 1);
+    	cache.putPreparedPlan(id, true, new PreparedPlanCache.PreparedPlan());
     	//should have one now
-    	assertNotNull("Unable to get prepared plan from cache", cache.getPreparedPlan(token, EXAMPLE_QUERY + 1)); //$NON-NLS-1$
+    	assertNotNull("Unable to get prepared plan from cache", cache.getPreparedPlan(id)); //$NON-NLS-1$
     }
     
-    public void testGetPreparedPlan(){
+    @Test public void testGetPreparedPlan(){
     	PreparedPlanCache cache = new PreparedPlanCache();
-    	helpCreatePreparedPlans(cache, token, 0, 10);
-    	helpCreatePreparedPlans(cache, token2, 0, 15);
+    	helpPutPreparedPlans(cache, token, 0, 10);
+    	helpPutPreparedPlans(cache, token2, 0, 15);
     	
     	//read an entry for session2 (token2)
-    	PreparedPlanCache.PreparedPlan pPlan = cache.getPreparedPlan(token2, EXAMPLE_QUERY + 12);
+    	PreparedPlanCache.PreparedPlan pPlan = cache.getPreparedPlan(new PreparedPlanCache.CacheID(token2, pi, EXAMPLE_QUERY + 12));
     	assertNotNull("Unable to get prepared plan from cache", pPlan); //$NON-NLS-1$
     	assertEquals("Error getting plan from cache", new RelationalPlan(new ProjectNode(12)).toString(), pPlan.getPlan().toString()); //$NON-NLS-1$
     	assertEquals("Error getting command from cache", EXAMPLE_QUERY + 12, pPlan.getCommand().toString()); //$NON-NLS-1$
@@ -73,55 +83,55 @@
     	assertEquals("Error gettting reference from cache", "ref12", pPlan.getReferences().get(0)); //$NON-NLS-1$ //$NON-NLS-2$
     }
     
-    public void testClearAll(){
+    @Test public void testClearAll(){
     	PreparedPlanCache cache = new PreparedPlanCache();
     	
     	//create one for each session token
-    	cache.createPreparedPlan(token, EXAMPLE_QUERY + 1);
-    	cache.createPreparedPlan(token2, EXAMPLE_QUERY + 1);
+    	helpPutPreparedPlans(cache, token, 1, 1);
+    	helpPutPreparedPlans(cache, token2, 1, 1);
     	//should have one
-    	assertNotNull("Unable to get prepared plan from cache for token", cache.getPreparedPlan(token, EXAMPLE_QUERY + 1)); //$NON-NLS-1$
+    	assertNotNull("Unable to get prepared plan from cache for token", cache.getPreparedPlan(new PreparedPlanCache.CacheID(token, pi, EXAMPLE_QUERY + 1))); //$NON-NLS-1$
     	cache.clearAll();
     	//should not exist for token
-    	assertNull("Failed remove from cache", cache.getPreparedPlan(token, EXAMPLE_QUERY + 1)); //$NON-NLS-1$ 
+    	assertNull("Failed remove from cache", cache.getPreparedPlan(new PreparedPlanCache.CacheID(token, pi, EXAMPLE_QUERY + 1))); //$NON-NLS-1$ 
     	//should not exist for token2
-    	assertNull("Unable to get prepared plan from cache for token2", cache.getPreparedPlan(token2, EXAMPLE_QUERY + 1)); //$NON-NLS-1$ 
+    	assertNull("Unable to get prepared plan from cache for token2", cache.getPreparedPlan(new PreparedPlanCache.CacheID(token2, pi, EXAMPLE_QUERY + 1))); //$NON-NLS-1$ 
     }
     
-    public void testMaxSize(){
+    @Test public void testMaxSize(){
         PreparedPlanCache cache = new PreparedPlanCache(100);
-        helpCreatePreparedPlans(cache, token, 0, 101);
+        helpPutPreparedPlans(cache, token, 0, 101);
         //the first one should be gone because the max size is 100
-        assertNull(cache.getPreparedPlan(token, EXAMPLE_QUERY + 0)); 
+        assertNull(cache.getPreparedPlan(new PreparedPlanCache.CacheID(token, pi, EXAMPLE_QUERY + 0))); 
         
-        assertNotNull(cache.getPreparedPlan(token, EXAMPLE_QUERY + 12)); 
-        helpCreatePreparedPlans(cache, token, 102, 50);
+        assertNotNull(cache.getPreparedPlan(new PreparedPlanCache.CacheID(token, pi, EXAMPLE_QUERY + 12))); 
+        helpPutPreparedPlans(cache, token, 102, 50);
         //"sql12" should still be there based on lru  policy
-        assertNotNull(cache.getPreparedPlan(token, EXAMPLE_QUERY + 12)); 
+        assertNotNull(cache.getPreparedPlan(new PreparedPlanCache.CacheID(token, pi, EXAMPLE_QUERY + 12))); 
         
-        helpCreatePreparedPlans(cache, token2, 0, 121);
-        helpCreatePreparedPlans(cache, token, 0, 50);
+        helpPutPreparedPlans(cache, token2, 0, 121);
+        helpPutPreparedPlans(cache, token, 0, 50);
         assertTrue(cache.getSpaceUsed() <= 100);
     }
     
-    public void testZeroSizeCache() {
+    @Test public void testZeroSizeCache() {
         // Create with 0 size cache
         PreparedPlanCache cache = new PreparedPlanCache(0);
         assertEquals(0, cache.getSpaceAllowed());
         
         // Add 1 plan and verify it is not in the cache
-        helpCreatePreparedPlans(cache, token, 0, 1);
-        assertNull(cache.getPreparedPlan(token, EXAMPLE_QUERY + 0)); 
+        helpPutPreparedPlans(cache, token, 0, 1);
+        assertNull(cache.getPreparedPlan(new PreparedPlanCache.CacheID(token, pi, EXAMPLE_QUERY + 0))); 
         assertEquals(0, cache.getSpaceUsed());
         
         // Add another plan and verify it is not in the cache
-        helpCreatePreparedPlans(cache, token, 1, 1);
-        assertNull(cache.getPreparedPlan(token, EXAMPLE_QUERY + 1)); 
+        helpPutPreparedPlans(cache, token, 1, 1);
+        assertNull(cache.getPreparedPlan(new PreparedPlanCache.CacheID(token, pi, EXAMPLE_QUERY + 1))); 
         assertEquals(0, cache.getSpaceUsed());        
     }
     
     // set init size to negative number, which should default to 100 (default)
-    public void testNegativeSizeCacheUsesDefault() {
+    @Test public void testNegativeSizeCacheUsesDefault() {
         PreparedPlanCache negativeSizedCache = new PreparedPlanCache(-1000);
         PreparedPlanCache defaultSizedCache = new PreparedPlanCache();
         
@@ -130,15 +140,18 @@
     }
     
     //====Help methods====//
-    private void helpCreatePreparedPlans(PreparedPlanCache cache, String token, int start, int count){
-    	for(int i=start; i<count; i++){
+    private void helpPutPreparedPlans(PreparedPlanCache cache, DQPWorkContext session, int start, int count){
+    	for(int i=0; i<count; i++){
     		Command dummy;
 			try {
-				dummy = QueryParser.getQueryParser().parseCommand(EXAMPLE_QUERY + i); 
+				dummy = QueryParser.getQueryParser().parseCommand(EXAMPLE_QUERY + (start + i)); 
 			} catch (QueryParserException e) {
 				throw new RuntimeException(e);
 			}
-    		PreparedPlanCache.PreparedPlan pPlan = cache.createPreparedPlan(token, dummy.toString());
+	    	CacheID id = new PreparedPlanCache.CacheID(session, pi, dummy.toString());
+
+	    	PreparedPlanCache.PreparedPlan pPlan = new PreparedPlanCache.PreparedPlan();
+    		cache.putPreparedPlan(id, true, pPlan);
     		pPlan.setCommand(dummy); 
     		pPlan.setPlan(new RelationalPlan(new ProjectNode(i)));
             Map props = new HashMap();

Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java	2009-04-20 20:41:11 UTC (rev 807)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java	2009-04-20 21:02:03 UTC (rev 808)
@@ -27,13 +27,10 @@
 import java.util.HashMap;
 import java.util.List;
 
-import org.teiid.dqp.internal.process.DQPWorkContext;
-import org.teiid.dqp.internal.process.PreparedPlanCache;
-import org.teiid.dqp.internal.process.PreparedStatementRequest;
+import junit.framework.TestCase;
+
 import org.teiid.dqp.internal.process.TestRequest.FakeApplicationEnvironment;
 
-import junit.framework.TestCase;
-
 import com.metamatrix.api.exception.MetaMatrixComponentException;
 import com.metamatrix.api.exception.query.QueryParserException;
 import com.metamatrix.api.exception.query.QueryPlannerException;
@@ -52,7 +49,6 @@
 import com.metamatrix.query.optimizer.capabilities.SourceCapabilities.Capability;
 import com.metamatrix.query.processor.FakeDataManager;
 import com.metamatrix.query.processor.ProcessorDataManager;
-import com.metamatrix.query.processor.ProcessorPlan;
 import com.metamatrix.query.processor.TestProcessor;
 import com.metamatrix.query.unittest.FakeMetadataFacade;
 import com.metamatrix.query.unittest.FakeMetadataFactory;
@@ -68,14 +64,14 @@
 		int hitCount;
 		
 		@Override
-		public synchronized PreparedPlan getPreparedPlan(
-				String clientConn, String sql) {
-			PreparedPlan plan = super.getPreparedPlan(clientConn, sql);
-			if (plan != null && plan.getPlan() != null) {
+		public PreparedPlan getPreparedPlan(CacheID id) {
+			PreparedPlan result = super.getPreparedPlan(id);
+			if (result != null) {
 				hitCount++;
 			}
-			return plan;
+			return result;
 		}
+		
 	}
 		
 	public TestPreparedStatement(String name) { 
@@ -89,8 +85,12 @@
 		
         helpTestProcessing(preparedSql, values, expected, dataManager, metadata, callableStatement);
 	}
-		
+	
     static void helpTestProcessing(String preparedSql, List values, List[] expected, ProcessorDataManager dataManager, QueryMetadataInterface metadata, boolean callableStatement) throws Exception { 
+    	helpTestProcessing(preparedSql, values, expected, dataManager, metadata, callableStatement, false);
+    }
+
+    static void helpTestProcessing(String preparedSql, List values, List[] expected, ProcessorDataManager dataManager, QueryMetadataInterface metadata, boolean callableStatement, boolean differentPlan) throws Exception { 
         TestablePreparedPlanCache prepPlan = new TestablePreparedPlanCache();
         //Create plan
         PreparedStatementRequest plan = TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, new DefaultCapabilitiesFinder(), metadata, prepPlan, SESSION_ID, callableStatement, false);
@@ -110,7 +110,7 @@
         //get the plan again with a new connection
         assertNotNull(TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, new DefaultCapabilitiesFinder(), metadata, prepPlan, 7, callableStatement, false));
 
-        assertEquals("new connection should not have used the same plan", 1, prepPlan.hitCount); //$NON-NLS-1$
+        assertEquals(differentPlan?1:2, prepPlan.hitCount); 
 	}
     	    
     public void testWhere() throws Exception { 
@@ -129,6 +129,23 @@
 		helpTestProcessing(preparedSql, values, expected, FakeMetadataFactory.example1Cached(), false);
 	}
     
+    public void testSessionSpecificFunction() throws Exception { 
+        // Create query 
+        String preparedSql = "SELECT user(), e2, pm1.g1.e3 as a, e4 as b FROM pm1.g1 WHERE e2=?"; //$NON-NLS-1$
+        
+        // Create expected results
+        List[] expected = new List[] { 
+            Arrays.asList(new Object[] { "foo",   new Integer(0),     Boolean.FALSE,  new Double(2.0) }), //$NON-NLS-1$
+            Arrays.asList(new Object[] { "foo",   new Integer(0),     Boolean.FALSE,  new Double(2.0) }) //$NON-NLS-1$
+        };    
+    
+		List values = new ArrayList();
+		values.add(new Short((short)0));
+        FakeDataManager dataManager = new FakeDataManager();
+        TestProcessor.sampleData1(dataManager);
+		helpTestProcessing(preparedSql, values, expected, dataManager, FakeMetadataFactory.example1Cached(), false, true);
+	}
+    
     public void testFunctionWithReferencePushDown() throws Exception { 
         // Create query 
         String preparedSql = "SELECT pm1.g1.e1 FROM pm1.g1, pm1.g2 WHERE pm1.g1.e1 = pm1.g2.e1 and pm1.g1.e2+2=?"; //$NON-NLS-1$




More information about the teiid-commits mailing list