[teiid-commits] teiid SVN: r4471 - in trunk: build/kits/jboss-as7/docs/teiid and 14 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Tue Sep 25 14:58:06 EDT 2012


Author: shawkins
Date: 2012-09-25 14:58:05 -0400 (Tue, 25 Sep 2012)
New Revision: 4471

Modified:
   trunk/api/src/main/java/org/teiid/language/SQLConstants.java
   trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html
   trunk/client/src/main/java/org/teiid/jdbc/TeiidSQLException.java
   trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/ProcedurePlanner.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/CreateCursorResultSetInstruction.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/ErrorInstruction.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/IfInstruction.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/LoopInstruction.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/Program.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/ProgramInstruction.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/WhileInstruction.java
   trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java
   trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
   trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
   trunk/engine/src/main/java/org/teiid/query/sql/proc/Block.java
   trunk/engine/src/main/java/org/teiid/query/sql/proc/ExceptionExpression.java
   trunk/engine/src/main/java/org/teiid/query/sql/proc/RaiseStatement.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
   trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
   trunk/engine/src/main/resources/org/teiid/query/i18n.properties
   trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
   trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcErrors.java
   trunk/engine/src/test/java/org/teiid/query/resolver/TestProcedureResolving.java
Log:
TEIID-1386 refinement to exception handling.  changed syntax slightly and added an exception handler to a block

Modified: trunk/api/src/main/java/org/teiid/language/SQLConstants.java
===================================================================
--- trunk/api/src/main/java/org/teiid/language/SQLConstants.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/api/src/main/java/org/teiid/language/SQLConstants.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -128,6 +128,7 @@
 		public static final String INDEX = "INDEX"; //$NON-NLS-1$
 		public static final String EXCEPTION = "EXCEPTION"; //$NON-NLS-1$
 		public static final String RAISE = "RAISE"; //$NON-NLS-1$
+		public static final String CHAIN = "CHAIN"; //$NON-NLS-1$
 	}
 	
 	public interface Reserved {

Modified: trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html	2012-09-25 18:58:05 UTC (rev 4471)
@@ -56,7 +56,6 @@
   <li>TEIID-2184 to be consistent with the rest of Teiid's logic the system functions dayName and monthName will return values from the default locale, rather than only the English names.  Use the system property org.teiid.enDateNames true to revert to the pre-8.2 behavior.
   <li>TEIID-2187 the CONSTRAINT keyword is not correctly used in table DDL.  It should be replaced with a comma from scripts to be compatible with 8.2.  If desired, 8.2 now supports the CONSTRAINT keyword to provide a name for each constraint.
   <li>TEIID-2181 system tables no longer contain valid OIDs.  That responsibility has moved to the pg_catalog.
-  <li>TEIID-1386 assignment statements and stored procedure invocations assigning a return value will no longer allow non-quoted non-reserved identifiers as left hand side variables.  The workaround is to use a quoted variable name if you are using a non-reserved word as a variable name.
   <li>TEIID-1386 the SQLState and errorCode reported by a TeiidSQLException will typically be from the top level nested SQLException.  If there is also a nested TeiidException, the TeiidSQLException.teiidCode will be set to the TeiidException.getCode value and the TeiidSQLException.errorCode will be set
   to the integer suffix of the teiidCode if possible.  
 </ul>

Modified: trunk/client/src/main/java/org/teiid/jdbc/TeiidSQLException.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/TeiidSQLException.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/client/src/main/java/org/teiid/jdbc/TeiidSQLException.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -102,7 +102,7 @@
 		if (exception instanceof SQLException) {
 			return new TeiidSQLException((SQLException) exception, message, true);
 		}
-		String sqlState = SQLStates.DEFAULT;
+		String sqlState = null;
 		int errorCode = 0;
 		SQLException se = ExceptionUtil.getExceptionOfType(exception, SQLException.class);
 		if (se != null && se.getSQLState() != null) {
@@ -125,8 +125,13 @@
 				}
 			}
 		}
-		exception = findRootException(exception);
-		sqlState = determineSQLState(exception, sqlState);
+		if (sqlState == null) {
+			exception = findRootException(exception);
+			sqlState = determineSQLState(exception, sqlState);
+		}
+		if (sqlState == null) {
+			sqlState = SQLStates.DEFAULT;
+		}
 		TeiidSQLException tse = new TeiidSQLException(origException, message, sqlState, errorCode);
 		tse.teiidCode = code;
 		return tse;

Modified: trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -59,7 +59,6 @@
 import org.teiid.core.types.basic.StringToSQLXMLTransform;
 import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.jdbc.TeiidSQLException;
-import org.teiid.jdbc.TeiidSQLWarning;
 import org.teiid.language.Like.MatchMode;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.function.FunctionDescriptor;
@@ -685,12 +684,7 @@
 		if (ee.getParent() != null) {
 			parent = (Exception) internalEvaluate(ee.getParent(), tuple);
 		}
-		Exception result = null;
-		if (ee.isWarning()) {
-			result = new TeiidSQLWarning(msg, sqlState, errorCode!=null?errorCode:0, parent);
-		} else {
-			result = new TeiidSQLException(parent, msg, sqlState, errorCode!=null?errorCode:0);
-		}
+		Exception result = new TeiidSQLException(parent, msg, sqlState, errorCode!=null?errorCode:0);
 		result.setStackTrace(SourceWarning.EMPTY_STACK_TRACE);
 		return result;
 	}

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/ProcedurePlanner.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/ProcedurePlanner.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/ProcedurePlanner.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -23,6 +23,7 @@
 package org.teiid.query.optimizer;
 
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.teiid.api.exception.query.QueryMetadataException;
@@ -132,7 +133,29 @@
         programBlock.setLabel(block.getLabel());
 
 		// plan each statement in the block
-        for (Statement statement : block.getStatements()) {
+        planStatements(parentProcCommand, block.getStatements(), metadata, debug, idGenerator,
+				capFinder, analysisRecord, context, programBlock);
+        
+        if (block.getExceptionGroup() != null) {
+        	programBlock.setExceptionGroup(block.getExceptionGroup());
+        	if (block.getExceptionStatements() != null) {
+        		Program exceptionBlock = new Program(false);
+                planStatements(parentProcCommand, block.getExceptionStatements(), metadata, debug, idGenerator,
+        				capFinder, analysisRecord, context, exceptionBlock);
+            	programBlock.setExceptionProgram(exceptionBlock);
+        	}
+        }
+
+        return programBlock;
+    }
+
+	private void planStatements(CreateProcedureCommand parentProcCommand,
+			List<Statement> stmts, QueryMetadataInterface metadata, boolean debug,
+			IDGenerator idGenerator, CapabilitiesFinder capFinder,
+			AnalysisRecord analysisRecord, CommandContext context,
+			Program programBlock) throws QueryPlannerException,
+			QueryMetadataException, TeiidComponentException {
+		for (Statement statement : stmts) {
 			Object instruction = planStatement(parentProcCommand, statement, metadata, debug, idGenerator, capFinder, analysisRecord, context);
             if(instruction instanceof ProgramInstruction){
                 programBlock.addInstruction((ProgramInstruction)instruction);
@@ -144,10 +167,8 @@
                 }
             }
         }
+	}
 
-        return programBlock;
-    }
-
 	/**
 	 * <p> Plan a {@link Statement} object, depending on the type of the statement construct the appropriate
 	 * {@link ProgramInstruction} return it to added to a {@link Program}. If the statement references a
@@ -198,8 +219,9 @@
                 
 				Expression asigExpr = res.getExpression();
 				error.setExpression(asigExpr);
+				error.setWarning(res.isWarning());
                 if(debug) {
-                	analysisRecord.println("\tERROR STATEMENT:\n" + statement); //$NON-NLS-1$ 
+                	analysisRecord.println("\tRAISE STATEMENT:\n" + statement); //$NON-NLS-1$ 
                 }
             	break;
             }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/CreateCursorResultSetInstruction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/CreateCursorResultSetInstruction.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/CreateCursorResultSetInstruction.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -26,7 +26,6 @@
 
 import static org.teiid.query.analysis.AnalysisRecord.*;
 
-import java.util.List;
 import java.util.Map;
 
 import org.teiid.client.plan.PlanNode;
@@ -104,9 +103,4 @@
         return plan;
     }
     
-    @Override
-    public void getChildPlans(List<ProcessorPlan> plans) {
-    	plans.add(this.plan);
-    }
-
 }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/ErrorInstruction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/ErrorInstruction.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/ErrorInstruction.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -24,14 +24,11 @@
 
 import static org.teiid.query.analysis.AnalysisRecord.*;
 
-import java.sql.SQLWarning;
-
-import org.teiid.client.ProcedureErrorInstructionException;
 import org.teiid.client.plan.PlanNode;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
+import org.teiid.jdbc.TeiidSQLException;
 import org.teiid.logging.LogManager;
-import org.teiid.query.QueryPlugin;
 import org.teiid.query.sql.symbol.Expression;
 
 
@@ -42,6 +39,7 @@
 public class ErrorInstruction extends ProgramInstruction {
 	
     private Expression expression;
+    private boolean warning;
     
 	/**
 	 * Constructor for DeclareInstruction.
@@ -52,6 +50,10 @@
 	public void setExpression(Expression expression) {
 		this.expression = expression;
 	}
+	
+	public void setWarning(boolean warning) {
+		this.warning = warning;
+	}
     
     /** 
      * @see org.teiid.query.processor.proc.ProgramInstruction#clone()
@@ -59,29 +61,33 @@
     public ErrorInstruction clone() {
         ErrorInstruction clone = new ErrorInstruction();
         clone.expression = expression;
+        clone.warning = warning;
         return clone;
     }
 	    
     public String toString() {
-        return "RAISE ERROR INSTRUCTION: " + expression; //$NON-NLS-1$
+        return "RAISE " + (warning?"WARNING":"ERROR") +" INSTRUCTION: " + expression; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
     }  
     
     public PlanNode getDescriptionProperties() {
-    	PlanNode node = new PlanNode("RAISE ERROR"); //$NON-NLS-1$
+    	PlanNode node = new PlanNode("RAISE " + (warning?"WARNING":"ERROR")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
     	node.addProperty(PROP_EXPRESSION, this.expression.toString());
     	return node;
     }
     
     @Override
     public void process(ProcedurePlan env) throws TeiidComponentException,
-    		TeiidProcessingException {
+    		TeiidProcessingException, TeiidSQLException {
     	Object value = env.evaluateExpression(expression);
-        LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Processing ErrorInstruction with the value :", value); //$NON-NLS-1$ 
-    	if (value instanceof SQLWarning) {
-    		env.getContext().addWarning((Exception)value);
-    		return;
-    	}
-        throw new ProcedureErrorInstructionException(QueryPlugin.Event.TEIID30167, (Exception) value); 
+        LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Processing RAISE with the value :", value); //$NON-NLS-1$
+        if (warning) {
+        	env.getContext().addWarning((Exception)value);
+        	return;
+        }
+        if (value == null) {
+        	throw new TeiidProcessingException();
+        }
+        throw TeiidSQLException.create((Exception)value);
     }
  
 }
\ No newline at end of file

Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/IfInstruction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/IfInstruction.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/IfInstruction.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -24,14 +24,11 @@
 
 import static org.teiid.query.analysis.AnalysisRecord.*;
 
-import java.util.List;
-
 import org.teiid.client.plan.PlanNode;
 import org.teiid.common.buffer.BlockedException;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
 import org.teiid.logging.LogManager;
-import org.teiid.query.processor.ProcessorPlan;
 import org.teiid.query.sql.lang.Criteria;
 
 
@@ -118,10 +115,10 @@
      * Returns a deep clone
      */
     public IfInstruction clone(){
-    	Program cloneIf = (Program) this.ifProgram.clone();
+    	Program cloneIf = this.ifProgram.clone();
     	Program cloneElse = null;
     	if(elseProgram != null) {
-    		cloneElse = (Program) this.elseProgram.clone();
+    		cloneElse = this.elseProgram.clone();
     	}
         IfInstruction clone = new IfInstruction(this.condition, cloneIf, cloneElse);
         return clone;
@@ -141,12 +138,4 @@
         return props;
     }
     
-    @Override
-    public void getChildPlans(List<ProcessorPlan> plans) {
-    	ifProgram.getChildPlans(plans);
-    	if (elseProgram != null) {
-    		elseProgram.getChildPlans(plans);
-    	}
-    }
-    
 }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/LoopInstruction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/LoopInstruction.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/LoopInstruction.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -122,10 +122,4 @@
         procEnv.removeResults(rsName);
     }
     
-    @Override
-    public void getChildPlans(List<ProcessorPlan> plans) {
-    	super.getChildPlans(plans);
-    	this.loopProgram.getChildPlans(plans);
-    }
-
 }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -37,6 +37,7 @@
 
 import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.api.exception.query.QueryValidatorException;
+import org.teiid.client.ProcedureErrorInstructionException;
 import org.teiid.client.plan.PlanNode;
 import org.teiid.client.xa.XATransactionException;
 import org.teiid.common.buffer.BlockedException;
@@ -56,6 +57,7 @@
 import org.teiid.dqp.service.TransactionService;
 import org.teiid.dqp.service.TransactionContext.Scope;
 import org.teiid.events.EventDistributor;
+import org.teiid.jdbc.TeiidSQLException;
 import org.teiid.logging.LogConstants;
 import org.teiid.logging.LogManager;
 import org.teiid.query.QueryPlugin;
@@ -69,11 +71,13 @@
 import org.teiid.query.processor.QueryProcessor;
 import org.teiid.query.processor.RegisterRequestParameter;
 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.Command;
 import org.teiid.query.sql.lang.Criteria;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
+import org.teiid.query.sql.symbol.GroupSymbol;
 import org.teiid.query.sql.util.VariableContext;
 import org.teiid.query.tempdata.TempTableStore;
 import org.teiid.query.util.CommandContext;
@@ -357,21 +361,61 @@
                 this.pop(true);
                 continue;
             }
-            if (inst instanceof RepeatedInstruction) {
-    	        LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Executing repeated instruction", inst); //$NON-NLS-1$
-                RepeatedInstruction loop = (RepeatedInstruction)inst;
-                if (loop.testCondition(this)) {
-                    LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Passed condition, executing program " + loop.getNestedProgram()); //$NON-NLS-1$
-                    inst.process(this);
-                    this.push(loop.getNestedProgram());
-                    continue;
-                }
-                LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Exiting repeated instruction", inst); //$NON-NLS-1$
-                loop.postInstruction(this);
-            } else {
-            	LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Executing instruction", inst); //$NON-NLS-1$
-                inst.process(this);
-            }
+	        try {
+	            if (inst instanceof RepeatedInstruction) {
+	    	        LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Executing repeated instruction", inst); //$NON-NLS-1$
+	                RepeatedInstruction loop = (RepeatedInstruction)inst;
+	                if (loop.testCondition(this)) {
+	                    LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Passed condition, executing program " + loop.getNestedProgram()); //$NON-NLS-1$
+	                    inst.process(this);
+	                    this.push(loop.getNestedProgram());
+	                    continue;
+	                }
+	                LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Exiting repeated instruction", inst); //$NON-NLS-1$
+	                loop.postInstruction(this);
+	            } else {
+	            	LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Executing instruction", inst); //$NON-NLS-1$
+	                inst.process(this);
+	            }
+	        } catch (Exception e) {
+	        	if (e instanceof BlockedException) {
+	        		throw (BlockedException)e;
+	        	}
+	        	while (program.getExceptionGroup() == null) {
+        			this.pop(false);
+	        		if (this.programs.empty()) {
+	        			//reached the top without a handler, so throw
+        				if (e instanceof RuntimeException) {
+    	        			throw (RuntimeException)e;
+    	        		}
+    	        		if (e instanceof TeiidComponentException) {
+    	        			throw (TeiidComponentException)e;
+    	        		}
+    	        		if (e instanceof TeiidProcessingException) {
+    	        			throw (TeiidProcessingException)e;
+    	        		}
+    	        		throw new ProcedureErrorInstructionException(QueryPlugin.Event.TEIID30167, e);
+	        		}
+        			program = peek();
+	        	}
+        		//assign variables
+        		if (program.getExceptionProgram() == null) {
+        			this.pop(true);
+        			continue;
+        		}
+	        	Program exceptionProgram = program.getExceptionProgram();
+	        	exceptionProgram.setStartedTxn(program.startedTxn());
+    			this.pop(null); //all the current program to go out of scope
+				this.push(exceptionProgram);	
+				TeiidSQLException tse = TeiidSQLException.create(e);
+				GroupSymbol gs = new GroupSymbol(program.getExceptionGroup());
+				this.currentVarContext.setValue(exceptionSymbol(gs, 0), tse.getSQLState());
+				this.currentVarContext.setValue(exceptionSymbol(gs, 1), tse.getErrorCode());
+				this.currentVarContext.setValue(exceptionSymbol(gs, 2), tse.getTeiidCode());
+				this.currentVarContext.setValue(exceptionSymbol(gs, 3), tse);
+				this.currentVarContext.setValue(exceptionSymbol(gs, 4), tse.getCause());
+				continue;
+	        }
             program.incrementProgramCounter();
 	    }
 
@@ -381,6 +425,12 @@
         return lastTupleSource;
     }
 
+	private ElementSymbol exceptionSymbol(GroupSymbol gs, int pos) {
+		ElementSymbol es = UpdateProcedureResolver.exceptionGroup.get(pos).clone();
+		es.setGroupSymbol(gs);
+		return es;
+	}
+
     public void close()
         throws TeiidComponentException {
         if (!this.cursorStates.isEmpty()) {
@@ -409,7 +459,7 @@
     }
 
 	public ProcessorPlan clone(){
-        ProcedurePlan plan = new ProcedurePlan((Program)originalProgram.clone());
+        ProcedurePlan plan = new ProcedurePlan(originalProgram.clone());
         plan.setOutputElements(this.getOutputElements());
         plan.setParams(params);
         plan.setOutParams(outParams);
@@ -565,13 +615,13 @@
      * @throws TeiidComponentException 
      * @throws XATransactionException 
      */
-    public void pop(boolean success) throws TeiidComponentException {
+    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();
-    	if (program.startedTxn() && this.blockContext != null) {
+    	if (success != null && program.startedTxn() && this.blockContext != null) {
     		TransactionService ts = this.getContext().getTransactionServer();
     		TransactionContext tc = this.blockContext;
     		this.blockContext = null;

Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/Program.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/Program.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/Program.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -26,7 +26,6 @@
 import java.util.List;
 
 import org.teiid.client.plan.PlanNode;
-import org.teiid.query.processor.ProcessorPlan;
 import org.teiid.query.sql.proc.Statement.Labeled;
 import org.teiid.query.tempdata.TempTableStore;
 import org.teiid.query.tempdata.TempTableStore.TransactionMode;
@@ -45,6 +44,8 @@
     private String label;
     private TempTableStore tempTables;
     private boolean startedTxn;
+    private String exceptionGroup;
+    private Program exceptionProgram;
 
 	/**
 	 * Constructor for Program.
@@ -149,7 +150,7 @@
     /**
      * Produces a deep clone.
      */
-    public Object clone(){
+    public Program clone(){
         Program program = new Program(atomic);
         program.counter = this.counter;
         
@@ -161,12 +162,18 @@
             program.programInstructions = clonedInstructions;
         }
         program.label = label;
+        program.exceptionGroup = this.exceptionGroup;
+        if (this.exceptionProgram != null) {
+        	program.exceptionProgram = this.exceptionProgram.clone();
+        }
         return program;
     }
 
     public PlanNode getDescriptionProperties() {
     	PlanNode props = new PlanNode("Program"); //$NON-NLS-1$
-        
+        if (label != null) {
+        	props.addProperty("Label", label); //$NON-NLS-1$
+        }
         if(this.programInstructions != null) {
         	for (int i = 0; i < programInstructions.size(); i++) {
                 ProgramInstruction inst = programInstructions.get(i);
@@ -174,6 +181,13 @@
                 props.addProperty("Instruction " + i, childProps); //$NON-NLS-1$
             }
         }
+        
+        if (this.exceptionGroup != null) {
+        	props.addProperty("EXCEPTION GROUP", this.exceptionGroup); //$NON-NLS-1$
+        	if (this.exceptionProgram != null) {
+        		props.addProperty("EXCEPTION HANDLER", this.exceptionProgram.getDescriptionProperties()); //$NON-NLS-1$
+        	}
+        }
         return props;
     }
     
@@ -207,7 +221,12 @@
         StringBuilder str = new StringBuilder();   
             
         programToString(str);
-        
+        if (exceptionGroup != null) {
+        	str.append("\nEXCEPTION ").append(exceptionGroup).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (exceptionProgram != null) {
+        	exceptionProgram.programToString(str);
+        }
         return "PROGRAM counter " + this.counter + "\n" + str.toString(); //$NON-NLS-1$ //$NON-NLS-2$ 
     }
 
@@ -248,11 +267,21 @@
         
         buffer.append(counterStr + line + "\n"); //$NON-NLS-1$
     }
-    
-    void getChildPlans(List<ProcessorPlan> plans) {
-    	for (ProgramInstruction instruction : programInstructions) {
-			instruction.getChildPlans(plans);
-		}
-    }
+     
+	public void setExceptionGroup(String exceptionGroup) {
+		this.exceptionGroup = exceptionGroup;
+	}
+
+	public void setExceptionProgram(Program exceptionBlock) {
+		this.exceptionProgram = exceptionBlock;
+	}
+	
+	public String getExceptionGroup() {
+		return exceptionGroup;
+	}
+	
+	public Program getExceptionProgram() {
+		return exceptionProgram;
+	}
         
 }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/ProgramInstruction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/ProgramInstruction.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/ProgramInstruction.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -22,12 +22,10 @@
 
 package org.teiid.query.processor.proc;
 
-import java.util.List;
-
 import org.teiid.client.plan.PlanNode;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
-import org.teiid.query.processor.ProcessorPlan;
+import org.teiid.jdbc.TeiidSQLException;
 
 
 /**
@@ -50,19 +48,12 @@
      * in turn manipulate the running program. A typical instruction should simply {@link
      * Program#incrementProgramCounter increment} the program counter of the current program, but specialized
      * instructions may add sub programs to the stack or not increment the counter (so that they are executed again.)
+     * @throws TeiidSQLException 
      */
     public abstract void process(ProcedurePlan env) 
-        throws TeiidComponentException, TeiidProcessingException;
+        throws TeiidComponentException, TeiidProcessingException, TeiidSQLException;
         
     /**
-     * Finds all nested plans and returns them.
-     * @return List of ProcessorPlan 
-     * @since 4.2
-     */
-    public void getChildPlans(List<ProcessorPlan> plans) {
-    }
-    
-    /**
      * Override Object.clone() to make the method public.  This method 
      * simply calls super.clone(), deferring to the default shallow
      * cloning.  Some ProcessorInstruction subclasses may need to 

Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/WhileInstruction.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/WhileInstruction.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/WhileInstruction.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -26,12 +26,9 @@
 
 import static org.teiid.query.analysis.AnalysisRecord.*;
 
-import java.util.List;
-
 import org.teiid.client.plan.PlanNode;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
-import org.teiid.query.processor.ProcessorPlan;
 import org.teiid.query.sql.lang.Criteria;
 
 
@@ -73,7 +70,7 @@
      * Returns a deep clone
      */
     public WhileInstruction clone(){
-        return new WhileInstruction((Program)this.whileProgram.clone(), this.condition, this.label);
+        return new WhileInstruction(this.whileProgram.clone(), this.condition, this.label);
     }
 
     public String toString() {
@@ -104,9 +101,4 @@
     public void postInstruction(ProcedurePlan procEnv) throws TeiidComponentException {
     }
     
-    @Override
-    public void getChildPlans(List<ProcessorPlan> plans) {
-    	whileProgram.getChildPlans(plans);
-    }
-    
 }

Modified: trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -35,6 +35,7 @@
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.types.DataTypeManager;
 import org.teiid.language.SQLConstants;
+import org.teiid.language.SQLConstants.NonReserved;
 import org.teiid.logging.LogManager;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.metadata.SupportConstants;
@@ -71,6 +72,21 @@
 		List<StatementNode> children;
 	}
 	
+	public static final List<ElementSymbol> exceptionGroup;
+	static {
+		ElementSymbol es1 = new ElementSymbol("STATE"); //$NON-NLS-1$
+        es1.setType(DataTypeManager.DefaultDataClasses.STRING);
+        ElementSymbol es2 = new ElementSymbol("ERRORCODE"); //$NON-NLS-1$
+        es2.setType(DataTypeManager.DefaultDataClasses.INTEGER);
+        ElementSymbol es3 = new ElementSymbol("TEIIDCODE"); //$NON-NLS-1$
+        es3.setType(DataTypeManager.DefaultDataClasses.STRING);
+        ElementSymbol es4 = new ElementSymbol(NonReserved.EXCEPTION);
+        es4.setType(Exception.class);
+        ElementSymbol es5 = new ElementSymbol(NonReserved.CHAIN);
+        es5.setType(Exception.class);
+        exceptionGroup = Arrays.asList(es1, es2, es3, es4, es5);
+	}
+	
     /**
      * @see org.teiid.query.resolver.CommandResolver#resolveCommand(org.teiid.query.sql.lang.Command, TempMetadataAdapter, boolean)
      */
@@ -145,6 +161,24 @@
         for (Statement statement : block.getStatements()) {
             resolveStatement(command, statement, externalGroups, variables, metadata, sn);
         }
+        
+        if (block.getExceptionGroup() != null) {
+            //create a new variable and metadata context for this block so that discovered metadata is not visible else where
+        	store = metadata.getMetadataStore().clone();
+            metadata = new TempMetadataAdapter(metadata.getMetadata(), store);
+            externalGroups = new GroupContext(externalGroups, null);
+            
+            //create a new variables group for this block
+            variables = ProcedureContainerResolver.addScalarGroup(ProcedureReservedWords.VARIABLES, store, externalGroups, new LinkedList<Expression>());
+            isValidGroup(metadata, block.getExceptionGroup());
+            
+            if (block.getExceptionStatements() != null) {
+            	ProcedureContainerResolver.addScalarGroup(block.getExceptionGroup(), store, externalGroups, exceptionGroup, false);
+	            for (Statement statement : block.getExceptionStatements()) {
+	                resolveStatement(command, statement, externalGroups, variables, metadata, sn);
+	            }
+            }
+        }
     }
 
 	private void resolveStatement(CreateProcedureCommand command, Statement statement, GroupContext externalGroups, GroupSymbol variables, TempMetadataAdapter metadata, StatementNode sn)
@@ -208,12 +242,7 @@
                 //this could be the last select statement, set the projected symbol
                 //on the virtual procedure command
                 if (subCommand.returnsResultSet() && sn != null) {
-                	updateDynamicAs(sn);
-                    
-            		sn.cs = cmdStmt;
-            		if (sn.children != null) {
-            			sn.children.clear();
-            		}
+                	clearReturnableStatement(sn, cmdStmt);
                 }
 
                 break;
@@ -254,6 +283,9 @@
 	        		exprStmt.setExpression(ResolverUtil.convertExpression(exprStmt.getExpression(), varTypeName, metadata));     
 	        		if (statement.getType() == Statement.TYPE_ERROR) {
 	        			ResolverVisitor.checkException(exprStmt.getExpression());
+	        			if (!((RaiseStatement)statement).isWarning()) {
+	        				clearReturnableStatement(sn, null);
+	        			}
 	        		}
                 }
                 break;
@@ -270,15 +302,7 @@
                 LoopStatement loopStmt = (LoopStatement) statement;
                 String groupName = loopStmt.getCursorName();
 
-                if (metadata.getMetadataStore().getTempGroupID(groupName) != null) {
-                     throw new QueryResolverException(QueryPlugin.Event.TEIID30124, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30124));
-                }
-                
-	        	//check - cursor name should not start with #
-	        	if(GroupSymbol.isTempGroupName(loopStmt.getCursorName())){
-	        		String errorMsg = QueryPlugin.Util.getString("ResolveVariablesVisitor.reserved_word_for_temporary_used", loopStmt.getCursorName()); //$NON-NLS-1$
-	        		 throw new QueryResolverException(QueryPlugin.Event.TEIID30125, errorMsg);
-	        	}
+                isValidGroup(metadata, groupName);
                 Command cmd = loopStmt.getCommand();
                 resolveEmbeddedCommand(metadata, externalGroups, cmd);
                 List<Expression> symbols = cmd.getProjectedSymbols();
@@ -295,6 +319,28 @@
         }
     }
 
+	private void clearReturnableStatement(StatementNode sn,
+			CommandStatement cmdStmt) {
+		updateDynamicAs(sn);
+		
+		sn.cs = cmdStmt;
+		if (sn.children != null) {
+			sn.children.clear();
+		}
+	}
+
+	private void isValidGroup(TempMetadataAdapter metadata, String groupName)
+			throws QueryResolverException {
+		if (metadata.getMetadataStore().getTempGroupID(groupName) != null) {
+		     throw new QueryResolverException(QueryPlugin.Event.TEIID30124, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30124, groupName));
+		}
+		
+		//check - cursor name should not start with #
+		if(GroupSymbol.isTempGroupName(groupName)){
+			 throw new QueryResolverException(QueryPlugin.Event.TEIID30125, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30125, groupName));
+		}
+	}
+
 	private void updateDynamicAs(StatementNode sn) {
 		if (sn.cs != null && sn.cs.getCommand().getType() == Command.TYPE_DYNAMIC) {
 		    DynamicCommand dynamicCommand = (DynamicCommand)sn.cs.getCommand();

Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -242,20 +242,27 @@
 	private Block rewriteBlock(Block block)
 								 throws TeiidComponentException, TeiidProcessingException{
 		List<Statement> statements = block.getStatements();
-        Iterator<Statement> stmtIter = statements.iterator();
+        List<Statement> newStmts = rewriteStatements(statements);
+        block.setStatements(newStmts);
+        if (block.getExceptionStatements() != null) {
+            block.setExceptionStatements(rewriteStatements(block.getExceptionStatements()));
+        }
+        return block;
+	 }
 
+	private List<Statement> rewriteStatements(List<Statement> statements)
+			throws TeiidComponentException, TeiidProcessingException {
+		Iterator<Statement> stmtIter = statements.iterator();
+
 		List<Statement> newStmts = new ArrayList<Statement>(statements.size());
 		// plan each statement in the block
         while(stmtIter.hasNext()) {
 			Statement stmnt = stmtIter.next();
 			rewriteStatement(stmnt, newStmts);
         }
+		return newStmts;
+	}
 
-        block.setStatements(newStmts);
-
-        return block;
-	 }
-
 	private void rewriteStatement(Statement statement, List<Statement> newStmts)
 								 throws TeiidComponentException, TeiidProcessingException{
 

Modified: trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -103,6 +103,7 @@
     public void visit(Block obj) {
         preVisitVisitor(obj);
         visitNodes(obj.getStatements());
+        visitNodes(obj.getExceptionStatements());
         postVisitVisitor(obj);
     }
     public void visit(BranchingStatement obj) {

Modified: trunk/engine/src/main/java/org/teiid/query/sql/proc/Block.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/proc/Block.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/sql/proc/Block.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -27,6 +27,7 @@
 
 import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.core.util.StringUtil;
+import org.teiid.query.sql.LanguageObject;
 import org.teiid.query.sql.LanguageVisitor;
 import org.teiid.query.sql.ProcedureReservedWords;
 import org.teiid.query.sql.lang.Command;
@@ -46,6 +47,9 @@
 	private List<Statement> statements;
 	private boolean atomic;
 	private String label;
+	
+	private String exceptionGroup;
+	private List<Statement> exceptionStatements;
 
 	/**
 	 * Constructor for Block.
@@ -92,11 +96,15 @@
 	 * @param statement The <code>Statement</code> to be added to the block
 	 */
 	public void addStatement(Statement statement) {
+		addStatement(statement, false);
+	}
+	
+	public void addStatement(Statement statement, boolean exception) {
 		if (statement instanceof AssignmentStatement) {
 			AssignmentStatement stmt = (AssignmentStatement)statement;
 			Command cmd = stmt.getCommand();
 			if (cmd != null) {
-				statements.add(new CommandStatement(cmd));
+				internalAddStatement(new CommandStatement(cmd), exception);
 				stmt.setCommand(null);
 				stmt.setExpression(null);
 				if (stmt.getVariable().getShortName().equalsIgnoreCase(ProcedureReservedWords.ROWCOUNT) 
@@ -107,8 +115,19 @@
 				stmt.setExpression(new ElementSymbol(fullName));
 			}
 		}
-		statements.add(statement);
+		internalAddStatement(statement, exception);
 	}
+
+	private void internalAddStatement(Statement statement, boolean exception) {
+		if (exception) {
+			if (this.exceptionStatements == null) {
+				exceptionStatements = new ArrayList<Statement>();
+			}
+			exceptionStatements.add(statement);
+		} else {
+			statements.add(statement);
+		}
+	}
 	
     // =========================================================================
     //                  P R O C E S S I N G     M E T H O D S
@@ -125,9 +144,11 @@
 	public Block clone() {		
 		Block copy = new Block();
 		copy.setAtomic(atomic);
-		for (Statement statement : statements) {
-			copy.addStatement((Statement)statement.clone());
+		copy.statements = LanguageObject.Util.deepClone(statements, Statement.class);
+		if (exceptionStatements != null) {
+			copy.exceptionStatements = LanguageObject.Util.deepClone(exceptionStatements, Statement.class);
 		}
+		copy.exceptionGroup = this.exceptionGroup;
 		copy.setLabel(label);
 		return copy;
 	}
@@ -154,7 +175,9 @@
 		// Compare the statements on the block
         return this.atomic == other.atomic 
         && StringUtil.equalsIgnoreCase(label, other.label)
-        && EquivalenceUtil.areEqual(getStatements(), other.getStatements());
+        && EquivalenceUtil.areEqual(getStatements(), other.getStatements())
+        && EquivalenceUtil.areEqual(exceptionGroup, exceptionGroup)
+        && EquivalenceUtil.areEqual(exceptionStatements, exceptionStatements);
     }    
 
     /**
@@ -188,5 +211,21 @@
     public int getType() {
     	return Statement.TYPE_COMPOUND;
     }
+    
+    public String getExceptionGroup() {
+		return exceptionGroup;
+	}
+    
+    public void setExceptionGroup(String exceptionGroup) {
+		this.exceptionGroup = exceptionGroup;
+	}
+    
+    public List<Statement> getExceptionStatements() {
+		return exceptionStatements;
+	}
+    
+    public void setExceptionStatements(List<Statement> exceptionStatements) {
+		this.exceptionStatements = exceptionStatements;
+	}
 
 }// END CLASS

Modified: trunk/engine/src/main/java/org/teiid/query/sql/proc/ExceptionExpression.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/proc/ExceptionExpression.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/sql/proc/ExceptionExpression.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -36,7 +36,6 @@
 	private Expression sqlState;
 	private Expression errorCode;
 	private Expression parent;
-	private boolean warning;
 	
 	@Override
 	public Class<?> getType() {
@@ -58,13 +57,12 @@
 		return EquivalenceUtil.areEqual(message, other.message) 
 		&& EquivalenceUtil.areEqual(sqlState, other.sqlState)
 		&& EquivalenceUtil.areEqual(errorCode, other.errorCode)
-		&& EquivalenceUtil.areEqual(parent, other.parent)
-		&& warning == other.warning;
+		&& EquivalenceUtil.areEqual(parent, other.parent);
 	}
 	
 	@Override
 	public int hashCode() {
-		return HashCodeUtil.hashCode(warning?0:1, message, sqlState, errorCode);
+		return HashCodeUtil.hashCode(0, message, sqlState, errorCode);
 	}
 	
 	@Override
@@ -75,7 +73,6 @@
 	@Override
 	public ExceptionExpression clone() {
 		ExceptionExpression clone = new ExceptionExpression();
-		clone.warning = this.warning;
 		if (this.message != null) {
 			clone.message = (Expression) this.message.clone();
 		}
@@ -123,23 +120,12 @@
 		this.parent = parent;
 	}
 	
-	public boolean isWarning() {
-		return warning;
-	}
-	
-	public void setWarning(boolean warning) {
-		this.warning = warning;
-	}
-
 	@Override
 	public void acceptVisitor(LanguageVisitor visitor) {
 		visitor.visit(this);
 	}
 
 	public String getDefaultSQLState() {
-		if (isWarning()) {
-			return "01000";
-		}
 		return "50001";
 	}
 

Modified: trunk/engine/src/main/java/org/teiid/query/sql/proc/RaiseStatement.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/proc/RaiseStatement.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/sql/proc/RaiseStatement.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -35,6 +35,7 @@
 public class RaiseStatement extends Statement implements ExpressionStatement {
 	
 	private Expression expression;
+	private boolean warning;
 
 	public RaiseStatement() {
 	}
@@ -46,6 +47,11 @@
 	public RaiseStatement(Expression message) {
 		expression = message;
 	}
+	
+	public RaiseStatement(Expression message, boolean warning) {
+		expression = message;
+		this.warning = warning;
+	}
         
     public void acceptVisitor(LanguageVisitor visitor) {
         visitor.visit(this);
@@ -65,7 +71,7 @@
 
 	@Override
 	public RaiseStatement clone() {
-		return new RaiseStatement((Expression) this.expression.clone());
+		return new RaiseStatement((Expression) this.expression.clone(), warning);
 	}
 	
 	@Override
@@ -84,12 +90,20 @@
 		
 		RaiseStatement other = (RaiseStatement)obj;
 		
-		return other.expression.equals(this.expression);
+		return other.expression.equals(this.expression) && this.warning == other.warning;
 	}
 	
 	@Override
 	public Class<?> getExpectedType() {
 		return DataTypeManager.DefaultDataClasses.OBJECT;
 	}
+	
+	public boolean isWarning() {
+		return warning;
+	}
+	
+	public void setWarning(boolean warning) {
+		this.warning = warning;
+	}
     
 } // END CLASS
\ No newline at end of file

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -47,6 +47,7 @@
 import org.teiid.query.sql.lang.TextTable.TextColumn;
 import org.teiid.query.sql.lang.XMLTable.XMLColumn;
 import org.teiid.query.sql.proc.*;
+import org.teiid.query.sql.proc.BranchingStatement.BranchingMode;
 import org.teiid.query.sql.proc.Statement.Labeled;
 import org.teiid.query.sql.symbol.*;
 import org.teiid.query.sql.symbol.AggregateSymbol.Type;
@@ -1376,7 +1377,21 @@
         	append(ATOMIC);
         }
         append("\n"); //$NON-NLS-1$
-        Iterator<Statement> stmtIter = statements.iterator();
+        addStatements(statements);
+        if (obj.getExceptionGroup() != null) {
+        	append(NonReserved.EXCEPTION);
+        	append(SPACE);
+        	outputDisplayName(obj.getExceptionGroup());
+        	append("\n"); //$NON-NLS-1$
+        	if (obj.getExceptionStatements() != null) {
+        		addStatements(obj.getExceptionStatements());
+        	}
+        }
+        append(END);
+    }
+
+	private void addStatements(List<Statement> statements) {
+		Iterator<Statement> stmtIter = statements.iterator();
         while (stmtIter.hasNext()) {
             // Add each statement
             addTabs(1);
@@ -1384,8 +1399,7 @@
             append("\n"); //$NON-NLS-1$
         }
         addTabs(0);
-        append(END);
-    }
+	}
 
 	private void addLabel(Labeled obj) {
 		if (obj.getLabel() != null) {
@@ -1464,17 +1478,17 @@
     public void visit( RaiseStatement obj ) {
         append(NonReserved.RAISE);
         append(SPACE);
+        if (obj.isWarning()) {
+        	append(SQLWARNING);
+            append(SPACE);
+        }
         visitNode(obj.getExpression());
         append(";"); //$NON-NLS-1$
     }
     
     @Override
     public void visit(ExceptionExpression exceptionExpression) {
-    	if (exceptionExpression.isWarning()) {
-    		append(SQLWARNING);
-    	} else {
-    		append(SQLEXCEPTION);
-    	}
+		append(SQLEXCEPTION);
     	append(SPACE);
     	visitNode(exceptionExpression.getMessage());
     	if (exceptionExpression.getSqlState() != null) {
@@ -1490,7 +1504,7 @@
     	}
     	if (exceptionExpression.getParent() != null) {
         	append(SPACE);
-        	append(NonReserved.EXCEPTION);
+        	append(NonReserved.CHAIN);
         	append(SPACE);
         	append(exceptionExpression.getParent());
     	}
@@ -1525,7 +1539,7 @@
         append(") "); //$NON-NLS-1$
         append(AS);
         append(" "); //$NON-NLS-1$
-        append(obj.getCursorName());
+        outputDisplayName(obj.getCursorName());
         append("\n"); //$NON-NLS-1$
         addTabs(0);
         visitNode(obj.getBlock());

Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2012-09-25 18:58:05 UTC (rev 4471)
@@ -457,6 +457,7 @@
 |   <VARIADIC: "variadic">
 |   <EXCEPTION: "exception">
 |   <RAISE: "raise">
+|   <CHAIN: "chain">
 
 }
 /*
@@ -564,7 +565,7 @@
      |<TO_BYTES>|<TIMESTAMPADD>|<TIMESTAMPDIFF>|<QUERYSTRING>|<NAMESPACE>|<RESULT>|<INDEX>|<ACCESSPATTERN>|<AUTO_INCREMENT>|<WELLFORMED>|<SQL_TSI_FRAC_SECOND>
      |<SQL_TSI_SECOND>|<SQL_TSI_MINUTE>|<SQL_TSI_HOUR>|<SQL_TSI_DAY>|<SQL_TSI_WEEK>|<SQL_TSI_MONTH>|<SQL_TSI_QUARTER>|<SQL_TSI_YEAR>|<TEXTTABLE>|<ARRAYTABLE>
      |<SELECTOR>|<SKIP_KEYWORD>|<WIDTH>|<PASSING>|<NAME>|<ENCODING>|<COLUMNS>|<DELIMITER>|<QUOTE>|<HEADER>|<NULLS>|<OBJECTTABLE>
-     |<VERSION>|<INCLUDING>|<EXCLUDING>|<XMLDECLARATION>|<VARIADIC>|<RAISE>|<EXCEPTION>)
+     |<VERSION>|<INCLUDING>|<EXCLUDING>|<XMLDECLARATION>|<VARIADIC>|<RAISE>|<EXCEPTION>|<CHAIN>)
     {
     	return getToken(0);
     }	
@@ -910,12 +911,14 @@
 RaiseStatement raiseStatement(ParseInfo info) :
 {
     Expression err = null;
+    boolean warning = false;
 }
 { 
     <RAISE>
+    [<SQLWARNING> {warning = true;}]
     err = exceptionReference(info)
     {
-        return new RaiseStatement(err);       
+        return new RaiseStatement(err, warning);       
     }
 }
 
@@ -949,22 +952,20 @@
 	Expression sqlState = null;
 	Expression errCode = null;
 	Expression parent = null;
-	boolean warning = false;
 }
 {
-    (<SQLWARNING> {warning=true;}|<SQLEXCEPTION>)
+    <SQLEXCEPTION>
 	err = commonValueExpression(info)
 	[<SQLSTATE> sqlState = commonValueExpression(info)
      [<COMMA> errCode = commonValueExpression(info)]
     ]
-    [<EXCEPTION> parent = exceptionReference(info)]
+    [<CHAIN> parent = exceptionReference(info)]
 	{
 		ExceptionExpression ee = new ExceptionExpression();
 		ee.setMessage(err);
 		ee.setSqlState(sqlState);
 		ee.setErrorCode(errCode);
 		ee.setParent(parent);
-		ee.setWarning(warning);
 		return ee;
 	}	
 }
@@ -1013,7 +1014,7 @@
     Statement stmt = null;
 }           
 {
-     (stmt = assignStatement(info) |
+     (LOOKAHEAD(2) stmt = assignStatement(info) |
 	  stmt = sqlStatement(info) |
       stmt = errorStatement(info) |
       stmt = raiseStatement(info) |
@@ -1036,15 +1037,24 @@
     Statement stmt = null;  
     Block block = new Block();
     Boolean atomic = null;
+    String eId = null;
 }
 {   
     <BEGIN> [[<NOT> {atomic = Boolean.FALSE;}] <ATOMIC> {if (atomic == null) {atomic = Boolean.TRUE;}}]
-    (
+    (LOOKAHEAD(2)
       stmt = statement(info)
       {          
-	    block.addStatement(stmt);            	                	    
+	    block.addStatement(stmt, false);            	                	    
 	  }
  	)*
+ 	[<EXCEPTION> eId = id() {block.setExceptionGroup(validateAlias(eId));}
+ 	 (
+       stmt = statement(info)
+       {          
+	     block.addStatement(stmt, true);            	                	    
+	   }
+ 	 )*
+ 	]
     <END>
     {
         if (atomic != null) {
@@ -1200,13 +1210,13 @@
 Statement assignStatement(ParseInfo info) :
 {
     LanguageObject value = null;
-    Token var = null;
+    String var = null;
     ElementSymbol elementID = null;
 }
 {
-    var = <ID>
+    var = id()
     {
-        elementID = new ElementSymbol(normalizeId(var.image));              
+        elementID = new ElementSymbol(var);              
     } 
     [<COLON>]<EQ>
     (value = assignStatementOperand(info) |

Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2012-09-25 18:58:05 UTC (rev 4471)
@@ -210,7 +210,7 @@
 ERR.015.012.0062 = Elements cannot appear more than once in a SET or USING clause.  The following elements are duplicated: {0}
 ERR.015.012.0063 = Multiple failures occurred during validation:
 ERR.015.012.0064 = Validation succeeded
-TEIID30124=Nested Loop can not use the same cursor name as that of its parent.
+TEIID30124=Loop cursor or exception group name {0} already exists.
 ERR.015.012.0067 = No scalar subqueries are allowed in the SELECT with no FROM clause.
 ERR.015.012.0069 = INTO clause can not be used in XML query.
 
@@ -673,7 +673,7 @@
 QueryResolver.invalid_xpath=Invalid xpath value: {0}
 TEIID30066=The definition for {0} does not have the correct number of projected symbols.  Expected {1}, but was {2}.
 QueryResolver.wrong_view_symbol_type=The definition for {0} has the wrong type for column {1}.  Expected {2}, but was {3}.
-ResolveVariablesVisitor.reserved_word_for_temporary_used=Cursor names cannot begin with "#" as that indicates the name of a temporary table: {0}.
+TEIID30125=Cursor or exception group names cannot begin with "#" as that indicates the name of a temporary table: {0}.
 SimpleQueryResolver.materialized_table_not_used=The query against {0} did not use materialization table {1} due to the use of OPTION NOCACHE.
 SimpleQueryResolver.cache_hint_used=Loading materialized view {1} for view {0} using cache hint {2}.
 SimpleQueryResolver.procedure_cache_used=Procedure caching will be used for {0}.

Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -3021,12 +3021,11 @@
     @Test public void testRaiseErrorStatement() throws Exception {
     	ExceptionExpression ee = new ExceptionExpression();
     	ee.setMessage(new Constant("Test only"));
-    	ee.setWarning(true);
     	ee.setSqlState(new Constant("100"));
     	ee.setParent(new ElementSymbol("e"));
-        RaiseStatement errStmt = new RaiseStatement(ee);
+        RaiseStatement errStmt = new RaiseStatement(ee, true);
                  
-        helpStmtTest("RAISE SQLWARNING 'Test only' SQLSTATE '100' EXCEPTION e;", "RAISE SQLWARNING 'Test only' SQLSTATE '100' EXCEPTION e;", //$NON-NLS-1$ //$NON-NLS-2$
+        helpStmtTest("RAISE SQLWARNING SQLEXCEPTION 'Test only' SQLSTATE '100' chain e;", "RAISE SQLWARNING SQLEXCEPTION 'Test only' SQLSTATE '100' CHAIN e;", //$NON-NLS-1$ //$NON-NLS-2$
             errStmt);           
     }
     
@@ -5270,5 +5269,17 @@
     @Test public void testTextTableNegativeWidth() {        
         helpException("SELECT * from texttable(null columns x string width -1) as x"); 
 	}
+    
+    @Test public void testBlockExceptionHandling() throws ParseException {
+    	CommandStatement cmdStmt =	new CommandStatement(new Query(new Select(Arrays.asList(new MultipleElementSymbol())), new From(Arrays.asList(new UnaryFromClause(new GroupSymbol("x")))), null, null, null));
+    	AssignmentStatement assigStmt =	new AssignmentStatement(new ElementSymbol("a"), new Constant(new Integer(1))); //$NON-NLS-1$
+    	RaiseStatement errStmt =	new RaiseStatement(new Constant("My Error")); //$NON-NLS-1$
+    	Block b = new Block();
+    	b.setExceptionGroup("g");
+    	b.addStatement(cmdStmt);
+    	b.addStatement(assigStmt);
+    	b.addStatement(errStmt, true);
+    	helpStmtTest("BEGIN\nselect * from x;\na = 1;\nexception e\nERROR 'My Error';\nEND", "BEGIN\nSELECT * FROM x;\na = 1;\nEXCEPTION e\nRAISE SQLEXCEPTION 'My Error';\nEND", b); //$NON-NLS-1$
+    }
 
 }

Modified: trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcErrors.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcErrors.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcErrors.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -25,10 +25,12 @@
 import static org.junit.Assert.*;
 import static org.teiid.query.processor.proc.TestProcedureProcessor.*;
 
+import java.util.Arrays;
+import java.util.List;
+
 import org.junit.Test;
 import org.teiid.core.TeiidProcessingException;
 import org.teiid.jdbc.TeiidSQLException;
-import org.teiid.jdbc.TeiidSQLWarning;
 import org.teiid.query.metadata.TransformationMetadata;
 import org.teiid.query.processor.HardcodedDataManager;
 import org.teiid.query.processor.ProcessorPlan;
@@ -39,7 +41,7 @@
 	
     @Test public void testInvalidException() throws Exception {
     	String ddl = 
-    			"create virtual procedure vproc (x integer) returns integer as begin declare object e = sqlwarning 'hello'; raise e; raise sqlexception 'hello world' sqlstate 'abc', 1 exception e; end;";
+    			"create virtual procedure vproc (x integer) returns integer as begin declare object e = sqlexception 'hello'; raise e; raise sqlexception 'hello world' sqlstate 'abc', 1 chain e; end;";
     	try {
     		TestProcedureResolving.createMetadata(ddl);
     		fail();
@@ -50,7 +52,7 @@
 
     @Test public void testExceptionAndWarning() throws Exception {
     	String ddl = 
-    			"create virtual procedure vproc (x integer) returns integer as begin declare exception e = sqlwarning 'hello'; raise e; raise sqlexception 'hello world' sqlstate 'abc', 1 exception e; end;";
+    			"create virtual procedure vproc (x integer) returns integer as begin declare exception e = sqlexception 'hello'; raise sqlwarning e; raise sqlexception 'hello world' sqlstate 'abc', 1 chain e; end;";
     	TransformationMetadata tm = TestProcedureResolving.createMetadata(ddl);    	
 
     	String sql = "call vproc(1)"; //$NON-NLS-1$
@@ -63,7 +65,7 @@
         	helpTestProcess(plan, null, dataManager, tm);
         	fail();
         } catch (TeiidProcessingException e) {
-            TeiidSQLWarning tsw = (TeiidSQLWarning) plan.getContext().getAndClearWarnings().get(0);
+            TeiidSQLException tsw = (TeiidSQLException) plan.getContext().getAndClearWarnings().get(0);
         	assertEquals("hello", tsw.getMessage());
         	
         	assertEquals(e.getCause().getCause(), tsw);
@@ -74,5 +76,28 @@
         }
         
     }
+    
+    @Test public void testExceptionHandling() throws Exception {
+    	String ddl = 
+    			"create virtual procedure vproc (x integer) returns integer as begin " +
+    			"raise sqlexception 'hello world' sqlstate 'abc', 1;" +
+    			"exception e " +
+    			"raise sqlwarning sqlexception 'caught' chain e.exception; " +
+    			"\"return\" = 1;"+
+    			"end;";
+    	TransformationMetadata tm = TestProcedureResolving.createMetadata(ddl);    	
+
+    	String sql = "call vproc(1)"; //$NON-NLS-1$
+
+        ProcessorPlan plan = getProcedurePlan(sql, tm);
+
+        HardcodedDataManager dataManager = new HardcodedDataManager(tm);
+        
+    	helpTestProcess(plan, new List[] {Arrays.asList(1)}, dataManager, tm);
+    	
+    	TeiidSQLException tse = (TeiidSQLException)plan.getContext().getAndClearWarnings().get(0);
+    	assertEquals("caught", tse.getMessage());
+    	assertEquals("hello world", tse.getCause().getMessage());
+    }
 	
 }

Modified: trunk/engine/src/test/java/org/teiid/query/resolver/TestProcedureResolving.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/resolver/TestProcedureResolving.java	2012-09-25 18:56:07 UTC (rev 4470)
+++ trunk/engine/src/test/java/org/teiid/query/resolver/TestProcedureResolving.java	2012-09-25 18:58:05 UTC (rev 4471)
@@ -807,7 +807,7 @@
         String userUpdateStr = "UPDATE vm1.g1 SET e1='x'"; //$NON-NLS-1$
         
         helpFailUpdateProcedure(proc.toString(), userUpdateStr,
-                                     Table.TriggerEvent.UPDATE, "TEIID30124 Nested Loop can not use the same cursor name as that of its parent."); //$NON-NLS-1$
+                                     Table.TriggerEvent.UPDATE, "TEIID30124 Loop cursor or exception group name loopCursor already exists."); //$NON-NLS-1$
     }
     
     @Test public void testTempGroupElementShouldNotBeResolable() {
@@ -978,7 +978,7 @@
     
     //cursor starts with "#" Defect14924
     @Test public void testVirtualProcedureInvalid1() throws Exception {
-    	helpResolveException("EXEC pm1.vsp32()",RealMetadataFactory.example1Cached(), "TEIID30125 Cursor names cannot begin with \"#\" as that indicates the name of a temporary table: #mycursor.");   //$NON-NLS-1$ //$NON-NLS-2$
+    	helpResolveException("EXEC pm1.vsp32()",RealMetadataFactory.example1Cached(), "TEIID30125 Cursor or exception group names cannot begin with \"#\" as that indicates the name of a temporary table: #mycursor.");   //$NON-NLS-1$ //$NON-NLS-2$
     }
     
     @Test public void testVirtualProcedureWithOrderBy() throws Exception {
@@ -1002,7 +1002,7 @@
     }
     
     @Test public void testLoopRedefinition2() throws Exception {
-        helpResolveException("EXEC pm1.vsp11()", RealMetadataFactory.example1Cached(), "TEIID30124 Nested Loop can not use the same cursor name as that of its parent."); //$NON-NLS-1$ //$NON-NLS-2$
+        helpResolveException("EXEC pm1.vsp11()", RealMetadataFactory.example1Cached(), "TEIID30124 Loop cursor or exception group name mycursor already exists."); //$NON-NLS-1$ //$NON-NLS-2$
     }
         
     @Test public void testVariableResolutionWithIntervening() throws Exception {



More information about the teiid-commits mailing list