diff --git a/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java b/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
index d4cb205..13ae34e 100644
--- a/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
+++ b/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
@@ -25,15 +25,7 @@
 import static org.teiid.query.analysis.AnalysisRecord.*;
 
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-import java.util.TreeMap;
+import java.util.*;
 
 import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.api.exception.query.QueryValidatorException;
@@ -65,6 +57,10 @@
 import org.teiid.query.analysis.AnalysisRecord;
 import org.teiid.query.metadata.QueryMetadataInterface;
 import org.teiid.query.metadata.SupportConstants;
+import org.teiid.query.metadata.TempMetadataAdapter;
+import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
+import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
+import org.teiid.query.optimizer.relational.rules.CapabilitiesUtil;
 import org.teiid.query.processor.BatchIterator;
 import org.teiid.query.processor.CollectionTupleSource;
 import org.teiid.query.processor.ProcessorDataManager;
@@ -72,11 +68,14 @@
 import org.teiid.query.processor.QueryProcessor;
 import org.teiid.query.processor.RegisterRequestParameter;
 import org.teiid.query.processor.proc.CreateCursorResultSetInstruction.Mode;
+import org.teiid.query.processor.relational.RelationalNodeUtil;
 import org.teiid.query.processor.relational.SubqueryAwareEvaluator;
 import org.teiid.query.resolver.command.UpdateProcedureResolver;
 import org.teiid.query.sql.ProcedureReservedWords;
+import org.teiid.query.sql.lang.BatchedUpdateCommand;
 import org.teiid.query.sql.lang.Command;
 import org.teiid.query.sql.lang.Criteria;
+import org.teiid.query.sql.lang.Insert;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.symbol.GroupSymbol;
@@ -88,6 +87,36 @@
  */
 public class ProcedurePlan extends ProcessorPlan implements ProcessorDataManager {
 
+	private static class BatchKey {
+		String model;
+		String connector;
+
+		public BatchKey(String model, String connector) {
+			this.model = model;
+			this.connector = connector;
+		}
+
+		@Override
+		public int hashCode() {
+			return this.connector != null?this.connector.hashCode():model.hashCode();
+		}
+		
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj) {
+				return true;
+			}
+			if (!(obj instanceof BatchKey)) {
+				return false;
+			}
+			BatchKey other = (BatchKey)obj;
+			if (this.connector != null) {
+				return this.connector.equals(other.connector);
+			}
+			return this.model.equals(other.model);
+		}
+	}
+	
 	private static class CursorState {
 		QueryProcessor processor;
 		IndexedTupleSource ts;
@@ -145,6 +174,11 @@
      * Resources cannot be held open across the txn boundary.  This list is a hack at ensuring the resources are closed.
      */
     private LinkedList<WeakReference<DataTierTupleSource>> txnTupleSources = new LinkedList<WeakReference<DataTierTupleSource>>();
+
+	private CapabilitiesFinder capabilitiesFinder;
+	
+	private Map<BatchKey, List<Command>> batchedCommands;
+	private TupleSource pending;
 
     /**
      * Constructor for ProcedurePlan.
@@ -443,6 +477,7 @@
         plan.setMetadata(metadata);
         plan.requiresTransaction = requiresTransaction;
         plan.runInContext = runInContext;
+        plan.capabilitiesFinder = capabilitiesFinder;
         return plan;
     }
 
@@ -507,7 +542,7 @@
     
 	private void createVariableContext() {
 		this.currentVarContext = new VariableContext(false);
-        this.currentVarContext.setValue(ROWCOUNT, 0);
+        this.currentVarContext.setValue(ROWCOUNT, null);
 	}
 
     /**
@@ -581,9 +616,9 @@
         		}
         		removeState(this.currentState);
         		this.currentState = null;
-        		int rowCount = 0;
+        		Object rowCount = 0;
         		if (t != null) {
-        			rowCount = (Integer)t.get(0);
+        			rowCount = t.get(0);
         		}
         		getCurrentVariableContext().setValue(ProcedurePlan.ROWCOUNT, rowCount);
         		return;
@@ -620,18 +655,14 @@
     /** 
      * @param success
      * @throws TeiidComponentException 
+     * @throws TeiidProcessingException 
      * @throws XATransactionException 
      */
     public void pop(Boolean success) throws TeiidComponentException {
-    	Program program = this.programs.pop();
-        if (this.currentVarContext.getParentContext() != null) {
-        	this.currentVarContext = this.currentVarContext.getParentContext();
-        }
-    	program.getTempTableStore().removeTempTables();
+    	Program program = this.programs.peek();
     	if (success != null && program.startedTxn() && this.blockContext != null) {
     		TransactionService ts = this.getContext().getTransactionServer();
     		TransactionContext tc = this.blockContext;
-    		this.blockContext = null;
     		try {
     			ts.resume(tc);
 	    		for (WeakReference<DataTierTupleSource> ref : txnTupleSources) {
@@ -642,15 +673,49 @@
 	    		}
 	    		this.txnTupleSources.clear();
 	    		if (success) {
+					flushBatched();
 	    			ts.commit(tc);
 	    		} else {
+	    			batchedCommands = null;
 	    			ts.rollback(tc);
 	    		}
+	    		this.blockContext = null;
     		} catch (XATransactionException e) {
     			 throw new TeiidComponentException(QueryPlugin.Event.TEIID30165, e);
     		}
     	}
+		flushBatched();
+        if (this.currentVarContext.getParentContext() != null) {
+        	this.currentVarContext = this.currentVarContext.getParentContext();
+        }
+    	program.getTempTableStore().removeTempTables();
+    	this.programs.pop();
     }
+
+	private void flushBatched() throws TeiidComponentException, AssertionError {
+		try {
+			if (pending != null) {
+				pending.nextTuple();
+				pending.closeSource();
+				pending = null;
+			}
+			if (batchedCommands != null) {
+				for (Iterator<Map.Entry<BatchKey, List<Command>>> iter = batchedCommands.entrySet().iterator(); iter.hasNext();) {
+					Map.Entry<BatchKey, List<Command>> entry = iter.next();
+					iter.remove();
+					if (!entry.getValue().isEmpty()) {
+						RegisterRequestParameter params = new RegisterRequestParameter(entry.getKey().connector, -1, -1);
+						pending = this.parentDataMrg.registerRequest(getContext(), new BatchedUpdateCommand(entry.getValue()), entry.getKey().model, params);
+						pending.nextTuple();
+						pending.closeSource();
+						pending = null;
+					}
+				}
+			}
+		} catch (TeiidProcessingException e) {
+			throw new AssertionError();
+		}
+	}
     
     public void push(Program program) throws XATransactionException {
     	program.reset(this.getContext().getConnectionId());
@@ -810,11 +875,59 @@
 		this.runInContext = runInContext;
 	}
 
+	public void setCapabilitiesFinder(CapabilitiesFinder capFinder) {
+		this.capabilitiesFinder = capFinder;
+	}
+	
 	@Override
 	public TupleSource registerRequest(CommandContext context, Command command,
 			String modelName, RegisterRequestParameter parameterObject)
 			throws TeiidComponentException, TeiidProcessingException {
+		if ((blockContext != null || (context.getTransactionContext() != null && context.getTransactionContext().getTransactionType() != Scope.NONE)) //txn
+				&& (programs.isEmpty() || !programs.peek().isTrappingExceptions()) //need to force errors as they occur
+				&& !TempMetadataAdapter.TEMP_MODEL.getID().equals(modelName)) { //only source queries
+			if (RelationalNodeUtil.isUpdate(command) && !parameterObject.mustExecute) {
+				Object modelID = metadata.getModelID(modelName);
+				//TODO: bulk support (but at this point it requires more logic to determine the bind parameters, which will happen
+				//      anyway at the source)
+				boolean supportsBatched = CapabilitiesUtil.supports(Capability.BATCHED_UPDATES, modelID, metadata, capabilitiesFinder);
+				if (supportsBatched) {
+					if (batchedCommands == null) {
+						batchedCommands = new HashMap<BatchKey, List<Command>>(); 
+					}
+					BatchKey key = new BatchKey(modelName, parameterObject.connectorBindingId);
+					List<Command> commands = batchedCommands.get(key);
+					if (commands == null) {
+						commands = new ArrayList<Command>();
+						batchedCommands.put(key, commands);
+					}
+					if (command instanceof BatchedUpdateCommand) {
+						//accumulate commands
+						throw new AssertionError();
+					} else if (command instanceof Insert) {
+						Insert insert = (Insert)command;
+						if (insert.getTupleSource() != null) {
+							throw new AssertionError();
+							//flush
+						}
+					} else {
+						commands.add(command);
+					}
+					throw new AssertionError();
+					//init the row count with an invalid value for safety
+					//return new CollectionTupleSource(Arrays.asList(Arrays.asList(CommandContext.INVALID)).iterator());
+				}
+			} else if (batchedCommands != null) {
+				BatchKey key = new BatchKey(modelName, parameterObject.connectorBindingId);
+				List<Command> existing = batchedCommands.get(key);
+				if (existing != null && !existing.isEmpty()) {
+					//flush
+					throw new AssertionError();
+				}
+			}
+		}
 		//programs will be empty for parameter evaluation
+		parameterObject.mustExecute = (programs.isEmpty() || programs.peek().isTrappingExceptions());
 		TupleSource ts = parentDataMrg.registerRequest(context, command, modelName, parameterObject);
 		if (blockContext != null && ts instanceof DataTierTupleSource) {
 			txnTupleSources.add(new WeakReference<DataTierTupleSource>((DataTierTupleSource)ts));
diff --git a/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java b/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java
index 2a3b04a..ef5195e 100644
--- a/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java
+++ b/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java
@@ -52,8 +52,10 @@
 import org.teiid.query.metadata.TransformationMetadata;
 import org.teiid.query.optimizer.QueryOptimizer;
 import org.teiid.query.optimizer.TestOptimizer;
+import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
 import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
 import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
+import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
 import org.teiid.query.parser.QueryParser;
 import org.teiid.query.processor.FakeDataManager;
 import org.teiid.query.processor.HardcodedDataManager;
@@ -2141,6 +2143,46 @@
         helpTestProcess(plan, expected, dataManager, tm);
 
     }
+    
+    @Test public void testAtomicBatching() throws Exception {
+        String proc = "CREATE VIRTUAL PROCEDURE " + //$NON-NLS-1$
+        		"BEGIN ATOMIC" + //$NON-NLS-1$
+                " update pm1.g1 set e1 = 1 where e4 < \"in\";\n" + //$NON-NLS-1$
+        		" if (\"in\" = 0) begin " +
+                " delete from pm1.g2 where e4 > rowcount;\n" + //$NON-NLS-1$
+        		" end else " +
+                " delete from pm1.g2 where e4 > 2; " +
+        		"END"; //$NON-NLS-1$
+        TransformationMetadata tm = RealMetadataFactory.example1();
+        addProc(tm, "sq1", proc, new String[] { "e1" }, 
+        		new String[] { DataTypeManager.DefaultDataTypes.INTEGER }, new String[] {"in"}, new String[] {DataTypeManager.DefaultDataTypes.INTEGER});
+        CommandContext context = new CommandContext("pID", null, null, null, 1); //$NON-NLS-1$
+    	QueryMetadataInterface metadata = new TempMetadataAdapter(tm, new TempMetadataStore());
+        context.setMetadata(metadata);
+
+        BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
+        caps.setCapabilitySupport(Capability.BATCHED_UPDATES, true);
+
+        TransactionContext tc = new TransactionContext();
+        TransactionService ts = Mockito.mock(TransactionService.class);
+        context.setTransactionService(ts);
+        context.setTransactionContext(tc);
+
+        String userQuery = "EXEC pm1.sq1(1)"; //$NON-NLS-1$
+        ProcessorPlan plan = getProcedurePlan(userQuery, tm, new DefaultCapabilitiesFinder(caps));
+        HardcodedDataManager dataMgr = new HardcodedDataManager();
+        dataMgr.setFullBatchedUpdate(true);
+        dataMgr.addData("UPDATE pm1.g1 SET e1 = '1' WHERE e4 < 1.0;\nDELETE FROM pm1.g2 WHERE e4 > 2.0", new List[]{Arrays.asList(1), Arrays.asList(2)});
+    	TestProcessor.helpProcess(plan, context, dataMgr, new List<?>[0]);
+    	Mockito.verify(ts, Mockito.times(3)).begin(tc);
+    	Mockito.verify(ts, Mockito.times(3)).commit(tc);
+    	
+    	userQuery = "EXEC pm1.sq1(0)"; //$NON-NLS-1$
+        plan = getProcedurePlan(userQuery, tm, new DefaultCapabilitiesFinder(caps));
+        dataMgr = new HardcodedDataManager();
+        dataMgr.addData("UPDATE pm1.g1 SET e1 = '1' WHERE e4 < 1.0;\nDELETE FROM pm1.g2 WHERE e4 > 2.0", new List[]{Arrays.asList(1), Arrays.asList(2)});
+    	TestProcessor.helpProcess(plan, context, dataMgr, new List<?>[0]);
+    }
 
     private static final boolean DEBUG = false;
     