[teiid-commits] teiid SVN: r2869 - in trunk: build/kits/jboss-container and 15 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Fri Jan 21 10:59:54 EST 2011


Author: shawkins
Date: 2011-01-21 10:59:53 -0500 (Fri, 21 Jan 2011)
New Revision: 2869

Modified:
   trunk/COPYRIGHT.txt
   trunk/build/kits/jboss-container/teiid-releasenotes.html
   trunk/documentation/reference/src/main/docbook/en-US/content/procedures.xml
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/Request.java
   trunk/engine/src/main/java/org/teiid/query/metadata/TempMetadataAdapter.java
   trunk/engine/src/main/java/org/teiid/query/metadata/TempMetadataID.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/QueryOptimizer.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
   trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java
   trunk/engine/src/main/java/org/teiid/query/resolver/command/ExecResolver.java
   trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/StoredProcedure.java
   trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
   trunk/engine/src/main/resources/org/teiid/query/i18n.properties
   trunk/engine/src/test/java/org/teiid/query/processor/TestProcedureRelational.java
   trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java
   trunk/engine/src/test/java/org/teiid/query/resolver/TestProcedureResolving.java
   trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java
   trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
Log:
TEIID-946 adding support for inout/out/return parameters to have values assigned.

Modified: trunk/COPYRIGHT.txt
===================================================================
--- trunk/COPYRIGHT.txt	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/COPYRIGHT.txt	2011-01-21 15:59:53 UTC (rev 2869)
@@ -1,4 +1,4 @@
-Portions Copyright (C) 2008-2009 Red Hat, Inc.
+Portions Copyright (C) 2008-2011 Red Hat, Inc.
 Portions Copyright (C) 2000-2007 MetaMatrix, Inc.
 Portions Copyright (c) 2000, 2003, 2008 IBM Corporation and others.
 Portions Copyright (c) 1997-2000 Sun Microsystems, Inc.
\ No newline at end of file

Modified: trunk/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-container/teiid-releasenotes.html	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/build/kits/jboss-container/teiid-releasenotes.html	2011-01-21 15:59:53 UTC (rev 2869)
@@ -26,21 +26,7 @@
 </UL>
 <H2><A NAME="Highlights"></A>Highlights</H2>
 <UL>
-	<LI><B>Subquery Optimization</B> - added rewrite to INNER JOIN for applicable WHERE clause subqueries. Also added cost based SEMI and ANTI-SEMI join handling for applicable non-pushed WHERE and HAVING subqueries.
-	<LI><B>Updatable Views</B>
-	    <UL>
-	        <LI>Added support to perform simple pass-through and more complicated updates through views by default.
-	        <LI>Added support for "FOR EACH ROW" update procedure handling (similar to INSTEAD OF triggers in other DBMS's), which should be used instead of the deprecated TRANSLATE criteria approach.
-	    </UL>
-	<LI><B>Temp table enhancements</B> - added support for the SERIAL datatype, which is a not null INTEGER that auto-increments, and the ability to specify a column as NOT NULL.                     
-	<LI><B>UDF</B> - new API objects added to teiid-api to support user defined functions that are capable of pushdown to source.
-	<LI><B>Unescape Function</B> - a new system function, unescape, was added to handle common \ escaping in strings including octal, hex/unicode, \b, \r, \n, \f, and \t.
-	<LI><B>Predicate Optimization</B> - expanded optimizations for detecting always false conditions when using IS NULL, IN, or comparison predicates with literal values.
-	<LI><B>Partition-wise Optimizations</B> - Views defined by partitioned unions (union alls where each branch has a projected literal or an IN predicate that makes its values mutually exclusive from the other branches) can 
-	be used in aggregation or joins and the optimizer will take advantage of the partitioning information.  For example, when a partitioned union is joined against another partitioned union, the optimizer will reorganize the join of unions into a union of joins.
-	<LI><B>Delegate Translator</B> - A new translator base class was added that is capable of delegating all the calls to another configured translator.
-	<LI><B>JDBC Reauthentication</B> - Teiid connections (defined by the org.teiid.jdbc.TeiidConnection interface) now support the changeUser method to reauthenticate a given connection.
-	<LI><B>Lob Caching</B> - Lobs are allowed to cache to disk as part of ResultSet caching. Distributed lob caching is not allowed. 
+	<LI><B>Virtual procedure out params</B> - virtual procedures can now have RETURN/OUT/INOUT parameters to return values.
 </UL>
 
 <h2><a name="Compatibility">Compatibility Issues</a></h2>

Modified: trunk/documentation/reference/src/main/docbook/en-US/content/procedures.xml
===================================================================
--- trunk/documentation/reference/src/main/docbook/en-US/content/procedures.xml	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/documentation/reference/src/main/docbook/en-US/content/procedures.xml	2011-01-21 15:59:53 UTC (rev 2869)
@@ -305,8 +305,9 @@
         expected result set and parameters of the procedure.</para>      
     </section>
     <section>
-      <title>Procedure Input Parameters</title>
-      <para>Virtual procedures can take zero or more input parameters. Each input has the following information that is used during runtime processing: </para>
+      <title>Procedure Parameters</title>
+      <para>Virtual procedures can take zero or more IN/INOUT parameters and may also have any number of OUT parameters and an optional RETURN parameter.
+       Each input has the following information that is used during runtime processing: </para>
       <itemizedlist>
         <listitem>
           <para>Name - The name of the input parameter</para>
@@ -321,16 +322,20 @@
           <para>Nullable - NO_NULLS, NULLABLE, NULLABLE_UNKNOWN; parameter is optional if nullable, and is not required to be listed when using named parameter syntax</para>
         </listitem>
       </itemizedlist>
-      <para>You reference an input to a virtual procedure by using the fully-qualified name of the param (or less if unambiguous). For example, MySchema.MyProc.Param1.
+      <para>You reference a parameter in a virtual procedure by using the fully-qualified name of the param (or less if unambiguous). For example, MySchema.MyProc.Param1.
       </para>
       <example>
-        <title>Example of Referencing an Input Parameter for 'GetBalance' Procedure</title>
+        <title>Example of Referencing an Input Parameter and Assigning an Out Parameter for 'GetBalance' Procedure</title>
         <programlisting>
 CREATE VIRTUAL PROCEDURE 
 BEGIN 
+  MySchema.GetBalance.RetVal = UPPER(MySchema.GetBalance.AcctID);
   SELECT Balance FROM MySchema.Accts WHERE MySchema.Accts.AccountID = MySchema.GetBalance.AcctID; 
 END</programlisting>
       </example>
+      <para>If an INOUT parameter is not assigned any value in a procedure it will remain the value it was assigned for input.  
+      Any OUT/RETURN parameter not assigned a value will remain the as the default NULL value.  
+      The INOUT/OUT/RETURN output values are validated against the NOT NULL metadata of the parameter.</para>
     </section>
     <section>
       <title>Example Virtual Procedures</title>

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/Request.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/Request.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/Request.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -323,7 +323,7 @@
         // Validate with visitor
         ValidatorReport report = Validator.validate(command, metadata, visitor);
         if (report.hasItems()) {
-            ValidatorFailure firstFailure = (ValidatorFailure) report.getItems().iterator().next();
+            ValidatorFailure firstFailure = report.getItems().iterator().next();
             throw new QueryValidatorException(firstFailure.getMessage());
         }
     }

Modified: trunk/engine/src/main/java/org/teiid/query/metadata/TempMetadataAdapter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/metadata/TempMetadataAdapter.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/query/metadata/TempMetadataAdapter.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -340,10 +340,15 @@
                 case SupportConstants.Element.NULL: {
                 	if (id.isNotNull()) {
                 		return false;
+                	} 
+                	if (id.isTempTable()) {
+                		return true;
                 	}
                 	break;
                 }
                 case SupportConstants.Element.AUTO_INCREMENT:	 return id.isAutoIncrement();
+                case SupportConstants.Element.UPDATE:			 return id.isTempTable() || id.isUpdatable();
+                
             }
             
             // If this is a temp table column or real metadata is unknown, return hard-coded values
@@ -351,7 +356,6 @@
             if(elementID == null || id.isTempTable()) {
                 switch(supportConstant) {
                     case SupportConstants.Element.NULL:              return true;
-                    case SupportConstants.Element.UPDATE:            return true;
                     case SupportConstants.Element.SIGNED:            return true;
                 }
                 

Modified: trunk/engine/src/main/java/org/teiid/query/metadata/TempMetadataID.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/metadata/TempMetadataID.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/query/metadata/TempMetadataID.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -78,6 +78,7 @@
     private Class<?> type;     // type of this element, only for element
     private boolean autoIncrement;
     private boolean notNull;
+    private boolean updatable;
     
     /**
      * Constructor for group form of metadata ID.
@@ -273,6 +274,10 @@
 	public void setMetadataType(Type metadataType) {
 		this.metadataType = metadataType;
 	}
+	
+	public Type getMetadataType() {
+		return metadataType;
+	}
 
 	public List<TempMetadataID> getPrimaryKey() {
 		return getTableData().primaryKey;
@@ -350,5 +355,13 @@
 	public void setNotNull(boolean notNull) {
 		this.notNull = notNull;
 	}
+	
+	public void setUpdatable(boolean updatable) {
+		this.updatable = updatable;
+	}
+	
+	public boolean isUpdatable() {
+		return updatable;
+	}
 		
 }

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/QueryOptimizer.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/QueryOptimizer.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/QueryOptimizer.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -23,6 +23,8 @@
 package org.teiid.query.optimizer;
 
 import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 
 import org.teiid.api.exception.query.QueryMetadataException;
@@ -50,6 +52,7 @@
 import org.teiid.query.sql.lang.Command;
 import org.teiid.query.sql.lang.ProcedureContainer;
 import org.teiid.query.sql.lang.Query;
+import org.teiid.query.sql.lang.SPParameter;
 import org.teiid.query.sql.lang.StoredProcedure;
 import org.teiid.query.sql.lang.TranslatableProcedureContainer;
 import org.teiid.query.sql.proc.CreateUpdateProcedureCommand;
@@ -129,6 +132,24 @@
 	        	LinkedHashMap<ElementSymbol, Expression> params = container.getProcedureParameters();
 	        	if (container instanceof StoredProcedure) {
 	        		plan.setRequiresTransaction(container.getUpdateCount() > 0);
+	        		StoredProcedure sp = (StoredProcedure)container;
+	        		if (sp.returnParameters()) {
+	        			List<ElementSymbol> outParams = new LinkedList<ElementSymbol>();
+	        			for (SPParameter param : sp.getParameters()) {
+							if (param.getParameterType() == SPParameter.RETURN_VALUE) {
+								outParams.add(param.getParameterSymbol());
+							}
+						}
+	        			for (SPParameter param : sp.getParameters()) {
+							if (param.getParameterType() == SPParameter.INOUT || 
+									param.getParameterType() == SPParameter.OUT) {
+								outParams.add(param.getParameterSymbol());
+							}
+						}
+	        			if (outParams.size() > 0) {
+	        				plan.setOutParams(outParams);
+	        			}
+	        		}
 	        	}
 	            plan.setParams(params);
 	            plan.setMetadata(metadata);

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	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -25,10 +25,10 @@
 import static org.teiid.query.analysis.AnalysisRecord.*;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -36,6 +36,7 @@
 import java.util.Set;
 import java.util.Stack;
 
+import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.api.exception.query.QueryValidatorException;
 import org.teiid.client.plan.PlanNode;
 import org.teiid.common.buffer.BlockedException;
@@ -94,9 +95,10 @@
     // Temp state for final results
     private TupleSource finalTupleSource;
     private int beginBatch = 1;
-    private List batchRows;
+    private List<Object> batchRows;
     private boolean lastBatch = false;
     private LinkedHashMap<ElementSymbol, Expression> params;
+    private List<ElementSymbol> outParams;
     private Map<ElementSymbol, Reference> implicitParams;
     private QueryMetadataInterface metadata;
 
@@ -117,7 +119,7 @@
     
     private TempTableStore tempTableStore;
     
-    private LinkedList tempContext = new LinkedList();
+    private LinkedList<Set<String>> tempContext = new LinkedList<Set<String>>();
 	private SubqueryAwareEvaluator evaluator;
 	
     // Stack of programs, with current program on top
@@ -186,6 +188,11 @@
 
     public void open() throws TeiidProcessingException, TeiidComponentException {
     	if (!this.evaluatedParams) {
+    		if (this.outParams != null) {
+    			for (ElementSymbol param : this.outParams) {
+					setParameterValue(param, getCurrentVariableContext(), null);
+				}
+    		}
     		if (this.params != null) { 
 		        for (Map.Entry<ElementSymbol, Expression> entry : this.params.entrySet()) {
 		            ElementSymbol param = entry.getKey();
@@ -195,9 +202,7 @@
 		            Object value = this.evaluateExpression(expr);
 		
 		            //check constraint
-		            if (value == null && !metadata.elementSupports(param.getMetadataID(), SupportConstants.Element.NULL)) {
-		                throw new QueryValidatorException(QueryPlugin.Util.getString("ProcedurePlan.nonNullableParam", expr)); //$NON-NLS-1$
-		            }
+		            checkNotNull(param, value);
 		            setParameterValue(param, context, value);
 		        }
     		}
@@ -214,6 +219,14 @@
     	this.evaluatedParams = true;
     }
 
+	private void checkNotNull(ElementSymbol param, Object value)
+			throws TeiidComponentException, QueryMetadataException,
+			QueryValidatorException {
+		if (value == null && !metadata.elementSupports(param.getMetadataID(), SupportConstants.Element.NULL)) {
+		    throw new QueryValidatorException(QueryPlugin.Util.getString("ProcedurePlan.nonNullableParam", param)); //$NON-NLS-1$
+		}
+	}
+
 	protected void setParameterValue(ElementSymbol param,
 			VariableContext context, Object value) {
 		context.setValue(param, value);
@@ -245,11 +258,22 @@
             // May throw BlockedException and exit here
             List tuple = this.finalTupleSource.nextTuple();
             if(tuple == null) {
+            	if (outParams != null) {
+            		VariableContext vc = getCurrentVariableContext();
+            		List<Object> paramTuple = Arrays.asList(new Object[this.getOutputElements().size()]);
+            		int i = this.getOutputElements().size() - this.outParams.size();
+            		for (ElementSymbol param : outParams) {
+            			Object value = vc.getValue(param);
+            			checkNotNull(param, value);
+						paramTuple.set(i++, value);
+					}
+            		addBatchRow(paramTuple, true);
+            	}
                 terminateBatches();
                 done = true;
                 break;
             }
-            addBatchRow(tuple);
+            addBatchRow(tuple, false);
         }
 
         return pullBatch();
@@ -340,16 +364,24 @@
         plan.setUpdateProcedure(this.isUpdateProcedure());
         plan.setOutputElements(this.getOutputElements());
         plan.setParams(params);
+        plan.setOutParams(outParams);
         plan.setImplicitParams(implicitParams);
         plan.setMetadata(metadata);
         plan.requiresTransaction = requiresTransaction;
         return plan;
     }
 
-    private void addBatchRow(List row) {
+	private void addBatchRow(List<?> row, boolean last) {
         if(this.batchRows == null) {
-            this.batchRows = new ArrayList(this.batchSize);
+            this.batchRows = new ArrayList<Object>(this.batchSize/4);
         }
+        if (!last && this.outParams != null) {
+        	List<Object> newRow = Arrays.asList(new Object[row.size() + this.outParams.size()]);
+        	for (int i = 0; i < row.size(); i++) {
+				newRow.set(i, row.get(i));
+			}
+        	row = newRow;
+        }
         this.batchRows.add(row);
     }
 
@@ -389,6 +421,10 @@
     public void setMetadata( QueryMetadataInterface metadata ) {
         this.metadata = metadata;
     }
+    
+    public void setOutParams(List<ElementSymbol> outParams) {
+		this.outParams = outParams;
+	}
 
     public void setParams( LinkedHashMap<ElementSymbol, Expression> params ) {
         this.params = params;
@@ -456,9 +492,9 @@
             	//process assignments
             	Assertion.assertTrue(this.currentState.currentRow != null);
             	for (Map.Entry<ElementSymbol, ElementSymbol> entry : procAssignments.entrySet()) {
-            		if (entry.getValue() == null) {
-            			continue;
-            		}
+            		if (entry.getValue() == null || !metadata.elementSupports(entry.getValue().getMetadataID(), SupportConstants.Element.UPDATE)) {
+	            		continue;
+	            	}
             		int index = this.currentState.processor.getOutputElements().indexOf(entry.getKey());
             		getCurrentVariableContext().setValue(entry.getValue(), DataTypeManager.transformValue(this.currentState.currentRow.get(index), entry.getValue().getType()));
 				}
@@ -489,15 +525,15 @@
         if (this.currentVarContext.getParentContext() != null) {
         	this.currentVarContext = this.currentVarContext.getParentContext();
         }
-        Set current = getTempContext();
+        Set<String> current = getTempContext();
 
-        Set tempTables = getLocalTempTables();
+        Set<String> tempTables = getLocalTempTables();
 
         tempTables.addAll(current);
         
         if (program != originalProgram) {
-	        for (Iterator i = tempTables.iterator(); i.hasNext();) {
-	            this.tempTableStore.removeTempTableByName((String)i.next());
+        	for (String table : tempTables) {
+	            this.tempTableStore.removeTempTableByName(table);
 	        }
         }
         this.tempContext.removeLast();
@@ -510,12 +546,12 @@
         context.setParentContext(this.currentVarContext);
         this.currentVarContext = context;
         
-        Set current = getTempContext();
+        Set<String> current = getTempContext();
         
-        Set tempTables = getLocalTempTables();
+        Set<String> tempTables = getLocalTempTables();
         
         current.addAll(tempTables);
-        this.tempContext.add(new HashSet());
+        this.tempContext.add(new HashSet<String>());
     }
     
     public void incrementProgramCounter() throws TeiidComponentException {
@@ -531,21 +567,21 @@
     /** 
      * @return
      */
-    private Set getLocalTempTables() {
-        Set tempTables = this.tempTableStore.getAllTempTables();
+    private Set<String> getLocalTempTables() {
+        Set<String> tempTables = this.tempTableStore.getAllTempTables();
         
         //determine what was created in this scope
         for (int i = 0; i < tempContext.size() - 1; i++) {
-            tempTables.removeAll((Set)tempContext.get(i));
+            tempTables.removeAll(tempContext.get(i));
         }
         return tempTables;
     }
 
-    public Set getTempContext() {
+    public Set<String> getTempContext() {
         if (this.tempContext.isEmpty()) {
-            tempContext.addLast(new HashSet());
+            tempContext.addLast(new HashSet<String>());
         }
-        return (Set)this.tempContext.getLast();
+        return this.tempContext.getLast();
     }
 
     public List getCurrentRow(String rsName) throws TeiidComponentException {

Modified: trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/ProcedureContainerResolver.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -23,6 +23,7 @@
 package org.teiid.query.resolver;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.teiid.api.exception.query.QueryMetadataException;
@@ -53,6 +54,7 @@
 import org.teiid.query.sql.proc.TriggerAction;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.GroupSymbol;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
 import org.teiid.query.validator.UpdateValidator;
 import org.teiid.query.validator.UpdateValidator.UpdateInfo;
 import org.teiid.query.validator.UpdateValidator.UpdateType;
@@ -119,10 +121,10 @@
             List<ElementSymbol> viewElements = ResolverUtil.resolveElementsInGroup(ta.getView(), metadata);
             if (procCommand instanceof Update || procCommand instanceof Insert) {
             	addChanging(tma.getMetadataStore(), externalGroups, viewElements);
-            	ProcedureContainerResolver.addScalarGroup(SQLConstants.Reserved.NEW, tma.getMetadataStore(), externalGroups, viewElements);
+            	ProcedureContainerResolver.addScalarGroup(SQLConstants.Reserved.NEW, tma.getMetadataStore(), externalGroups, viewElements, false);
             }
             if (procCommand instanceof Update || procCommand instanceof Delete) {
-            	ProcedureContainerResolver.addScalarGroup(SQLConstants.Reserved.OLD, tma.getMetadataStore(), externalGroups, viewElements);
+            	ProcedureContainerResolver.addScalarGroup(SQLConstants.Reserved.OLD, tma.getMetadataStore(), externalGroups, viewElements, false);
             }
             QueryResolver.setChildMetadata(subCommand, tma.getMetadataStore().getData(), externalGroups);
             QueryResolver.resolveCommand(subCommand, metadata);
@@ -192,8 +194,8 @@
             inputElments.add(inputElement);
         }
 
-        addScalarGroup(ProcedureReservedWords.INPUT, discoveredMetadata, externalGroups, inputElments);
-        addScalarGroup(ProcedureReservedWords.INPUTS, discoveredMetadata, externalGroups, inputElments);
+        addScalarGroup(ProcedureReservedWords.INPUT, discoveredMetadata, externalGroups, inputElments, false);
+        addScalarGroup(ProcedureReservedWords.INPUTS, discoveredMetadata, externalGroups, inputElments, false);
 
         // Switch type to be boolean for all CHANGING variables
         addChanging(discoveredMetadata, externalGroups, elements);
@@ -210,7 +212,7 @@
             changingElements.add(changeElement);
         }
 
-        addScalarGroup(ProcedureReservedWords.CHANGING, discoveredMetadata, externalGroups, changingElements);
+        addScalarGroup(ProcedureReservedWords.CHANGING, discoveredMetadata, externalGroups, changingElements, false);
 	}
         
     /** 
@@ -313,13 +315,27 @@
         procCommand.setUpdateInfo(ProcedureContainerResolver.getUpdateInfo(group, metadata, procCommand.getType()));
     }
 
-	public static GroupSymbol addScalarGroup(String name, TempMetadataStore metadata, GroupContext externalGroups, List symbols) {
+    public static GroupSymbol addScalarGroup(String name, TempMetadataStore metadata, GroupContext externalGroups, List<? extends SingleElementSymbol> symbols) {
+    	return addScalarGroup(name, metadata, externalGroups, symbols, true);
+    }
+    
+	public static GroupSymbol addScalarGroup(String name, TempMetadataStore metadata, GroupContext externalGroups, List<? extends SingleElementSymbol> symbols, boolean updatable) {
+		boolean[] updateArray = new boolean[symbols.size()];
+		if (updatable) {
+			Arrays.fill(updateArray, true);
+		}
+		return addScalarGroup(name, metadata, externalGroups, symbols, updateArray);
+	}
+	
+	public static GroupSymbol addScalarGroup(String name, TempMetadataStore metadata, GroupContext externalGroups, List<? extends SingleElementSymbol> symbols, boolean[] updatable) {
 		GroupSymbol variables = new GroupSymbol(name);
 	    externalGroups.addGroup(variables);
 	    TempMetadataID tid = metadata.addTempGroup(name, symbols);
 	    tid.setMetadataType(Type.SCALAR);
+	    int i = 0;
 	    for (TempMetadataID cid : tid.getElements()) {
 			cid.setMetadataType(Type.SCALAR);
+			cid.setUpdatable(updatable[i++]);
 		}
 	    variables.setMetadataID(tid);
 	    return variables;

Modified: trunk/engine/src/main/java/org/teiid/query/resolver/command/ExecResolver.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/command/ExecResolver.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/command/ExecResolver.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -235,15 +235,18 @@
         GroupContext context = new GroupContext();
 
         // Look through parameters to find input elements - these become child metadata
-        List<ElementSymbol> tempElements = new ArrayList<ElementSymbol>();
+        List<ElementSymbol> tempElements = new ArrayList<ElementSymbol>(storedProcedureCommand.getParameters().size());
+        boolean[] updatable = new boolean[storedProcedureCommand.getParameters().size()];
+        int i = 0;
         for (SPParameter param : storedProcedureCommand.getParameters()) {
-            if(param.getParameterType() == ParameterInfo.IN || param.getParameterType() == ParameterInfo.INOUT) {
+            if(param.getParameterType() != ParameterInfo.RESULT_SET) {
                 ElementSymbol symbol = param.getParameterSymbol();
                 tempElements.add(symbol);
+                updatable[i++] = param.getParameterType() != ParameterInfo.IN;  
             }
         }
 
-        ProcedureContainerResolver.addScalarGroup(procName, discoveredMetadata, context, tempElements);
+        ProcedureContainerResolver.addScalarGroup(procName, discoveredMetadata, context, tempElements, updatable);
         
         return context;
     }
@@ -264,7 +267,7 @@
             if(expr == null) {
             	continue;
             }
-            for (SubqueryContainer container : ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(expr)) {
+            for (SubqueryContainer<?> container : ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(expr)) {
                 QueryResolver.setChildMetadata(container.getCommand(), command);
                 
                 QueryResolver.resolveCommand(container.getCommand(), metadata.getMetadata());

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	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/command/UpdateProcedureResolver.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -40,6 +40,7 @@
 import org.teiid.logging.LogManager;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.metadata.QueryMetadataInterface;
+import org.teiid.query.metadata.SupportConstants;
 import org.teiid.query.metadata.TempMetadataAdapter;
 import org.teiid.query.metadata.TempMetadataID;
 import org.teiid.query.metadata.TempMetadataStore;
@@ -181,7 +182,7 @@
         externalGroups = new GroupContext(externalGroups, null);
         
         //create a new variables group for this block
-        GroupSymbol variables = ProcedureContainerResolver.addScalarGroup(ProcedureReservedWords.VARIABLES, store, externalGroups, new LinkedList());
+        GroupSymbol variables = ProcedureContainerResolver.addScalarGroup(ProcedureReservedWords.VARIABLES, store, externalGroups, new LinkedList<SingleElementSymbol>());
         
         for (Statement statement : block.getStatements()) {
             resolveStatement(command, statement, externalGroups, variables, metadata);
@@ -218,11 +219,19 @@
                 			continue;
                 		}
             			switch (param.getParameterType()) {
-        	            case ParameterInfo.INOUT:
         	            case ParameterInfo.OUT:
         	            case ParameterInfo.RETURN_VALUE:
+        	            	if (param.getExpression() instanceof ElementSymbol && !metadata.elementSupports(((ElementSymbol)param.getExpression()).getMetadataID(), SupportConstants.Element.UPDATE)) {
+        	                    throw new QueryResolverException(QueryPlugin.Util.getString("UpdateProcedureResolver.only_variables", param.getExpression())); //$NON-NLS-1$
+        	            	}
         	            	sp.setCallableStatement(true);
         	            	break;
+        	            case ParameterInfo.INOUT:
+        	            	if (param.getExpression() instanceof ElementSymbol && !metadata.elementSupports(((ElementSymbol)param.getExpression()).getMetadataID(), SupportConstants.Element.UPDATE)) {
+        	            		continue;
+        	            	}
+        	            	sp.setCallableStatement(true);
+        	            	break;
         	            }
 					}
                 }
@@ -277,7 +286,7 @@
                 } else if (statement.getType() == Statement.TYPE_ASSIGNMENT) {
                 	AssignmentStatement assStmt = (AssignmentStatement)statement;
                     ResolverVisitor.resolveLanguageObject(assStmt.getVariable(), null, externalGroups, metadata);
-                    if (statement.getType() == Statement.TYPE_ASSIGNMENT && !assStmt.getVariable().getGroupSymbol().getCanonicalName().equals(ProcedureReservedWords.VARIABLES)) {
+                    if (!metadata.elementSupports(assStmt.getVariable().getMetadataID(), SupportConstants.Element.UPDATE)) {
                         throw new QueryResolverException(QueryPlugin.Util.getString("UpdateProcedureResolver.only_variables", assStmt.getVariable())); //$NON-NLS-1$
                     }
                     //don't allow variable assignments to be external
@@ -326,7 +335,7 @@
                 metadata = new TempMetadataAdapter(metadata.getMetadata(), store);
                 externalGroups = new GroupContext(externalGroups, null);
                 
-                ProcedureContainerResolver.addScalarGroup(groupName, store, externalGroups, symbols);
+                ProcedureContainerResolver.addScalarGroup(groupName, store, externalGroups, symbols, false);
                 
                 resolveBlock(command, loopStmt.getBlock(), externalGroups, metadata);
                 break;
@@ -375,7 +384,9 @@
         }
         variable.setType(DataTypeManager.getDataTypeClass(typeName));
         variable.setGroupSymbol(variables);
-        variable.setMetadataID(new TempMetadataID(variable.getName(), variable.getType()));
+        TempMetadataID id = new TempMetadataID(variable.getName(), variable.getType());
+        id.setUpdatable(true);
+        variable.setMetadataID(id);
         //TODO: this will cause the variables group to loose it's cache of resolved symbols
         metadata.getMetadataStore().addElementToTempGroup(ProcedureReservedWords.VARIABLES, (ElementSymbol)variable.clone());
     }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/StoredProcedure.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/StoredProcedure.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/StoredProcedure.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -397,13 +397,10 @@
 	 * @since 5.0
 	 */
 	public LinkedHashMap<ElementSymbol, Expression> getProcedureParameters() {
-	    
 		LinkedHashMap<ElementSymbol, Expression> map = new LinkedHashMap<ElementSymbol, Expression>();
-	    for (Iterator iter = this.getInputParameters().iterator(); iter.hasNext();) {
-	        
-	        SPParameter element = (SPParameter)iter.next();
+	    for (SPParameter element : this.getInputParameters()) {
 	        map.put(element.getParameterSymbol(), element.getExpression());            
-	   } // for
+	    } // for
 	    
 	    return map;
 	}

Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -442,10 +442,6 @@
 
     public void visit(CreateUpdateProcedureCommand obj) {
         if(!obj.isUpdateProcedure()){
-        	//Every virtual procedure should have at least one query.
-        	if(CommandCollectorVisitor.getCommands(obj).isEmpty()){
-        		handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.Procedure_should_have_query"), obj); //$NON-NLS-1$
-        	}
         	
             //check that the procedure does not contain references to itself
             if (GroupCollectorVisitor.getGroups(obj,true).contains(obj.getVirtualGroup())) {

Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2011-01-21 15:59:53 UTC (rev 2869)
@@ -668,7 +668,6 @@
 SimpleQueryResolver.procedure_cache_not_usable=Procedure caching will not be used for {0} since the result set cache is disabled or the results/parameters cannot be cached.
 SimpleQueryResolver.procedure_cache_not_used=Procedure caching will not be used for {0} due to the use of OPTION NOCACHE.
 ValidationVisitor.groupby_subquery=Expressions used in a GROUP BY cannot be constant and must not contain subqueries: "{0}".
-ValidationVisitor.Procedure_should_have_query=Procedure must execute at least one command to define the procedure result set.
 ValidationVisitor.Procedure_has_group_self_reference=Procedure cannot have a Group reference to itself.
 ExpressionEvaluator.Expected_props_for_payload_function=Unable to evaluate {0}: expected Properties for command payload but got object of type {1}
 ValidationVisitor.The_rowlimit_function_cannot_be_used_in_a_non-XML_command=The ''rowlimit'' and ''rowlimitexception'' functions cannot be used in a non-XML command
@@ -712,7 +711,7 @@
 ValidationVisitor.xmlparse_type=XMLPARSE expects a STRING, CLOB, or BLOB value.
 ValidationVisitor.invalid_encoding=Encoding {0} is not valid.
 ValidationVisitor.subquery_insert=SELECT INTO should not be used in a subquery.
-UpdateProcedureResolver.only_variables=Element symbol "{0}" cannot be assigned a value.  Only declared VARIABLES can be assigned values.
+UpdateProcedureResolver.only_variables=Variable "{0}" is read only and cannot be assigned a value.
 MappingLoader.unknown_node_type=Unknown Node Type "{0}" being loaded by the XML mapping document.
 MappingLoader.invalid_criteria_node=Invalid criteria node found; A criteria node must have criteria specified or it must be a default node.
 WrongTypeChild=Wrong type of child node is being added.

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestProcedureRelational.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestProcedureRelational.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestProcedureRelational.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -585,7 +585,7 @@
             TestProcessor.doProcess(plan, dataManager, expected, TestProcessor.createCommandContext()); 
             fail("QueryPlannerException was expected.");  //$NON-NLS-1$
         } catch (QueryValidatorException e) {
-        	assertEquals("The procedure parameter is not nullable, but is set to null: pm1.vsp26.param2",e.getMessage());  //$NON-NLS-1$
+        	assertEquals("The procedure parameter pm1.vsp26.param2 is not nullable, but is set to null.",e.getMessage());  //$NON-NLS-1$
         }
     }
     

Modified: trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -2697,5 +2697,41 @@
         helpTestProcess(plan, expected, dataMgr, metadata);
     }
     
+    @Test public void testReturnParamWithNoResultSetVirtual() throws Exception {
+        String sql = "EXEC TEIIDSP8(51)";     //$NON-NLS-1$
+        TransformationMetadata metadata = RealMetadataFactory.exampleBQTCached();
+        ProcessorPlan plan = getProcedurePlan(sql, metadata);
+
+        // Set up data
+        FakeDataManager dataMgr = new FakeDataManager();
+  
+        // Create expected results
+        List[] expected = new List[] { Arrays.asList(51) }; //$NON-NLS-1$
+        helpTestProcess(plan, expected, dataMgr, metadata);
+    }
+    
+    @Test(expected=QueryProcessingException.class) public void testParamsWithResultSetVirtualNotNull() throws Exception {
+        String sql = "{? = call TEIIDSP9(51)}";     //$NON-NLS-1$
+        TransformationMetadata metadata = RealMetadataFactory.exampleBQTCached();
+        ProcessorPlan plan = getProcedurePlan(sql, metadata);
+
+        FakeDataManager dataMgr = new FakeDataManager();
+  
+        helpTestProcess(plan, null, dataMgr, metadata);
+    }
+
+    @Test public void testParamsWithResultSetVirtual() throws Exception {
+        String sql = "{? = call TEIIDSP9(1)}";     //$NON-NLS-1$
+        TransformationMetadata metadata = RealMetadataFactory.exampleBQTCached();
+        ProcessorPlan plan = getProcedurePlan(sql, metadata);
+
+        FakeDataManager dataMgr = new FakeDataManager();
+  
+        List[] expected = new List[] { Arrays.asList("hello", null, null), 
+        		Arrays.asList(null, 1, 10) }; //$NON-NLS-1$
+
+        helpTestProcess(plan, expected, dataMgr, metadata);
+    }
+
     private static final boolean DEBUG = false;
 }

Modified: trunk/engine/src/test/java/org/teiid/query/resolver/TestProcedureResolving.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/resolver/TestProcedureResolving.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/test/java/org/teiid/query/resolver/TestProcedureResolving.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -1319,7 +1319,7 @@
         String userUpdateStr = "UPDATE vm1.g1 SET e1='x'"; //$NON-NLS-1$
         
         helpFailUpdateProcedure(procedure, userUpdateStr,
-                                     FakeMetadataObject.Props.UPDATE_PROCEDURE, "Element symbol \"INPUTS.e1\" cannot be assigned a value.  Only declared VARIABLES can be assigned values."); //$NON-NLS-1$
+                                     FakeMetadataObject.Props.UPDATE_PROCEDURE);
     }
     
     // validating CHANGING element assigned
@@ -1334,7 +1334,7 @@
         String userUpdateStr = "UPDATE vm1.g1 SET e1='x'"; //$NON-NLS-1$
         
         helpFailUpdateProcedure(procedure, userUpdateStr,
-                                     FakeMetadataObject.Props.UPDATE_PROCEDURE, "Element symbol \"CHANGING.e1\" cannot be assigned a value.  Only declared VARIABLES can be assigned values."); //$NON-NLS-1$
+                                     FakeMetadataObject.Props.UPDATE_PROCEDURE);
     }
     
     // variables cannot be used among insert elements

Modified: trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -267,6 +267,20 @@
         Procedure vsp7 = createVirtualProcedure("TEIIDSP7", mmspTest1, Arrays.asList(vsp7p1), vspqn7); //$NON-NLS-1$
         vsp7.setResultSet(vsprs7);
         
+        ProcedureParameter vsp8p1 = createParameter("r", ParameterInfo.RETURN_VALUE, DataTypeManager.DefaultDataTypes.INTEGER); //$NON-NLS-1$
+        ProcedureParameter vsp8p2 = createParameter("p1", ParameterInfo.IN, DataTypeManager.DefaultDataTypes.INTEGER); //$NON-NLS-1$
+        QueryNode vspqn8 = new QueryNode("TEIIDSP8", "CREATE VIRTUAL PROCEDURE BEGIN r = p1; END"); //$NON-NLS-1$ //$NON-NLS-2$
+        createVirtualProcedure("TEIIDSP8", mmspTest1, Arrays.asList(vsp8p1, vsp8p2), vspqn8); //$NON-NLS-1$
+
+        ColumnSet<Procedure> vsprs9 = createResultSet("TEIIDSP9.vsprs1", new String[] { "StringKey" }, new String[] { DataTypeManager.DefaultDataTypes.STRING }); //$NON-NLS-1$ //$NON-NLS-2$
+        ProcedureParameter vsp9p1 = createParameter("r", ParameterInfo.RETURN_VALUE, DataTypeManager.DefaultDataTypes.INTEGER); //$NON-NLS-1$
+        vsp9p1.setNullType(NullType.No_Nulls);
+        ProcedureParameter vsp9p2 = createParameter("p1", ParameterInfo.IN, DataTypeManager.DefaultDataTypes.INTEGER); //$NON-NLS-1$
+        ProcedureParameter vsp9p3 = createParameter("p2", ParameterInfo.OUT, DataTypeManager.DefaultDataTypes.INTEGER); //$NON-NLS-1$
+        QueryNode vspqn9 = new QueryNode("TEIIDSP9", "CREATE VIRTUAL PROCEDURE BEGIN if (p1 = 1) begin\n r = 1; end\n p2 = 10; select 'hello'; END"); //$NON-NLS-1$ //$NON-NLS-2$
+        Procedure vsp9 = createVirtualProcedure("TEIIDSP9", mmspTest1, Arrays.asList(vsp9p1, vsp9p2, vsp9p3), vspqn9); //$NON-NLS-1$
+        vsp9.setResultSet(vsprs9);
+        
         // this is for the source added function
         bqt1.addFunction(new FunctionMethod("reverse", "reverse", "misc", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 
                 new FunctionParameter[] {new FunctionParameter("columnName", DataTypeManager.DefaultDataTypes.STRING, "")}, //$NON-NLS-1$ //$NON-NLS-2$

Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java	2011-01-21 13:38:38 UTC (rev 2868)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java	2011-01-21 15:59:53 UTC (rev 2869)
@@ -1674,7 +1674,7 @@
         // Validate
         ValidatorReport report = Validator.validate(command, metadata); 
         // Validate
-        assertEquals(1, report.getItems().size());  	
+        assertEquals(0, report.getItems().size());  	
     }
 	
     @Test public void testDefect21389() throws Exception{        



More information about the teiid-commits mailing list