[teiid-commits] teiid SVN: r1699 - in trunk/engine/src: main/java/com/metamatrix/query/processor and 12 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Wed Dec 23 10:14:01 EST 2009


Author: shawkins
Date: 2009-12-23 10:14:00 -0500 (Wed, 23 Dec 2009)
New Revision: 1699

Removed:
   trunk/engine/src/main/java/com/metamatrix/query/processor/BaseProcessorPlan.java
Modified:
   trunk/engine/src/main/java/com/metamatrix/query/optimizer/batch/BatchedUpdatePlanner.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/ProcessorPlan.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/batch/BatchedUpdatePlan.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/proc/ProcedurePlan.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/relational/RelationalPlan.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/xml/XMLPlan.java
   trunk/engine/src/main/java/com/metamatrix/query/processor/xquery/XQueryPlan.java
   trunk/engine/src/main/java/com/metamatrix/query/sql/util/VariableContext.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedStatementRequest.java
   trunk/engine/src/test/java/com/metamatrix/query/optimizer/batch/TestBatchedUpdatePlanner.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/FakeDataManager.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/FakeProcessorPlan.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/TestBaseProcessorPlan.java
   trunk/engine/src/test/java/com/metamatrix/query/processor/batch/TestBatchedUpdatePlan.java
   trunk/engine/src/test/java/com/metamatrix/query/unittest/FakeMetadataFactory.java
   trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDataTierManager.java
   trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java
   trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatementBatchedUpdate.java
Log:
TEIID-911 fix for virtual bulk updates.  the variablecontext was not being used by BatchedUpdatePlan

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-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/com/metamatrix/query/optimizer/batch/BatchedUpdatePlanner.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -96,6 +96,10 @@
         List updateCommands = batchedUpdateCommand.getUpdateCommands();
         int numCommands = updateCommands.size();
         List<VariableContext> allContexts = batchedUpdateCommand.getVariableContexts();
+        List<VariableContext> planContexts = null;
+        if (allContexts != null) {
+        	planContexts = new ArrayList<VariableContext>(allContexts.size());
+        }
         for (int commandIndex = 0; commandIndex < numCommands; commandIndex++) {
             // Potentially the first command of a batch
             Command updateCommand = (Command)updateCommands.get(commandIndex);
@@ -153,6 +157,9 @@
                         projectNode.addChild(batchNode);
                         // Add a new RelationalPlan that represents the plan for this batch.
                         childPlans.add(new RelationalPlan(projectNode));
+                        if (planContexts != null) {
+                        	planContexts.add(new VariableContext());
+                    	}
                         // Skip those commands that were added to this batch
                         commandIndex += batch.size() - 1;
                         commandWasBatched = true;
@@ -166,9 +173,12 @@
             		plan = QueryOptimizer.optimizePlan(cmd, metadata, idGenerator, capFinder, analysisRecord, context);
             	}
                 childPlans.add(plan);
+                if (allContexts != null) {
+                	planContexts.add(allContexts.get(commandIndex));
+                }
             }
         }
-        return new BatchedUpdatePlan(childPlans, batchedUpdateCommand.getUpdateCommands().size());
+        return new BatchedUpdatePlan(childPlans, batchedUpdateCommand.getUpdateCommands().size(), planContexts);
     }
     
     /**

Deleted: trunk/engine/src/main/java/com/metamatrix/query/processor/BaseProcessorPlan.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/BaseProcessorPlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/BaseProcessorPlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -1,85 +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.processor;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.metamatrix.api.exception.MetaMatrixException;
-import com.metamatrix.query.util.CommandContext;
-
-/**
- */
-public abstract class BaseProcessorPlan implements ProcessorPlan{
-
-    private List warnings = null;
-    
-    private CommandContext context;
-
-    /**
-     * Constructor for BaseProcessorPlan.
-     */
-    public BaseProcessorPlan() {
-        super();
-    }
-
-    /**
-     * @see com.metamatrix.query.processor.ProcessorPlan#getAndClearWarnings()
-     */
-    public List getAndClearWarnings() {
-        if (warnings == null) {
-            return null;
-        }
-        List copied = warnings;
-        warnings = null;
-        return copied;
-    }
-
-    protected void addWarning(MetaMatrixException warning) {
-        if (warnings == null) {
-            warnings = new ArrayList(1);
-        }
-        warnings.add(warning);
-    }
-
-    /**
-     * @return
-     */
-    public CommandContext getContext() {
-        return context;
-    }
-
-    /**
-     * @param context
-     */
-    public void setContext(CommandContext context) {
-        this.context = context;
-    }
-
-    public void reset() {
-        warnings = null;
-    }       
-
-	public abstract Object clone();
-
-}

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/ProcessorPlan.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/ProcessorPlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/ProcessorPlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -22,10 +22,12 @@
 
 package com.metamatrix.query.processor;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
 import com.metamatrix.api.exception.MetaMatrixComponentException;
+import com.metamatrix.api.exception.MetaMatrixException;
 import com.metamatrix.api.exception.MetaMatrixProcessingException;
 import com.metamatrix.common.buffer.*;
 import com.metamatrix.query.processor.BatchCollector.BatchProducer;
@@ -44,7 +46,11 @@
  * the call to {@link #close}.
  * </p>
  */
-public interface ProcessorPlan extends Cloneable, Describable, BatchProducer {
+public abstract class ProcessorPlan implements Cloneable, Describable, BatchProducer {
+	
+    private List warnings = null;
+    
+    private CommandContext context;
 
 	/**
 	 * Initialize the plan with some required pieces of data for making 
@@ -56,7 +62,7 @@
 	 * @param dataMgr Data manager reference
      * @param bufferMgr Buffer manager reference
 	 */
-	void initialize(CommandContext context, ProcessorDataManager dataMgr, BufferManager bufferMgr);
+	public abstract void initialize(CommandContext context, ProcessorDataManager dataMgr, BufferManager bufferMgr);
 	
     /**
      * Get all warnings found while processing this plan.  These warnings may
@@ -65,30 +71,52 @@
      * the current warnings list.  The warnings are in order they were detected.
      * @return Current list of warnings, never null
      */
-    List<Exception> getAndClearWarnings();
+    public List getAndClearWarnings() {
+        if (warnings == null) {
+            return null;
+        }
+        List copied = warnings;
+        warnings = null;
+        return copied;
+    }
     
+    protected void addWarning(MetaMatrixException warning) {
+        if (warnings == null) {
+            warnings = new ArrayList(1);
+        }
+        warnings.add(warning);
+    }
+
     /**
      * Reset a plan so that it can be processed again.
      */
-    void reset();
+    public void reset() {
+    	this.warnings = null;
+    }
     
     /**
      * Get list of resolved elements describing output columns for this plan.
      * @return List of SingleElementSymbol
      */
-    List getOutputElements();
+    public abstract List getOutputElements();
     
     /**
      * Get the processor context, which can be modified.
      * @return context object
      */
-    CommandContext getContext();
+    public CommandContext getContext() {
+        return context;
+    }
     
+    public void setContext(CommandContext context) {
+		this.context = context;
+	}
+    
     /**
      * Open the plan for processing.
      * @throws MetaMatrixComponentException
      */
-    void open() throws MetaMatrixComponentException, MetaMatrixProcessingException;
+    public abstract void open() throws MetaMatrixComponentException, MetaMatrixProcessingException;
     
     /**
      * Get a batch of results or possibly an Exception.
@@ -98,15 +126,14 @@
      * @throws MetaMatrixProcessingException for business rule exception, related
      * to user input or modeling
      */
-    TupleBatch nextBatch() throws BlockedException, MetaMatrixComponentException, MetaMatrixProcessingException;
+    public abstract TupleBatch nextBatch() throws BlockedException, MetaMatrixComponentException, MetaMatrixProcessingException;
 
     /**
      * Close the plan after processing.
      * @throws MetaMatrixComponentException
      */
-    void close() throws MetaMatrixComponentException;
+    public abstract void close() throws MetaMatrixComponentException;
     
-	
 	/**
 	 * Return a safe clone of the ProcessorPlan.  A ProcessorPlan may only be
 	 * safely cloned in between processings.  That is, it is only safe to clone
@@ -115,12 +142,12 @@
 	 * @return safe clone of this ProcessorPlan, as long as it is not open for
 	 * processing
 	 */
-	Object clone();
+	public abstract ProcessorPlan clone();
     
     /**
      * Finds all nested plans and returns them.
      * @return List of ProcessorPlan 
      * @since 4.2
      */
-    Collection getChildPlans();
+    public abstract Collection getChildPlans();
 }

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/batch/BatchedUpdatePlan.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/batch/BatchedUpdatePlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/batch/BatchedUpdatePlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -34,20 +34,23 @@
 import com.metamatrix.common.buffer.BlockedException;
 import com.metamatrix.common.buffer.BufferManager;
 import com.metamatrix.common.buffer.TupleBatch;
-import com.metamatrix.query.processor.BaseProcessorPlan;
 import com.metamatrix.query.processor.DescribableUtil;
 import com.metamatrix.query.processor.ProcessorDataManager;
 import com.metamatrix.query.processor.ProcessorPlan;
 import com.metamatrix.query.sql.lang.Command;
+import com.metamatrix.query.sql.util.VariableContext;
 import com.metamatrix.query.util.CommandContext;
 
 
 /** 
  * Plan for execution for a batched update command. The plan executes the child plans of the
  * individual commands in order.
+ * 
+ * If variableContexts are provided, then this is a bulk update where all plans are the same object.
+ * 
  * @since 4.2
  */
-public class BatchedUpdatePlan extends BaseProcessorPlan {
+public class BatchedUpdatePlan extends ProcessorPlan {
     
     /** Array that holds the child update plans */
     private ProcessorPlan[] updatePlans;
@@ -60,6 +63,8 @@
     /** The position of the command for which the update count is being retrieved */
     private int commandIndex = 0;
     
+    private List<VariableContext> contexts; //only set for bulk updates
+    
     /**
      *  
      * @param childPlans the child update plans for this batch
@@ -67,22 +72,29 @@
      * commands have been batched together.
      * @since 4.2
      */
-    public BatchedUpdatePlan(List childPlans, int commandsInBatch) {
+    public BatchedUpdatePlan(List childPlans, int commandsInBatch, List<VariableContext> contexts) {
         this.updatePlans = (ProcessorPlan[])childPlans.toArray(new ProcessorPlan[childPlans.size()]);
         this.planOpened = new boolean[updatePlans.length];
         this.updateCounts = new List[commandsInBatch];
+        this.contexts = contexts;
     }
 
     /** 
      * @see java.lang.Object#clone()
      * @since 4.2
      */
-    public Object clone() {
-        List clonedPlans = new ArrayList(updatePlans.length);
-        for (int i = 0; i < updatePlans.length; i++) {
-            clonedPlans.add(updatePlans[i].clone());
+    public BatchedUpdatePlan clone() {
+        List<ProcessorPlan> clonedPlans = new ArrayList<ProcessorPlan>(updatePlans.length);
+        
+        clonedPlans.add((ProcessorPlan)updatePlans[0].clone());
+        for (int i = 1; i <updatePlans.length; i++) {
+        	if (contexts == null) {
+                clonedPlans.add((ProcessorPlan)updatePlans[1].clone());        		
+        	} else {
+        		clonedPlans.add(clonedPlans.get(0));
+        	}
         }
-        return new BatchedUpdatePlan(clonedPlans, updateCounts.length);
+        return new BatchedUpdatePlan(clonedPlans, updateCounts.length, contexts);
     }
 
     /** 
@@ -90,8 +102,11 @@
      * @since 4.2
      */
     public void initialize(CommandContext context, ProcessorDataManager dataMgr, BufferManager bufferMgr) {
+    	context = (CommandContext)context.clone();
+    	context.setVariableContext(new VariableContext()); //start a new root variable context
+    	this.setContext(context);
         // Initialize all the child plans
-        for (int i = 0; i < updatePlans.length; i++) {
+        for (int i = 0; i < getPlanCount(); i++) {
             updatePlans[i].initialize(context, dataMgr, bufferMgr);
         }
     }
@@ -111,8 +126,7 @@
     public void open() throws MetaMatrixComponentException, MetaMatrixProcessingException {
         // It's ok to open() the first plan, as it is not dependent on any prior commands.
         // See note for defect 16166 in the nextBatch() method.
-        updatePlans[0].open();
-        planOpened[0] = true;
+       openPlan();
     }
 
     /** 
@@ -130,8 +144,7 @@
                  * guarantee that the commands in the previous plan are completed before the commands in any subsequent
                  * plans are executed.
                  */
-                updatePlans[planIndex].open();
-                planOpened[planIndex] = true;
+            	openPlan();
             }
             // Execute nextBatch() on each plan in sequence
             List[] currentBatch = updatePlans[planIndex].nextBatch().getAllTuples(); // Can throw BlockedException
@@ -148,6 +161,19 @@
         return batch;
     }
 
+	private void openPlan() throws MetaMatrixComponentException,
+			MetaMatrixProcessingException {
+		if (this.contexts != null && !this.contexts.isEmpty()) {
+			CommandContext context = updatePlans[planIndex].getContext();
+			context.getVariableContext().clear();
+			VariableContext currentValues = this.contexts.get(planIndex);
+			context.getVariableContext().putAll(currentValues); 
+		}
+		updatePlans[planIndex].reset();
+		updatePlans[planIndex].open();
+		planOpened[planIndex] = true;
+	}
+
     /** 
      * @see com.metamatrix.query.processor.ProcessorPlan#close()
      * @since 4.2
@@ -185,7 +211,7 @@
         Map props = new HashMap();
         props.put(PROP_TYPE, "Batched Update Plan"); //$NON-NLS-1$
         List children = new ArrayList();
-        for (int i = 0; i < updatePlans.length; i++) {
+        for (int i = 0; i < getPlanCount(); i++) {
             children.add(updatePlans[i].getDescriptionProperties());
         }
         props.put(PROP_CHILDREN, children);
@@ -195,7 +221,7 @@
     
     public String toString() {
         StringBuffer val = new StringBuffer("BatchedUpdatePlan {\n"); //$NON-NLS-1$
-        for (int i = 0; i < updatePlans.length; i++) {
+        for (int i = 0; i < getPlanCount(); i++) {
             val.append(updatePlans[i])
                .append("\n"); //$NON-NLS-1$
         }
@@ -203,6 +229,10 @@
         return val.toString();
     }
 
+	private int getPlanCount() {
+		return (contexts != null?1:updatePlans.length);
+	}
+
     /**
      * Returns the child plans for this batch. Used primarily for unit tests. 
      * @return

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/proc/ProcedurePlan.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/proc/ProcedurePlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/proc/ProcedurePlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -47,7 +47,6 @@
 import com.metamatrix.query.execution.QueryExecPlugin;
 import com.metamatrix.query.metadata.QueryMetadataInterface;
 import com.metamatrix.query.metadata.SupportConstants;
-import com.metamatrix.query.processor.BaseProcessorPlan;
 import com.metamatrix.query.processor.BatchIterator;
 import com.metamatrix.query.processor.CollectionTupleSource;
 import com.metamatrix.query.processor.DescribableUtil;
@@ -71,7 +70,7 @@
 import com.metamatrix.query.util.ErrorMessageKeys;
 /**
  */
-public class ProcedurePlan extends BaseProcessorPlan {
+public class ProcedurePlan extends ProcessorPlan {
 
 	public static class CursorState {
 		private QueryProcessor processor;
@@ -320,7 +319,7 @@
         return "ProcedurePlan:\n" + ProgramUtil.programToString(this.originalProgram); //$NON-NLS-1$
     }
 
-	public Object clone(){
+	public ProcessorPlan clone(){
         ProcedurePlan plan = new ProcedurePlan((Program)originalProgram.clone());
         plan.setUpdateProcedure(this.isUpdateProcedure());
         plan.setOutputElements(this.getOutputElements());

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/relational/RelationalPlan.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/relational/RelationalPlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/relational/RelationalPlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -35,7 +35,6 @@
 import com.metamatrix.common.buffer.BufferManager;
 import com.metamatrix.common.buffer.TupleBatch;
 import com.metamatrix.common.log.LogManager;
-import com.metamatrix.query.processor.BaseProcessorPlan;
 import com.metamatrix.query.processor.DescribableUtil;
 import com.metamatrix.query.processor.ProcessorDataManager;
 import com.metamatrix.query.processor.ProcessorPlan;
@@ -44,7 +43,7 @@
 
 /**
  */
-public class RelationalPlan extends BaseProcessorPlan {
+public class RelationalPlan extends ProcessorPlan {
 
 	// Initialize state - don't reset
 	private RelationalNode root;
@@ -130,7 +129,7 @@
 		return this.root.toString();    
 	}
     
-	public Object clone(){
+	public RelationalPlan clone(){
 		RelationalPlan plan = new RelationalPlan((RelationalNode)root.clone());
 		plan.setOutputElements(new ArrayList(( outputCols != null ? outputCols : Collections.EMPTY_LIST )));
 		return plan;

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/xml/XMLPlan.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/xml/XMLPlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/xml/XMLPlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -73,7 +73,6 @@
 import com.metamatrix.common.types.XMLType;
 import com.metamatrix.core.util.Assertion;
 import com.metamatrix.query.execution.QueryExecPlugin;
-import com.metamatrix.query.processor.BaseProcessorPlan;
 import com.metamatrix.query.processor.DescribableUtil;
 import com.metamatrix.query.processor.ProcessorDataManager;
 import com.metamatrix.query.processor.ProcessorPlan;
@@ -89,7 +88,7 @@
 /**
  * 
  */
-public class XMLPlan extends BaseProcessorPlan {
+public class XMLPlan extends ProcessorPlan {
 	
 	// State passed during construction
 	private XMLProcessorEnvironment env;
@@ -645,7 +644,7 @@
  	 * in other words, it's only safe to call clone() on a plan after nextTuple() returns null,
  	 * meaning the plan has finished processing.
  	 */
-	public Object clone(){
+	public XMLPlan clone(){
         XMLPlan xmlPlan = new XMLPlan((XMLProcessorEnvironment)this.env.clone());
         return xmlPlan;
     }

Modified: trunk/engine/src/main/java/com/metamatrix/query/processor/xquery/XQueryPlan.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/processor/xquery/XQueryPlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/com/metamatrix/query/processor/xquery/XQueryPlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -40,9 +40,9 @@
 import com.metamatrix.common.types.DataTypeManager;
 import com.metamatrix.common.types.Streamable;
 import com.metamatrix.common.types.XMLType;
-import com.metamatrix.query.processor.BaseProcessorPlan;
 import com.metamatrix.query.processor.DescribableUtil;
 import com.metamatrix.query.processor.ProcessorDataManager;
+import com.metamatrix.query.processor.ProcessorPlan;
 import com.metamatrix.query.processor.dynamic.SqlEval;
 import com.metamatrix.query.processor.xml.XMLUtil;
 import com.metamatrix.query.sql.lang.XQuery;
@@ -54,7 +54,7 @@
 /**
  * XQuery execution Plan
  */
-public class XQueryPlan extends BaseProcessorPlan {        
+public class XQueryPlan extends ProcessorPlan {        
     private XQuery xQuery;
     private BufferManager bufferMgr;
     private String xmlFormat;
@@ -76,7 +76,7 @@
     /**
      * @see java.lang.Object#clone()
      */
-    public Object clone() {
+    public XQueryPlan clone() {
         XQuery clonedQuery = (XQuery)this.xQuery.clone();
         return new XQueryPlan(clonedQuery);
     }

Modified: trunk/engine/src/main/java/com/metamatrix/query/sql/util/VariableContext.java
===================================================================
--- trunk/engine/src/main/java/com/metamatrix/query/sql/util/VariableContext.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/com/metamatrix/query/sql/util/VariableContext.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -177,4 +177,12 @@
     	return this.variableMap.toString();
     }
     
+    public void clear() {
+    	this.variableMap.clear();
+    }
+    
+    public void putAll(VariableContext other) {
+    	this.variableMap.putAll(other.variableMap);
+    }
+    
 }

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-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/PreparedStatementRequest.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -191,11 +191,13 @@
 			throw new QueryValidatorException("No batch values sent for prepared batch update"); //$NON-NLS-1$
 		}
 		boolean supportPreparedBatchUpdate = false;
+		Command command = null;
 		if (this.processPlan instanceof RelationalPlan) {
 			RelationalPlan rPlan = (RelationalPlan)this.processPlan;
 			if (rPlan.getRootNode() instanceof AccessNode) {
 				AccessNode aNode = (AccessNode)rPlan.getRootNode();
 				String modelName = aNode.getModelName();
+				command = aNode.getCommand();
 		        SourceCapabilities caps = capabilitiesFinder.findCapabilities(modelName);
 		        supportPreparedBatchUpdate = caps.supportsCapability(SourceCapabilities.Capability.BULK_UPDATE);
 			}
@@ -216,11 +218,13 @@
 					List<Object> multiValue = multiValues.get(i);
 					multiValue.add(values.get(i));
 				}
-				continue; 
+			} else { //just accumulate copies of the command/plan - clones are not necessary
+				if (command == null) {
+					command = this.prepPlan.getCommand();
+					command.setProcessorPlan(this.processPlan);
+				}
+				commands.add(command);
 			}
-			Command c = (Command)this.prepPlan.getCommand().clone();
-			commands.add(c);
-			c.setProcessorPlan((ProcessorPlan)this.processPlan.clone());
 		}
 		
 		if (paramValues.size() > 1) {

Modified: trunk/engine/src/test/java/com/metamatrix/query/optimizer/batch/TestBatchedUpdatePlanner.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/optimizer/batch/TestBatchedUpdatePlanner.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/test/java/com/metamatrix/query/optimizer/batch/TestBatchedUpdatePlanner.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -67,9 +67,9 @@
         super(name);
     }
     
-    public static List helpGetCommands(String[] sql, QueryMetadataInterface md) throws QueryParserException, QueryResolverException, MetaMatrixComponentException, QueryValidatorException  { 
+    public static List<Command> helpGetCommands(String[] sql, QueryMetadataInterface md) throws QueryParserException, QueryResolverException, MetaMatrixComponentException, QueryValidatorException  { 
         if(DEBUG) System.out.println("\n####################################\n" + sql);  //$NON-NLS-1$
-        List commands = new ArrayList(sql.length);
+        List<Command> commands = new ArrayList<Command>(sql.length);
         for (int i = 0; i < sql.length; i++) {
             Command command = QueryParser.getQueryParser().parseCommand(sql[i]);
             QueryResolver.resolveCommand(command, md);

Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/FakeDataManager.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/FakeDataManager.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/FakeDataManager.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -76,18 +76,26 @@
 
     // Track history to verify it later
     private List<String> queries = new ArrayList<String>();
+    private boolean recordingCommands = true;
     
-	public FakeDataManager() {
-	}
-    
     /**
      * Return string form of all queries run against this FDM 
-     * @return List<String>
+     * @return List<String> recorded commands
      */
     public List<String> getQueries() {
         return this.queries;
     }
 	        
+    /**
+     * Clears the list of recorded commands and returns a copy
+     * @return a copy of the recorded commands prior to clearing the list
+     */
+    public List<String> clearQueries() {
+    	List<String> rc = new ArrayList<String>(this.getQueries());
+    	this.queries.clear();
+    	return rc;
+    }
+	        
 	public void registerTuples(Object groupID, List elements, List[] data) {
 		tuples.put(groupID, new Object[] { elements, data });
 	}
@@ -101,9 +109,10 @@
         
         LogManager.logTrace(LOG_CONTEXT, new Object[]{"Register Request:", command, ",processorID:", processorID, ",model name:", modelName,",TupleSourceID nodeID:",new Integer(nodeID)}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 
-        
-        if (! (command instanceof BatchedUpdateCommand) ) {
-        	this.queries.add(command.toString());
+        if (this.recordingCommands) {
+            if (! (command instanceof BatchedUpdateCommand) ) {
+            	this.queries.add(command.toString());
+            }
         }
 
         if (ReferenceCollectorVisitor.getReferences(command).size() > 0) {
@@ -122,9 +131,11 @@
     		if ( command.getSubCommands().get(0) instanceof Update ) {
     			group = ((Update)command.getSubCommands().get(0)).getGroup();
     		}
-        	for ( Iterator<Command> it = ((BatchedUpdateCommand) command).getUpdateCommands().iterator(); it.hasNext(); ) {
-        		this.queries.add(it.next().toString());
-        	}
+    		if (this.recordingCommands) {
+            	for ( Iterator<Command> it = ((BatchedUpdateCommand) command).getUpdateCommands().iterator(); it.hasNext(); ) {
+            		this.queries.add(it.next().toString());
+            	}
+    		}
 		}
 		
 		Object groupID = group.getMetadataID();
@@ -350,8 +361,31 @@
     }
     
     @Override
-    public void clearCodeTables() {
-    	
-    }
+    public void clearCodeTables() {/* does nothing */}
 
+    /**
+     * Are commands/queries that are registered with the data manager being 
+     * recorded?
+     * <p>
+     * Recorded commands can be retrieved by {@link #getQueries()}
+     * 
+	 * @return whether or not commands should be recorded
+	 */
+	public boolean isRecordingCommands() {
+		return recordingCommands;
+	}
+
+	/**
+	 * Indicate whether or not commands/queries registered with the data 
+	 * manager are to be recorded in {@link #queries}.
+	 * <p>
+	 * Recorded commands can be retrieved by {@link #getQueries()}
+     * 
+	 * @param shouldRecord should commands be recorded?
+	 */
+	public void setRecordingCommands(boolean shouldRecord) {
+		this.recordingCommands = shouldRecord;
+	}
+
+
 }
\ No newline at end of file

Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/FakeProcessorPlan.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/FakeProcessorPlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/FakeProcessorPlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -30,7 +30,7 @@
 
 /**
  */
-public class FakeProcessorPlan extends BaseProcessorPlan {
+public class FakeProcessorPlan extends ProcessorPlan {
 
     private List outputElements;
     private List batches;
@@ -51,7 +51,7 @@
     /**
      * @see java.lang.Object#clone()
      */
-    public Object clone() {
+    public FakeProcessorPlan clone() {
         throw new UnsupportedOperationException();
     }
 

Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/TestBaseProcessorPlan.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/TestBaseProcessorPlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/TestBaseProcessorPlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -35,7 +35,6 @@
 import com.metamatrix.common.buffer.BlockedException;
 import com.metamatrix.common.buffer.BufferManager;
 import com.metamatrix.common.buffer.TupleBatch;
-import com.metamatrix.common.buffer.TupleSource;
 import com.metamatrix.query.util.CommandContext;
 
 public class TestBaseProcessorPlan extends TestCase {
@@ -55,15 +54,13 @@
         assertNull("Did not clear warnings from plan", plan.getAndClearWarnings());         //$NON-NLS-1$
     }
 
-
-
-    private static class FakeProcessorPlan extends BaseProcessorPlan {
+    private static class FakeProcessorPlan extends ProcessorPlan {
             
         
             /**
          * @see java.lang.Object#clone()
          */
-        public Object clone() {
+        public FakeProcessorPlan clone() {
             return null;
         }
 
@@ -74,12 +71,6 @@
         }
 
         /**
-         * @see com.metamatrix.query.processor.ProcessorPlan#connectTupleSource(com.metamatrix.common.buffer.TupleSource, int)
-         */
-        public void connectTupleSource(TupleSource source, int dataRequestID) {
-        }
-
-        /**
          * @see com.metamatrix.query.processor.ProcessorPlan#getOutputElements()
          */
         public List getOutputElements() {
@@ -108,14 +99,6 @@
         public void open() throws MetaMatrixComponentException {
         }
 
-        /* (non-Javadoc)
-         * @see com.metamatrix.query.processor.ProcessorPlan#getUpdateCount()
-         */
-        public int getUpdateCount() {
-            // TODO Auto-generated method stub
-            return 0;
-        }
-
         public Map getDescriptionProperties() {
             return new HashMap();
         }

Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/batch/TestBatchedUpdatePlan.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/processor/batch/TestBatchedUpdatePlan.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/test/java/com/metamatrix/query/processor/batch/TestBatchedUpdatePlan.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -36,8 +36,8 @@
 import com.metamatrix.common.buffer.BufferManager;
 import com.metamatrix.common.buffer.TupleBatch;
 import com.metamatrix.common.buffer.TupleSource;
-import com.metamatrix.query.processor.BaseProcessorPlan;
 import com.metamatrix.query.processor.ProcessorDataManager;
+import com.metamatrix.query.processor.ProcessorPlan;
 import com.metamatrix.query.util.CommandContext;
 
 
@@ -58,7 +58,7 @@
             totalCommands += commandsPerPlan[i];
             plans.add(new FakeProcessorPlan(commandsPerPlan[i]));
         }
-        BatchedUpdatePlan plan = new BatchedUpdatePlan(plans, totalCommands);
+        BatchedUpdatePlan plan = new BatchedUpdatePlan(plans, totalCommands, null);
         TupleBatch batch = plan.nextBatch();
         assertEquals(totalCommands, batch.getRowCount());
         for (int i = 1; i <= totalCommands; i++) {
@@ -71,7 +71,7 @@
         for (int i = 0; i < plans.length; i++) {
             plans[i] = new FakeProcessorPlan(1);
         }
-        BatchedUpdatePlan plan = new BatchedUpdatePlan(Arrays.asList(plans), plans.length);
+        BatchedUpdatePlan plan = new BatchedUpdatePlan(Arrays.asList(plans), plans.length, null);
         plan.open();
         // First plan may or may not be opened, but all subsequent plans should not be opened.
         for (int i = 1; i < plans.length; i++) {
@@ -91,14 +91,14 @@
         helpTestNextBatch(new int[] {1, 1, 1, 1});
     }
     
-    private class FakeProcessorPlan extends BaseProcessorPlan {
+    private class FakeProcessorPlan extends ProcessorPlan {
         private int counts = 0;
         private boolean opened = false;
         private int updateConnectorCount = 1;
         private FakeProcessorPlan(int commands) {
             counts = commands;
         }       
-        public Object clone() {return null;}
+        public FakeProcessorPlan clone() {return null;}
         public void close() throws MetaMatrixComponentException {}
         public void connectTupleSource(TupleSource source, int dataRequestID) {}
         public List getOutputElements() {return null;}

Modified: trunk/engine/src/test/java/com/metamatrix/query/unittest/FakeMetadataFactory.java
===================================================================
--- trunk/engine/src/test/java/com/metamatrix/query/unittest/FakeMetadataFactory.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/test/java/com/metamatrix/query/unittest/FakeMetadataFactory.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -887,8 +887,10 @@
         QueryNode vspqn41 = new QueryNode("vsp41", "CREATE VIRTUAL PROCEDURE BEGIN SELECT e1 FROM pm1.g1 where e2=15; END"); //$NON-NLS-1$ //$NON-NLS-2$
         FakeMetadataObject vsp41 = createVirtualProcedure("pm1.vsp41", pm1, Arrays.asList(new FakeMetadataObject[] { vspp1 }), vspqn41); //$NON-NLS-1$
 
-        vm1g1.putProperty(FakeMetadataObject.Props.INSERT_PROCEDURE, "CREATE PROCEDURE BEGIN ROWS_UPDATED = INSERT INTO pm1.g1(e2) values(INPUT.e2); END"); //$NON-NLS-1$
-        vm1g1.putProperty(FakeMetadataObject.Props.UPDATE_PROCEDURE, "CREATE PROCEDURE BEGIN ROWS_UPDATED = UPDATE pm1.g1 SET e2 = INPUT.e2; END"); //$NON-NLS-1$       
+        vm1g1.putProperty(FakeMetadataObject.Props.INSERT_PROCEDURE, "CREATE PROCEDURE BEGIN ROWS_UPDATED = INSERT INTO pm1.g1(e1, e2, e3, e4) values(INPUT.e1, INPUT.e2, INPUT.e3, INPUT.e4); END"); //$NON-NLS-1$
+        vm1g1.putProperty(FakeMetadataObject.Props.UPDATE_PROCEDURE, "CREATE PROCEDURE BEGIN ROWS_UPDATED = UPDATE pm1.g1 SET e1 = INPUT.e1, e2 = INPUT.e2, e3 = INPUT.e3, e4=INPUT.e4 WHERE TRANSLATE CRITERIA; END"); //$NON-NLS-1$       
+        vm1g1.putProperty(FakeMetadataObject.Props.DELETE_PROCEDURE, "CREATE PROCEDURE BEGIN ROWS_UPDATED = DELETE FROM pm1.g1 WHERE TRANSLATE CRITERIA; END"); //$NON-NLS-1$       
+
         vm1g37.putProperty(FakeMetadataObject.Props.INSERT_PROCEDURE, "CREATE PROCEDURE BEGIN ROWS_UPDATED = INSERT INTO pm4.g1(e1, e2, e3, e4) values(INPUT.e1, INPUT.e2, INPUT.e3, INPUT.e4); END"); //$NON-NLS-1$
         vm1g37.putProperty(FakeMetadataObject.Props.DELETE_PROCEDURE, "CREATE PROCEDURE BEGIN ROWS_UPDATED = DELETE FROM pm4.g1 where translate criteria; END"); //$NON-NLS-1$
         QueryNode vspqn37 = new QueryNode("vsp37", "CREATE VIRTUAL PROCEDURE BEGIN DECLARE integer x; VARIABLES.x=5; INSERT INTO vm1.g1(e2) values(VARIABLES.x); END"); //$NON-NLS-1$ //$NON-NLS-2$

Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDataTierManager.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDataTierManager.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDataTierManager.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -29,10 +29,10 @@
 import java.util.Map;
 import java.util.Properties;
 
-import org.teiid.connector.metadata.runtime.MetadataStore;
-
 import junit.framework.TestCase;
 
+import org.teiid.connector.metadata.runtime.MetadataStore;
+
 import com.metamatrix.api.exception.ComponentNotFoundException;
 import com.metamatrix.api.exception.MetaMatrixComponentException;
 import com.metamatrix.api.exception.MetaMatrixException;
@@ -316,11 +316,9 @@
         }
     }
     
-    private static class FakeProcessorPlan implements ProcessorPlan {
-        public Object clone() {return this;}
+    private static class FakeProcessorPlan extends ProcessorPlan {
+        public FakeProcessorPlan clone() {return this;}
         public void close() throws MetaMatrixComponentException {}
-        public List getAndClearWarnings() {return null;}
-        public CommandContext getContext() {return null;}
         public List getOutputElements() {return Collections.EMPTY_LIST;}
         public void initialize(CommandContext context,ProcessorDataManager dataMgr,BufferManager bufferMgr) {}
         public TupleBatch nextBatch() throws BlockedException,MetaMatrixComponentException {

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-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -124,9 +124,22 @@
         //make sure the plan is only created once
         assertEquals("should reuse the plan", exHitCount, prepPlanCache.hitCount); //$NON-NLS-1$
                 
+        // If we are using FakeDataManager, stop command recording to prevent
+        // duplicate commands
+        boolean dmir = false;
+        if (dataManager instanceof FakeDataManager && ((FakeDataManager) dataManager).isRecordingCommands()) {
+        	dmir = true;
+        	((FakeDataManager) dataManager).setRecordingCommands(false);
+        }
         // Run query again
         TestProcessor.doProcess(plan.processPlan, dataManager, expected, plan.context);
         
+        // If we are using FakeDataManager and we stopped it from recording, 
+        // start it back up again
+        if (dmir == true) {
+        	((FakeDataManager) dataManager).setRecordingCommands(true);
+        }
+        
         //get the plan again with a new connection
         assertNotNull(TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, capFinder, metadata, prepPlanCache, 7, callableStatement, false));
 

Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatementBatchedUpdate.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatementBatchedUpdate.java	2009-12-22 19:36:54 UTC (rev 1698)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatementBatchedUpdate.java	2009-12-23 15:14:00 UTC (rev 1699)
@@ -48,19 +48,53 @@
  */
 public class TestPreparedStatementBatchedUpdate {
 
+    @Test public void testBatchedUpdatePushdown() throws Exception {
+        // Create query 
+		String preparedSql = "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE pm1.g1.e2=?"; //$NON-NLS-1$
+        
+		// Create a testable prepared plan cache
+		TestablePreparedPlanCache prepPlanCache = new TestablePreparedPlanCache();
+		
+		// Construct data manager with data
+        HardcodedDataManager dataManager = new HardcodedDataManager();
+		dataManager.addData("UPDATE pm1.g1 SET e1 = ?, e3 = ? WHERE pm1.g1.e2 = ?", new List[] {Arrays.asList(4)}); //$NON-NLS-1$
+		// Source capabilities must support batched updates
+        FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+        BasicSourceCapabilities caps = new BasicSourceCapabilities();
+        caps.setCapabilitySupport(Capability.BULK_UPDATE, true);
+        capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+        
+        // batch with two commands
+		ArrayList<ArrayList<Object>> values = new ArrayList<ArrayList<Object>>(2);
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "a",  Boolean.FALSE, new Integer(0) })));  //$NON-NLS-1$
+    	values.add(new ArrayList<Object>(Arrays.asList(new Object[] { null, Boolean.FALSE, new Integer(1) })));
+    	
+    	List<?>[] expected = new List[] { 
+                Arrays.asList(4)
+        };
+    	
+    	// Create the plan and process the query
+    	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, false);
+    	Update update = (Update)dataManager.getCommandHistory().iterator().next();
+    	assertTrue(((Constant)update.getChangeList().getClauses().get(0).getValue()).isMultiValued());
+    }
+    
     /**
      * Test prepared statements that use batched updates using the same prepared
-     * command with varying number of commands in the batch.
+     * command with same number of commands in the batch.
      * <p>
-     * The test verifies that no errors occur when planning the same batched 
-     * command SQL with varying number of batched command parameter value sets.
-     * For example, if the first executeBatch() call were to occur with three 
-     * batched commands a repeated call with only two batched commands should 
-     * not result in an error.
+     * The test verifies that no errors occur when planning and executing the 
+     * same batched command SQL with the same number of batched command parameter 
+     * value sets.  For example, if the first executeBatch() call were to occur 
+     * with two batched commands a repeated call with two batched commands  
+     * should not result in an error during planning or execution and the value 
+     * used in the second batched command should be used instead of any values 
+     * from the first batched command.
      * <p>
-     * The test also verifies that a cached version of the PreparedStatement plan 
-     * is used on each subsequent execution of the same SQL command even though 
-     * the number of batched commands may vary. 
+     * The test also verifies that the correct SQL is pushed to the data manager 
+     * to verify that the parameter substitution occurred and is correct and the
+     * correct number of statements made it to the data manager for the respective 
+     * batch command.
      * <p>
      * The batched command "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE pm1.g1.e2=?"
      * will appear as:
@@ -69,51 +103,169 @@
      * UPDATE pm1.g1 SET pm1.g1.e1=null, pm1.g1.e3=false WHERE pm1.g1.e2=1
      * <p>
      * UPDATE pm1.g1 SET pm1.g1.e1='a', pm1.g1.e3=false WHERE pm1.g1.e2=0
-     * <p>
-     * UPDATE pm1.g1 SET pm1.g1.e1='a', pm1.g1.e3=false WHERE pm1.g1.e2=0
-     * UPDATE pm1.g1 SET pm1.g1.e1=null, pm1.g1.e3=false WHERE pm1.g1.e2=1
-     * UPDATE pm1.g1 SET pm1.g1.e1='c', pm1.g1.e3=true WHERE pm1.g1.e2=4
      * UPDATE pm1.g1 SET pm1.g1.e1='b', pm1.g1.e3=true WHERE pm1.g1.e2=5
      * <p>
-     * The result should be that only one command is in the plan cache and 
-     * no plan creation or validation errors will occur.
+     * The result should be that one command is in the plan cache and 
+     * no plan creation, validation, or execution errors will occur and 
+     * a predetermined set of queries were executed in the data manager.
      * 
      * @throws Exception
      */
-    @Test public void testPlanCache_VarNumCmds() throws Exception {
+    @Test public void testUpdateSameNumCmds() throws Exception {
         // Create query 
 		String preparedSql = "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE pm1.g1.e2=?"; //$NON-NLS-1$
+		// Create a testable prepared plan cache
+		TestablePreparedPlanCache prepPlanCache = new TestablePreparedPlanCache();
+		
+		// Construct data manager with data
+        FakeDataManager dataManager = new FakeDataManager();
+        TestProcessor.sampleData1(dataManager);    
+		
+		// Source capabilities must support batched updates
+        FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+        BasicSourceCapabilities caps = new BasicSourceCapabilities();
+        caps.setCapabilitySupport(Capability.BATCHED_UPDATES, true);
+        capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
         
-		// Create PrepareedPlanCache
-		PreparedPlanCache prepPlanCache = new PreparedPlanCache();
+        // Something to hold our final query list
+        List<String> finalQueryList = new ArrayList<String>(13);
+        
+		// Create expected results
+        // first command should result in 2 rows affected
+        // second command should result in 2 rows affected  
+        List<?>[] expected = new List[] { 
+            Arrays.asList(new Object[] { new Integer(2) }),
+            Arrays.asList(new Object[] { new Integer(2) })
+        };    
+
+        // batch with two commands
+		List<List<Object>> values = new ArrayList<List<Object>>(2);
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "a",  Boolean.FALSE, new Integer(0) })));  //$NON-NLS-1$
+    	values.add(new ArrayList<Object>(Arrays.asList(new Object[] { null, Boolean.FALSE, new Integer(1) })));
+    	
+    	// Add our expected queries to the final query list
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = null, e3 = FALSE WHERE pm1.g1.e2 = 1")); //$NON-NLS-1$
+    	
+    	// Create the plan and process the query
+    	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, false);
+
+    	// Repeat with different number of commands in batch
+    	// Create expected results
+        // first command should result in 2 rows affected
+        expected = new List[] { 
+                Arrays.asList(new Object[] { new Integer(2) }),
+                Arrays.asList(new Object[] { new Integer(0) })
+        };    
+
+        // batch with two commands
+		values = new ArrayList<List<Object>>(1);
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "a",  Boolean.FALSE, new Integer(0) })));  //$NON-NLS-1$
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "b",  Boolean.TRUE, new Integer(5) })));  //$NON-NLS-1$
+    	
+    	// Add our expected queries to the final query list
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'b', e3 = TRUE WHERE pm1.g1.e2 = 5")); //$NON-NLS-1$
+    	
+    	// Use the cached plan and process the query
+    	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, true);
+
+    	// Verify all the queries that were run
+    	assertEquals("Unexpected queries executed -", finalQueryList, dataManager.getQueries()); //$NON-NLS-1$
+    }
+    
+    /**
+     * Test prepared statements that use batched updates using the same prepared
+     * command with same number of commands in the batch.  Update is performed 
+     * against a view model instead of a source model.
+     * <p>
+     * The test verifies that no errors occur when planning and executing the 
+     * same batched command SQL with the same number of batched command parameter 
+     * value sets.  For example, if the first executeBatch() call were to occur 
+     * with two batched commands a repeated call with two batched commands  
+     * should not result in an error during planning or execution and the value 
+     * used in the second batched command should be used instead of any values 
+     * from the first batched command.
+     * <p>
+     * The test also verifies that the correct SQL is pushed to the data manager 
+     * to verify that the parameter substitution occurred and is correct and the
+     * correct number of statements made it to the data manager for the respective 
+     * batch command.
+     * <p>
+     * The batched command "UPDATE vm1.g1 SET vm1.g1.e2=? WHERE vm1.g1.e1=?"
+     * will appear as:
+     * <p>
+     * UPDATE pm1.g1 SET e2=0 WHERE pm1.g1.e1='a'
+     * UPDATE pm1.g1 SET e2=1 WHERE pm1.g1.e1='b'
+     * <p>
+     * UPDATE pm1.g1 SET e2=2 WHERE pm1.g1.e1='c'
+     * UPDATE pm1.g1 SET e2=3 WHERE pm1.g1.e1='d'
+     * <p>
+     * The result should be that one command is in the plan cache and 
+     * no plan creation, validation, or execution errors will occur and 
+     * a predetermined set of queries were executed in the data manager.
+     * 
+     * @throws Exception
+     */
+    @Test public void testUpdateSameNumCmds_Virtual() throws Exception {
+        // Create query 
+		String preparedSql = "UPDATE vm1.g1 SET vm1.g1.e2=? WHERE vm1.g1.e1=?"; //$NON-NLS-1$
+		// Create a testable prepared plan cache
+		TestablePreparedPlanCache prepPlanCache = new TestablePreparedPlanCache();
 		
+		// Construct data manager with data
+        FakeDataManager dataManager = new FakeDataManager();
+        TestProcessor.sampleData1(dataManager);    
+		
+		// Source capabilities must support batched updates
+        FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+        BasicSourceCapabilities caps = new BasicSourceCapabilities();
+        caps.setCapabilitySupport(Capability.BATCHED_UPDATES, true);
+        capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+        
+        // Something to hold our final query list
+        List<String> finalQueryList = new ArrayList<String>();
+        
+		// Create expected results
+        List<?>[] expected = new List[] { 
+            Arrays.asList(3),
+            Arrays.asList(1)
+        };    
+
         // batch with two commands
 		ArrayList<ArrayList<Object>> values = new ArrayList<ArrayList<Object>>(2);
-		values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "a",  Boolean.FALSE, new Integer(0) } ) ) );  //$NON-NLS-1$
-    	values.add( new ArrayList<Object>( Arrays.asList( new Object[] { null, Boolean.FALSE, new Integer(1) } ) ) );
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { new Integer(0), "a" })));  //$NON-NLS-1$
+    	values.add(new ArrayList<Object>(Arrays.asList(new Object[] { new Integer(1), "b" })));  //$NON-NLS-1$
     	
-        //Create plan
-    	TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, prepPlanCache);
+    	// Add our expected queries to the final query list
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e2 = 0 WHERE pm1.g1.e1 = 'a'")); //$NON-NLS-1$
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e2 = 1 WHERE pm1.g1.e1 = 'b'")); //$NON-NLS-1$
+    	
+    	// Create the plan and process the query
+    	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, false);
 
-        // batch with one command
+    	// Repeat
+        expected = new List[] { 
+    		Arrays.asList(1),
+            Arrays.asList(0)
+        };    
+
+        // batch with two commands
 		values = new ArrayList<ArrayList<Object>>(1);
-		values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "a",  Boolean.FALSE, new Integer(0) } ) ) );  //$NON-NLS-1$
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { new Integer(2), "c" })));  //$NON-NLS-1$
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { new Integer(3), "d" })));  //$NON-NLS-1$
     	
-        //Create plan
-		TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, prepPlanCache);
+    	// Add our expected queries to the final query list
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e2 = 2 WHERE pm1.g1.e1 = 'c'")); //$NON-NLS-1$
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e2 = 3 WHERE pm1.g1.e1 = 'd'")); //$NON-NLS-1$
+    	
+    	// Use the cached plan and process the query
+    	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, true);
 
-        // batch with four commands
-		values = new ArrayList<ArrayList<Object>>(4);
-		values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "a",  Boolean.FALSE, new Integer(0) } ) ) );  //$NON-NLS-1$
-    	values.add( new ArrayList<Object>( Arrays.asList( new Object[] { null, Boolean.FALSE, new Integer(1) } ) ) );
-		values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "c",  Boolean.TRUE, new Integer(4) } ) ) );  //$NON-NLS-1$
-		values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "b",  Boolean.TRUE, new Integer(5) } ) ) );  //$NON-NLS-1$
-    	
-        //Create plan
-		TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, prepPlanCache);
-		assertEquals("PreparedPlanCache size is invalid - ", 1, prepPlanCache.getSpaceUsed() ); //$NON-NLS-1$
+    	// Verify all the queries that were run
+    	assertEquals("Unexpected queries executed -", finalQueryList, dataManager.getQueries()); //$NON-NLS-1$
     }
-
+    
     /**
      * Test prepared statements that use batched updates using the same prepared
      * command with varying number of commands in the batch.
@@ -124,14 +276,10 @@
      * with two batched commands a repeated call with only one batched command 
      * should not result in an error during planning or execution.
      * <p>
-     * The test also verifies that a cached version of the PreparedStatement plan 
-     * is used on each subsequent execution of the same SQL command even though 
-     * the number of batched commands may vary. 
-     * <p>
      * The test also verifies that the correct SQL is pushed to the data manager 
      * to verify that the parameter substitution occurred and is correct and the
      * correct number of statements made it to the data manager for the respective 
-     * batch.
+     * batch command.
      * <p>
      * The batched command "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE pm1.g1.e2=?"
      * will appear as:
@@ -146,16 +294,15 @@
      * UPDATE pm1.g1 SET pm1.g1.e1='c', pm1.g1.e3=true WHERE pm1.g1.e2=4
      * UPDATE pm1.g1 SET pm1.g1.e1='b', pm1.g1.e3=true WHERE pm1.g1.e2=5
      * <p>
-     * The result should be that only one command is in the plan cache and 
+     * The result should be that three commands are in the plan cache and 
      * no plan creation, validation, or execution errors will occur and 
      * a predetermined set of queries were executed in the data manager.
      * 
      * @throws Exception
      */
-    @Test public void testProcessor_VarNumCmds() throws Exception {
+    @Test public void testUpdateVarNumCmds() throws Exception {
         // Create query 
 		String preparedSql = "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE pm1.g1.e2=?"; //$NON-NLS-1$
-        int executionsPerTest = 2;
 		// Create a testable prepared plan cache
 		TestablePreparedPlanCache prepPlanCache = new TestablePreparedPlanCache();
 		
@@ -186,10 +333,8 @@
     	values.add(new ArrayList<Object>(Arrays.asList(new Object[] { null, Boolean.FALSE, new Integer(1) })));
     	
     	// Add our expected queries to the final query list
-    	for ( int i = 0; i < executionsPerTest; i++ ) {
-    		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
-    		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = null, e3 = FALSE WHERE pm1.g1.e2 = 1")); //$NON-NLS-1$
-    	}
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = null, e3 = FALSE WHERE pm1.g1.e2 = 1")); //$NON-NLS-1$
     	
     	// Create the plan and process the query
     	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, false);
@@ -206,9 +351,7 @@
 		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "a",  Boolean.FALSE, new Integer(0) })));  //$NON-NLS-1$
     	
     	// Add our expected queries to the final query list
-    	for (int i = 0; i < executionsPerTest; i++) {
-    		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
-    	}
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
     	
     	// Use the cached plan and process the query
     	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, true);
@@ -234,12 +377,10 @@
 		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "b",  Boolean.TRUE, new Integer(5)} )));  //$NON-NLS-1$
 
     	// Add our expected queries to the final query list
-    	for (int i = 0; i < executionsPerTest; i++) {
-    		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
-    		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = null, e3 = FALSE WHERE pm1.g1.e2 = 1")); //$NON-NLS-1$
-    		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'c', e3 = TRUE WHERE pm1.g1.e2 = 4")); //$NON-NLS-1$
-    		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'b', e3 = TRUE WHERE pm1.g1.e2 = 5")); //$NON-NLS-1$
-    	}
+		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
+		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = null, e3 = FALSE WHERE pm1.g1.e2 = 1")); //$NON-NLS-1$
+		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'c', e3 = TRUE WHERE pm1.g1.e2 = 4")); //$NON-NLS-1$
+		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'b', e3 = TRUE WHERE pm1.g1.e2 = 5")); //$NON-NLS-1$
     	
     	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, true);
 
@@ -247,35 +388,118 @@
     	assertEquals("Unexpected queries executed -", finalQueryList, dataManager.getQueries()); //$NON-NLS-1$
     }
     
-    @Test public void testBatchedUpdatePushdown() throws Exception {
+    /**
+     * Test prepared statements that use batched updates using the same prepared
+     * command with varying number of commands in the batch.  Update is 
+     * performed against a view model instead of a source model.
+     * <p>
+     * The test verifies that no errors occur when planning and executing the 
+     * same batched command SQL with varying number of batched command parameter 
+     * value sets.  For example, if the first executeBatch() call were to occur 
+     * with two batched commands a repeated call with only one batched command 
+     * should not result in an error during planning or execution.
+     * <p>
+     * The test also verifies that the correct SQL is pushed to the data manager 
+     * to verify that the parameter substitution occurred and is correct and the
+     * correct number of statements made it to the data manager for the respective 
+     * batch command.
+     * <p>
+     * The batched command "UPDATE vm1.g1 SET vm1.g1.e1=?, vm1.g1.e3=? WHERE vm1.g1.e2=?"
+     * will appear as:
+     * <p>
+     * UPDATE pm1.g1 SET e1='a', e3=false WHERE pm1.g1.e2=0
+     * UPDATE pm1.g1 SET e1='b', e3=true WHERE pm1.g1.e2=1
+     * <p>
+     * UPDATE pm1.g1 SET e1='c', e3=false WHERE pm1.g1.e2=1
+     * <p>
+     * UPDATE pm1.g1 SET e1='d', e3=false WHERE pm1.g1.e2=1
+     * UPDATE pm1.g1 SET e1='e', e3=false WHERE pm1.g1.e2=0
+     * UPDATE pm1.g1 SET e1='f', e3=true WHERE pm1.g1.e2=2
+     * UPDATE pm1.g1 SET e1='g', e3=true WHERE pm1.g1.e2=3
+     * <p>
+     * The result should be that three commands are in the plan cache and 
+     * no plan creation, validation, or execution errors will occur and 
+     * a predetermined set of queries were executed in the data manager.
+     * 
+     * @throws Exception
+     */
+    @Test public void testUpdateVarNumCmds_Virtual() throws Exception {
         // Create query 
-		String preparedSql = "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE pm1.g1.e2=?"; //$NON-NLS-1$
-        
+		String preparedSql = "UPDATE vm1.g1 SET vm1.g1.e1=?, vm1.g1.e3=? WHERE vm1.g1.e2=?"; //$NON-NLS-1$
 		// Create a testable prepared plan cache
 		TestablePreparedPlanCache prepPlanCache = new TestablePreparedPlanCache();
 		
 		// Construct data manager with data
-        HardcodedDataManager dataManager = new HardcodedDataManager();
-		dataManager.addData("UPDATE pm1.g1 SET e1 = ?, e3 = ? WHERE pm1.g1.e2 = ?", new List[] {Arrays.asList(4)}); //$NON-NLS-1$
+        FakeDataManager dataManager = new FakeDataManager();
+        TestProcessor.sampleData1(dataManager);    
+		
 		// Source capabilities must support batched updates
         FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
         BasicSourceCapabilities caps = new BasicSourceCapabilities();
-        caps.setCapabilitySupport(Capability.BULK_UPDATE, true);
+        caps.setCapabilitySupport(Capability.BATCHED_UPDATES, true);
         capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
         
+        // Something to hold our final query list
+        List<String> finalQueryList = new ArrayList<String>(13);
+        
+		// Create expected results
+        List<?>[] expected = new List[] { 
+                Arrays.asList(2),
+                Arrays.asList(2)
+        };    
+
         // batch with two commands
 		ArrayList<ArrayList<Object>> values = new ArrayList<ArrayList<Object>>(2);
 		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "a",  Boolean.FALSE, new Integer(0) })));  //$NON-NLS-1$
-    	values.add(new ArrayList<Object>(Arrays.asList(new Object[] { null, Boolean.FALSE, new Integer(1) })));
+    	values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "b", Boolean.TRUE, new Integer(1) })));  //$NON-NLS-1$
     	
-    	List<?>[] expected = new List[] { 
-                Arrays.asList(4)
-        };
+    	// Add our expected queries to the final query list
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'b', e3 = TRUE WHERE pm1.g1.e2 = 1")); //$NON-NLS-1$
     	
     	// Create the plan and process the query
     	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, false);
-    	Update update = (Update)dataManager.getCommandHistory().iterator().next();
-    	assertTrue(((Constant)update.getChangeList().getClauses().get(0).getValue()).isMultiValued());
+
+    	// Repeat with different number of commands in batch
+        expected = new List[] { 
+            Arrays.asList(new Object[] { new Integer(2) })
+        };    
+
+        // batch with one command
+		values = new ArrayList<ArrayList<Object>>(1);
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "c",  Boolean.FALSE, new Integer(1) })));  //$NON-NLS-1$
+    	
+    	// Add our expected queries to the final query list
+   		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'c', e3 = FALSE WHERE pm1.g1.e2 = 1")); //$NON-NLS-1$
+    	
+    	// Use the cached plan and process the query
+    	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, true);
+
+    	// Repeat with different number of commands in batch
+        expected = new List[] { 
+                Arrays.asList(2),
+                Arrays.asList(2),
+                Arrays.asList(1),
+                Arrays.asList(1)
+        };    
+
+        // batch with four commands
+		values = new ArrayList<ArrayList<Object>>(4);
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "d",  Boolean.FALSE, new Integer(1)} )));  //$NON-NLS-1$
+    	values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "e", Boolean.FALSE, new Integer(0)} )));  //$NON-NLS-1$ 
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "f",  Boolean.TRUE, new Integer(2)} )));  //$NON-NLS-1$
+		values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "g",  Boolean.TRUE, new Integer(3)} )));  //$NON-NLS-1$
+
+    	// Add our expected queries to the final query list
+		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'd', e3 = FALSE WHERE pm1.g1.e2 = 1")); //$NON-NLS-1$
+		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'e', e3 = FALSE WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
+		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'f', e3 = TRUE WHERE pm1.g1.e2 = 2")); //$NON-NLS-1$
+		finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'g', e3 = TRUE WHERE pm1.g1.e2 = 3")); //$NON-NLS-1$
+    	
+    	TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager, capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, true);
+
+    	// Verify all the queries that were run
+    	assertEquals("Unexpected queries executed -", finalQueryList, dataManager.getQueries()); //$NON-NLS-1$
     }
-    
+
 }



More information about the teiid-commits mailing list