openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ppod...@apache.org
Subject svn commit: r1480473 [1/2] - in /openjpa/sandboxes/21: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-jdbc/src/test/jav...
Date Wed, 08 May 2013 21:38:30 GMT
Author: ppoddar
Date: Wed May  8 21:38:29 2013
New Revision: 1480473

URL: http://svn.apache.org/r1480473
Log:
First draft of Stored Procedure query support

Added:
    openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java   (with props)
    openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java   (with props)
    openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MultiQueryResultSetMapping.java   (with props)
    openjpa/sandboxes/21/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestStoredProcedure.java   (with props)
    openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java   (with props)
    openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java   (with props)
    openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java   (with props)
    openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/TestStoredProcedure.java   (with props)
    openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java   (with props)
Modified:
    openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
    openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java
    openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
    openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java
    openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java
    openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
    openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java
    openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
    openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/QueryMetaData.java
    openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Services.java
    openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java
    openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java
    openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTestBroker.java
    openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Game.java
    openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java
    openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java
    openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java
    openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
    openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
    openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java
    openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java
    openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java
    openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java

Modified: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java (original)
+++ openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java Wed May  8 21:38:29 2013
@@ -907,9 +907,10 @@ public class JDBCStoreManager implements
         }
         if (QueryLanguages.LANG_SQL.equals(language)) {
             return new SQLStoreQuery(this);
-        }
-        if (QueryLanguages.LANG_PREPARED_SQL.equals(language)) {
+        } else if (QueryLanguages.LANG_PREPARED_SQL.equals(language)) {
             return new PreparedSQLStoreQuery(this);
+        } else if (QueryLanguages.LANG_STORED_PROC.equals(language)) {
+        	return new StoredProcedureQuery(this);
         }
         return null;
     }

Added: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java?rev=1480473&view=auto
==============================================================================
--- openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java (added)
+++ openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java Wed May  8 21:38:29 2013
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.jdbc.kernel;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.kernel.SQLStoreQuery.SQLExecutor;
+import org.apache.openjpa.jdbc.meta.MappingRepository;
+import org.apache.openjpa.jdbc.meta.MultiQueryResultSetMapping;
+import org.apache.openjpa.jdbc.meta.QueryResultMapping;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.StoredProcedure;
+import org.apache.openjpa.kernel.AbstractStoreQuery;
+import org.apache.openjpa.kernel.Query;
+import org.apache.openjpa.kernel.QueryContext;
+import org.apache.openjpa.kernel.QueryOperations;
+import org.apache.openjpa.kernel.AbstractStoreQuery.AbstractExecutor;
+import org.apache.openjpa.kernel.StoreQuery;
+import org.apache.openjpa.kernel.StoreQuery.Executor;
+import org.apache.openjpa.lib.jdbc.DelegatingCallableStatement;
+import org.apache.openjpa.lib.rop.ResultObjectProvider;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * Executes a stored procedure.
+ * 
+ * @author ppoddar
+ *
+ */
+@SuppressWarnings("serial")
+public class StoredProcedureQuery extends AbstractStoreQuery {
+	JDBCStore _store;
+	StoredProcedure _proc;
+	
+	public StoredProcedureQuery(JDBCStore store) {
+		_store = store;
+	}
+	
+	public int getOperation() {
+		return QueryOperations.OP_SELECT;
+	}
+	
+    public Executor newDataStoreExecutor(ClassMetaData meta,  boolean subclasses) {
+    	MultiQueryResultSetMapping resultMapping = null;
+    	String mappingName = ctx.getResultMappingName();
+        if (mappingName != null) {
+            ClassLoader envLoader = ctx.getStoreContext().getClassLoader();
+            MappingRepository repos = _store.getConfiguration().getMappingRepositoryInstance();
+            QueryResultMapping mapping = repos.getQueryResultMapping(ctx.getResultMappingScope(), mappingName, 
+            		envLoader, true);
+            if (mapping instanceof MultiQueryResultSetMapping) {
+            	resultMapping = (MultiQueryResultSetMapping)mapping;
+            } else {
+            	throw new RuntimeException("Bad mapping [" + mappingName + "]");
+            } 
+        }
+        return new StoredProcedureQueryExecutor(this, resultMapping);
+    }
+
+    public boolean supportsParameterDeclarations() {
+        return false;
+    }
+
+    public boolean supportsDataStoreExecution() {
+        return true;
+    }
+
+    public boolean requiresCandidateType() {
+        return false;
+    }
+
+    public boolean requiresParameterDeclarations() {
+        return false;
+    }
+    
+    
+    public class StoredProcedureQueryExecutor  extends AbstractExecutor {
+    	private MultiQueryResultSetMapping _resultMapping;
+    	
+    	public StoredProcedureQueryExecutor(StoredProcedureQuery q, MultiQueryResultSetMapping resultMapping) {
+            QueryContext ctx = q.getContext();
+            _resultMapping = resultMapping;
+       		// Look for the named Stored Procedure in the database
+            String procName = ctx.getQueryString();
+    		_proc = getStoredProcedure(_store.getConnection(), _store.getDBDictionary(), procName);
+    		if (_proc == null) {
+    			throw new RuntimeException("Can not find stored procedure " + procName);
+    		}
+    	}
+    	
+        StoredProcedure getStoredProcedure(Connection conn, DBDictionary dict, String procedureName) {
+    		try {
+    			StoredProcedure sp = dict.getStoredProcedure(conn.getMetaData(), null, null, procedureName);
+    			if (sp != null) {
+    				return sp;
+    			}
+    		} catch (SQLException ex) {
+        		throw new RuntimeException(ex);
+        	} finally {
+        		try {
+        			conn.close();
+        		} catch (SQLException ex) {
+        			
+        		}
+        	}
+			throw new RuntimeException("Procedure [" + procedureName + "] not found");
+        }
+    	
+		@Override
+		public ResultObjectProvider executeQuery(StoreQuery q, Object[] params, Range range) {
+			try {
+				DBDictionary dict = _store.getDBDictionary();
+				Connection conn = _store.getConnection();
+				CallableStatement stmnt = conn.prepareCall(_proc.getCallSQL());
+				for (int i = 0; i < params.length; i++) {
+					dict.setUnknown(stmnt, i+1, params[i], null);
+				}
+                JDBCFetchConfiguration fetch = (JDBCFetchConfiguration)q.getContext().getFetchConfiguration();
+            	ResultObjectProvider rop = new XROP(_resultMapping, _store, fetch, stmnt);
+            	rop.open();
+            	return rop;
+			} catch (Exception e) {
+				throw new RuntimeException(e);
+			}
+		}
+
+		@Override
+		public Object[] toParameterArray(StoreQuery q, Map<?, ?> userParams) {
+			if (userParams == null) return new Object[0];
+			Object[] array = new Object[userParams.size()];
+			int i = 0;
+			for (Map.Entry<?, ?> entry : userParams.entrySet()) {
+				array[i++] = entry.getValue();
+			}
+			return array;
+		}
+    
+    }
+}

Propchange: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java?rev=1480473&view=auto
==============================================================================
--- openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java (added)
+++ openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java Wed May  8 21:38:29 2013
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.jdbc.kernel;
+
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.openjpa.jdbc.meta.MultiQueryResultSetMapping;
+import org.apache.openjpa.jdbc.sql.ResultSetResult;
+import org.apache.openjpa.lib.rop.BatchedResultObjectProvider;
+import org.apache.openjpa.lib.rop.ResultObjectProvider;
+import org.apache.openjpa.util.InternalException;
+
+/**
+ * Gets multiple Result Object Providers each with different mapping.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class XROP implements BatchedResultObjectProvider {
+	private final PreparedStatement stmt;
+	private final JDBCFetchConfiguration fetch;
+	private final MultiQueryResultSetMapping _multi;
+	int index;
+	private final JDBCStore store;
+	// Result of first execution 
+	private boolean executionResult;
+	
+	public XROP(MultiQueryResultSetMapping mapping, JDBCStore store, JDBCFetchConfiguration fetch, 
+			PreparedStatement stmt) {
+		_multi = mapping;
+		this.stmt = stmt;
+		this.fetch = fetch;
+		this.store = store;
+	}
+	
+	/**
+	 * Does not support random access.
+	 */
+	@Override
+	public boolean supportsRandomAccess() {
+		return false;
+	}
+
+	/**
+	 * Opens this provider by executing the underlying Statment.
+	 * The result of execution is memorized. 
+	 */
+	@Override
+	public void open() throws Exception {
+		executionResult = stmt.execute();
+	}
+
+	/**
+	 * Gets the current result set, wraps it with a {@link ResultSetResult}, then wraps
+	 * again with appropriate ROP based on the result set mapping. 
+	 * <br>
+	 * The ResultSet and the associated connection must not be closed
+	 */
+	@Override
+	public ResultObjectProvider getResultObject() throws Exception {
+		ResultSet rs = stmt.getResultSet();
+		if (rs == null) 
+			return null;
+		
+		ResultSetResult res = new ResultSetResult(rs, store.getDBDictionary());
+		res.setCloseConnection(false);
+		res.setCloseStatement(false);
+		if (_multi == null) {
+			return new SQLProjectionResultObjectProvider(store, fetch, res, null);
+		}
+		return _multi.isClassMapping()
+		    ? new GenericResultObjectProvider(_multi.getResultType(index++), store, fetch, res)
+		    : new MappedQueryResultObjectProvider(_multi.getMapping(index++), store, fetch, res);
+		    
+	}
+
+
+	/**
+	 * Closes the underlying statement.
+	 */
+	@Override
+	public void close() throws Exception {
+		stmt.close();
+	}
+
+	/**
+	 * Affirms if more result sets are available.
+	 * <br>
+	 * <b.NOTE</b>: The side effect is to advance to the statement's next result.
+	 */
+    public boolean hasMoreResults() {
+    	try {
+			boolean result = stmt.getMoreResults();
+    		return result;
+		} catch (SQLException e) {
+			e.printStackTrace();
+		}
+		return false;
+    }
+    
+    public boolean getExecutionResult() {
+    	return executionResult;
+    }
+
+    /**
+     * Gets the update count, provided the current result of the statement is not a result set. 
+     */
+	@Override
+	public int getUpdateCount() {
+		try {
+			return stmt.getUpdateCount();
+		} catch (SQLException e) {
+			return -1;
+		}
+	}
+	
+	/**
+	 * Throws exception. 
+	 */
+	@Override
+	public boolean next() throws Exception {
+		throw new InternalException();
+	}
+
+	/**
+	 * Returns false.
+	 */
+	@Override
+	public boolean absolute(int pos) throws Exception {
+		return false;
+	}
+
+	/**
+	 * Returns {@code -1}.
+	 */
+	@Override
+	public int size() throws Exception {
+		return -1;
+	}
+
+	/**
+	 * Throws exception. 
+	 */
+	@Override
+	public void reset() throws Exception {
+		throw new InternalException();
+	}
+
+	@Override
+	public void handleCheckedException(Exception e) {
+		throw new RuntimeException(e);
+	}
+
+}

Propchange: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MultiQueryResultSetMapping.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MultiQueryResultSetMapping.java?rev=1480473&view=auto
==============================================================================
--- openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MultiQueryResultSetMapping.java (added)
+++ openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MultiQueryResultSetMapping.java Wed May  8 21:38:29 2013
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.jdbc.meta;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A mapping that is a composite of multiple mappings.
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+public class MultiQueryResultSetMapping extends QueryResultMapping {
+	private List<QueryResultMapping> _mappings;
+	private List<ClassMapping> _metas;
+	
+	public MultiQueryResultSetMapping(String name, MappingRepository repos) {
+		super(name, repos);
+	}
+	
+	public QueryResultMapping getMapping(int i) {
+		return _mappings.get(i);
+	}
+	public ClassMapping getResultType(int i) {
+		return _metas.get(i);
+	}
+	
+	public void addPart(Class<?> cls) {
+		if (_metas == null) {
+			_metas = new ArrayList<ClassMapping>();
+		}
+		ClassMapping meta = _repos.getMapping(cls, null, true);
+		_metas.add(meta);
+	}
+	
+	public void addPart(QueryResultMapping mapping) {
+		if (_mappings == null) {
+			_mappings = new ArrayList<QueryResultMapping>();
+		}
+		_mappings.add(mapping);
+	}
+	
+	public boolean isClassMapping() {
+		return _metas != null;
+	}
+
+}

Propchange: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MultiQueryResultSetMapping.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java (original)
+++ openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java Wed May  8 21:38:29 2013
@@ -53,7 +53,7 @@ public class QueryResultMapping
         (QueryResultMapping.class);
 
     private final String _name;
-    private final MappingRepository _repos;
+    protected final MappingRepository _repos;
     private File _file = null;
     private Object _scope = null;
     private int _srcType = SRC_OTHER;

Modified: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java (original)
+++ openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java Wed May  8 21:38:29 2013
@@ -60,6 +60,7 @@ public class ResultSetResult
     private final ResultSet _rs;
     private final DBDictionary _dict;
     private boolean _closeConn = true;
+    private boolean _closeStatement = true;
     private int _row = -1;
     private int _size = -1;
 
@@ -177,6 +178,23 @@ public class ResultSetResult
     public void setCloseConnection(boolean closeConn) {
         _closeConn = closeConn;
     }
+    
+    /**
+     * Whether to close the backing connection when this result is closed.
+     * Defaults to true.
+     */
+    public boolean getCloseStatement() {
+        return _closeStatement;
+    }
+
+    /**
+     * Whether to close the backing statment when this result is closed.
+     * Defaults to true.
+     */
+    public void setCloseStatement(boolean closeStatement) {
+    	_closeStatement = closeStatement;
+    }
+
 
     public void close() {
         super.close();
@@ -184,7 +202,7 @@ public class ResultSetResult
             _rs.close();
         } catch (SQLException se) {
         }
-        if (_stmnt != null)
+        if (_stmnt != null && _closeStatement)
             try {
                 _stmnt.close();
             } catch (SQLException se) {

Modified: openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java (original)
+++ openjpa/sandboxes/21/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java Wed May  8 21:38:29 2013
@@ -32,8 +32,12 @@ import org.apache.openjpa.jdbc.identifie
 import org.apache.openjpa.jdbc.identifier.DBIdentifier.DBIdentifierType;
 import org.apache.openjpa.jdbc.schema.Column;
 import org.apache.openjpa.jdbc.schema.Schemas;
+import org.apache.openjpa.meta.MultiQueryMetaData;
+
 /**
- * Holds metadata about a Stored Procedure.
+ * Holds metadata about a Database Stored Procedure. 
+ * This is different than {@link MultiQueryMetaData} which holds the metadata
+ * about what the user has specified.
  * <br>
  * An instance of this class can be constructed either by reading from database meta data
  * or by programatic assignment. If an instance if created programmatically, then
@@ -56,7 +60,6 @@ public class StoredProcedure {
 	private List<String> _sql = new ArrayList<String>();
 	private final boolean _fromDatabase;
 	
-	private static enum Action {CREATE, DROP, CALL};
 
 	/**
 	 * An enumeration on type of parameter for a Stored Procedure.
@@ -142,6 +145,18 @@ public class StoredProcedure {
 		return getColumns((short)DatabaseMetaData.procedureColumnOut);
 	}
 	
+	public Column[] getReturnColumns() {
+		return getColumns((short)DatabaseMetaData.procedureColumnReturn);
+	}
+	
+	public Column[] getResultColumns() {
+		return getColumns((short)DatabaseMetaData.procedureColumnResult);
+	}
+	
+	public Column[] getColumns() {
+		return _cols.toArray(new Column[_cols.size()]);
+	}
+	
 	/**
 	 * Counts the number of columns with the given flag.
 	 * @param flag

Added: openjpa/sandboxes/21/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestStoredProcedure.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestStoredProcedure.java?rev=1480473&view=auto
==============================================================================
--- openjpa/sandboxes/21/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestStoredProcedure.java (added)
+++ openjpa/sandboxes/21/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestStoredProcedure.java Wed May  8 21:38:29 2013
@@ -0,0 +1,96 @@
+package org.apache.openjpa.jdbc.sql;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Arrays;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
+import org.apache.openjpa.jdbc.schema.Column;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests reading the metadata about a Stored Procedure from a database.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class TestStoredProcedure extends TestCase {
+	private static DBDictionary _dict;
+	private static DatabaseMetaData _meta;
+	private String procedureName = "P1";
+	
+	public void setUp() throws Exception {
+		if (_dict != null) return;
+		JDBCConfiguration conf = new JDBCConfigurationImpl();
+		
+		String url  = System.getProperty("openjpa.ConnectionURL");
+		String user = System.getProperty("openjpa.ConnectionUserName");
+		String pwd  = System.getProperty("openjpa.ConnectionPassword");
+		Connection con = DriverManager.getConnection(url, user, pwd);
+		assertNotNull(con);
+		
+		_meta = con.getMetaData();
+		
+		_dict = new MySQLDictionary();
+		_dict.setConfiguration(conf);
+		_dict.connectedConfiguration(con);
+		createProcedure(con, procedureName);
+	}
+	
+	public void testReadFromDatabase() throws SQLException {
+		StoredProcedure proc = _dict.getStoredProcedure(_meta, null, null, procedureName);
+		assertNotNull(proc);
+		Column[] cols = proc.getColumns();
+		for (int i = 0; i < cols.length; i++) {
+			System.err.println(cols[i].getName() + " " + getFlag(cols[i]));
+		}
+		System.err.println("Columns " + proc.getColumns().length + " " 
+				+ Arrays.toString(proc.getColumns()));
+		assertEquals(procedureName, proc.getName());
+		assertEquals(1, proc.getInColumns().length);
+		assertEquals("NM", proc.getInColumns()[0].getIdentifier().getName());
+		assertEquals(1, proc.getOutColumns().length);
+		assertEquals("TOTAL", proc.getOutColumns()[0].getIdentifier().getName());
+		
+		System.err.println("Returns " + proc.getReturnColumns().length + " " 
+				+ Arrays.toString(proc.getReturnColumns()));
+		System.err.println("Results " + proc.getResultColumns().length + " " 
+				+ Arrays.toString(proc.getResultColumns()));
+
+	}
+	
+	
+	private void createProcedure(Connection con, String name) {
+		StoredProcedure procedure = new StoredProcedure(name);
+		try {
+			String createSQL = "CREATE PROCEDURE " + name + "(IN NM VARCHAR(20),OUT TOTAL INT) "
+            + "BEGIN "
+            + "SELECT p.NAME FROM PERSON p WHERE p.NAME=NM;"
+            + "SELECT a.CITY FROM ADDRESS a JOIN PERSON p WHERE a.OWNER=p.ID AND p.NAME=NM; "
+            + "SELECT COUNT(*) INTO TOTAL FROM PERSON p WHERE p.NAME=NM;"
+            + "END";
+
+			CallableStatement stmt = con.prepareCall(createSQL);
+			stmt.execute();
+		} catch (SQLException ex) {
+			
+		}
+	}
+	
+	String getFlag(Column col) {
+		StringBuilder buf = new StringBuilder();
+		if (col.getFlag(DatabaseMetaData.procedureColumnIn)) buf.append(" IN");
+		if (col.getFlag(DatabaseMetaData.procedureColumnInOut)) buf.append(" INOUT");
+		if (col.getFlag(DatabaseMetaData.procedureColumnOut)) buf.append(" OUT");
+		if (col.getFlag(DatabaseMetaData.procedureColumnResult)) buf.append(" RESULT");
+		if (col.getFlag(DatabaseMetaData.procedureColumnReturn)) buf.append(" RETURN");
+		if (col.getFlag(DatabaseMetaData.procedureColumnUnknown)) buf.append(" UNKNOWN");
+		
+		return buf.toString();
+	}
+}

Propchange: openjpa/sandboxes/21/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestStoredProcedure.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java (original)
+++ openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java Wed May  8 21:38:29 2013
@@ -150,7 +150,7 @@ public abstract class AbstractStoreQuery
                 }
             }
         }
-
+        
         public String[] getDataStoreActions(StoreQuery q, Object[] params,
             Range range) {
             return EMPTY_STRINGS;

Modified: openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java (original)
+++ openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java Wed May  8 21:38:29 2013
@@ -45,6 +45,7 @@ import org.apache.openjpa.kernel.exps.Pa
 import org.apache.openjpa.kernel.exps.QueryExpressions;
 import org.apache.openjpa.kernel.exps.Val;
 import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.rop.BatchedResultObjectProvider;
 import org.apache.openjpa.lib.rop.EagerResultList;
 import org.apache.openjpa.lib.rop.ListResultList;
 import org.apache.openjpa.lib.rop.MergedResultObjectProvider;
@@ -723,10 +724,8 @@ public class QueryImpl
     private StoreQuery.Executor createExecutor(boolean inMem) {
         assertCandidateType();
 
-        MetaDataRepository repos = _broker.getConfiguration().
-            getMetaDataRepositoryInstance();
-        ClassMetaData meta = repos.getMetaData(_class,
-            _broker.getClassLoader(), false);
+        MetaDataRepository repos = _broker.getConfiguration().getMetaDataRepositoryInstance();
+        ClassMetaData meta = repos.getMetaData(_class, _broker.getClassLoader(), false);
 
         ClassMetaData[] metas;
         if (_class == null || _storeQuery.supportsAbstractExecutors())
@@ -1224,9 +1223,12 @@ public class QueryImpl
     /**
      * Return the query result for the given result object provider.
      */
-    protected Object toResult(StoreQuery q, StoreQuery.Executor ex, 
+    public Object toResult(StoreQuery q, StoreQuery.Executor ex, 
         ResultObjectProvider rop, StoreQuery.Range range)
         throws Exception {
+    	if (rop instanceof BatchedResultObjectProvider) {
+    		return new QueryResultCallback(this, q, ex, (BatchedResultObjectProvider)rop, range);
+    	}
         // pack projections if necessary
         String[] aliases = ex.getProjectionAliases(q);
         if (!ex.isPacking(q)) {

Modified: openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java (original)
+++ openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java Wed May  8 21:38:29 2013
@@ -34,21 +34,19 @@ import org.apache.openjpa.util.InternalE
 public class QueryLanguages {
 
     public static final String LANG_SQL = "openjpa.SQL";
+    public static final String LANG_STORED_PROC = "openjpa.StoredProcedure.SQL";
     public static final String LANG_PREPARED_SQL = "openjpa.prepared.SQL";
     public static final String LANG_METHODQL = "openjpa.MethodQL";
 
-    private static Map _expressionParsers = new HashMap();
+    private static Map<String,ExpressionParser> _expressionParsers = new HashMap<String,ExpressionParser>();
     static {
         // Load and cache all the query languages available in the system.
-        Class[] classes = Services.getImplementorClasses(
-            ExpressionParser.class,
-            AccessController.doPrivileged(
-                J2DoPrivHelper.getClassLoaderAction(ExpressionParser.class)));
+        Class<ExpressionParser>[] classes = Services.getImplementorClasses(ExpressionParser.class,
+            AccessController.doPrivileged(J2DoPrivHelper.getClassLoaderAction(ExpressionParser.class)));
         for (int i = 0; i < classes.length; i++) {
             ExpressionParser ep;
             try {
-                ep = (ExpressionParser) AccessController.doPrivileged(
-                    J2DoPrivHelper.newInstanceAction(classes[i]));
+                ep = AccessController.doPrivileged(J2DoPrivHelper.newInstanceAction(classes[i]));
             } catch (PrivilegedActionException pae) {
                 throw new InternalException(pae.getException());
             } catch (InstantiationException e) {
@@ -66,6 +64,6 @@ public class QueryLanguages {
      * the specified language.
      */
     public static ExpressionParser parserForLanguage(String language) {
-        return (ExpressionParser) _expressionParsers.get(language);
+        return _expressionParsers.get(language);
     }
 }

Added: openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java?rev=1480473&view=auto
==============================================================================
--- openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java (added)
+++ openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java Wed May  8 21:38:29 2013
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.kernel;
+
+import org.apache.openjpa.kernel.StoreQuery.Executor;
+import org.apache.openjpa.kernel.StoreQuery.Range;
+import org.apache.openjpa.lib.rop.BatchedResultObjectProvider;
+import org.apache.openjpa.lib.rop.ResultObjectProvider;
+
+/**
+ * A callabck is used when a query results in multiple non-identical result sets.
+ * Designed to use with Stored Procedure Query.
+ *  
+ * @author ppoddar
+ *
+ */
+public class QueryResultCallback {
+	private final StoreQuery           storeQuery;
+	private final StoreQuery.Executor  executor;
+	private final BatchedResultObjectProvider parent;
+	private final StoreQuery.Range     range;
+	private final QueryImpl kernel;
+	
+	public QueryResultCallback(QueryImpl kernel, StoreQuery storeQuery, Executor executor, 
+			BatchedResultObjectProvider parent, Range range) {
+		super();
+		this.kernel     = kernel;
+		this.storeQuery = storeQuery;
+		this.executor = executor;
+		this.parent = parent;
+		this.range = range;
+	}
+	
+	public Object callback() throws Exception {
+		ResultObjectProvider rop = parent.getResultObject();
+		Object list = kernel.toResult(storeQuery, executor, rop, range);
+		return list;
+						
+	}
+	
+	public boolean hasMoreResults() {
+		return parent.hasMoreResults();
+	}
+	
+	public boolean getExecutionResult() {
+		return parent.getExecutionResult();
+	}
+	
+	public int getUpdateCount() {
+		return parent.getUpdateCount();
+	}
+	
+	
+}

Propchange: openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java (original)
+++ openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java Wed May  8 21:38:29 2013
@@ -1997,22 +1997,18 @@ public class MetaDataRepository implemen
 
     /**
      * Return query metadata for the given class, name, and classloader.
+     * Will trigger parsing the entities if the named query has not been 
+     * added to this receiver's cache.
      */
     private QueryMetaData getQueryMetaDataInternal(Class<?> cls, String name, ClassLoader envLoader) {
         if (name == null)
             return null;
-        QueryMetaData qm = null;
-        if (cls == null) {
-            qm = searchQueryMetaDataByName(name);
-            if (qm != null)
-                return qm;
-        }
         // check cache
-        qm = (QueryMetaData) _queries.get(name);
+        QueryMetaData qm = _queries.get(name);
         if (qm != null)
             return qm;
 
-        // get metadata for class, which will find queries in metadata file
+        // parse metadata for class, which will find queries in metadata file
         if (cls != null && getMetaData(cls, envLoader, false) != null) {
             qm = _queries.get(name);
             if (qm != null)
@@ -2054,61 +2050,36 @@ public class MetaDataRepository implemen
     public QueryMetaData getCachedQueryMetaData(String name) {
         if (_locking) {
             synchronized (this) {
-                return (QueryMetaData) _queries.get(name);
+                return _queries.get(name);
             }
         } else {
-            return (QueryMetaData) _queries.get(name);
+            return _queries.get(name);
         }
     }
 
     /**
-     * Add a new query metadata to the repository and return it.
-     */
-    public QueryMetaData addQueryMetaData(Class<?> cls, String name) {
-        if (_locking) {
-            synchronized (this) {
-                QueryMetaData meta = newQueryMetaData(cls, name);
-                _queries.put(name, meta);
-                return meta;
-            }
-        } else {
-            QueryMetaData meta = newQueryMetaData(cls, name);
-            _queries.put(name, meta);
-            return meta;   
-        }
-    }
-    
-    /**
-     * Add a new query metadata to the repository and return it.
+     * Add a given query metadata to the repository.
+     * If a metadata of the given name exists, then the given metadata is not overridden
+     * and the existing metadata is returned.
+     * 
+     * @param meta the given meta data to be added.
      * 
-     * @param name a moniker for the query
-     * @param q a query that has already been created by some other means
+     * @return existing metadata of the same name, if exists. Otherwise null.
      */
-    public QueryMetaData addQueryMetaData(String name, Query q) {
-    	boolean convert = _conf.getCompatibilityInstance().getConvertPositionalParametersToNamed();
+    public QueryMetaData addQueryMetaData(QueryMetaData meta) {
         if (_locking) {
             synchronized (this) {
-                QueryMetaData meta = new QueryMetaData(name, q, convert);
-                _queries.put(name, meta);
-                return meta;
+            	return (_queries.containsKey(meta.getName())) 
+            		 ? _queries.get(meta.getName())
+            		 : _queries.put(meta.getName(), meta);
             }
         } else {
-            QueryMetaData meta = new QueryMetaData(name, q, convert);
-            _queries.put(name, meta);
-            return meta;   
+        	return (_queries.containsKey(meta.getName())) 
+   		 		     ? _queries.get(meta.getName())
+   		 		     : _queries.put(meta.getName(), meta);
         }
     }
-
-
-    /**
-     * Create a new query metadata instance.
-     */
-    protected QueryMetaData newQueryMetaData(Class<?> cls, String name) {
-    	boolean convert = _conf.getCompatibilityInstance().getConvertPositionalParametersToNamed();
-        QueryMetaData meta = new QueryMetaData(name, convert);
-        meta.setDefiningType(cls);
-        return meta;
-    }
+    
 
     /**
      * Remove the given query metadata from the repository.
@@ -2145,9 +2116,9 @@ public class MetaDataRepository implemen
     /**
      * Searches all cached query metadata by name.
      */
-    public QueryMetaData searchQueryMetaDataByName(String name) {        
-        return (QueryMetaData) _queries.get(name);
-    }
+//    public QueryMetaData searchQueryMetaDataByName(String name) {        
+//        return (QueryMetaData) _queries.get(name);
+//    }
     
     /**
      * Return a unique key for a given class / name. The class argument can be null.

Added: openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java?rev=1480473&view=auto
==============================================================================
--- openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java (added)
+++ openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java Wed May  8 21:38:29 2013
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.meta;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Extends {@link QueryMetaData} to allow multiple {@link QueryMetaData#getResultType() result class} or 
+ * {@link QueryMetaData#getResultSetMappingName() mapping names}. 
+ * <br>
+ * Designed for mapping the results from a Stored Procudure that can produce more than one {@link ResultSet},
+ * each being mapped with a different mapping specification.
+ * 
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public class MultiQueryMetaData extends QueryMetaData {
+	private final List<Parameter> _params = new ArrayList<MultiQueryMetaData.Parameter>();
+	private final List<QueryMetaData> _parts = new ArrayList<QueryMetaData>();
+	
+	/**
+	 * Create this meta data given a scope of defiition and a name.
+	 * @param scope defining scope
+	 * @param name name as an identifier
+	 */
+	public MultiQueryMetaData(Class<?> scope, String name) {
+		super(scope, name);
+	}
+	
+	/**
+	 * Adds a new  metadata as a part to this metadata.
+	 * The name of the component metadata is {@code <name>#<index>} where {@code <name>} is the
+	 * name of this metadata itself, and {@code <index>} is the index at which the
+	 * new part is added.
+	 * <br>
+	 * The new part is not registered to the {@link MappingRepository#addQueryMetaData(QueryMetaData)
+	 * repository}. 
+	 * 
+	 * @return the new part metadata
+	 */
+	public QueryMetaData addComponent() {
+		QueryMetaData part = new QueryMetaData(getDefiningType(), getName() + "#" + _parts.size());
+		_parts.add(part);
+		return part;
+	}
+	
+	/**
+	 * Gets the component metadata at the given part index.
+	 * @param i a valid integer index
+	 * @return
+	 */
+	public QueryMetaData getComponent(int i) {
+		if (i < 0 || i >= _parts.size()) {
+			throw new ArrayIndexOutOfBoundsException("Invalid index " + i + ". Available " + _parts.size() + " parts");
+		}
+		return _parts.get(i);
+	}
+	
+	/**
+	 * Gets the number of component metadata contained in this metada.
+	 */
+	public int getComponentCount() {
+		return _parts.size();
+	}
+	
+	/**
+	 * Registers the given parameter.
+	 * @param p
+	 */
+	public void registerParameter(Parameter p) {
+		_params.add(p);
+	}
+	
+	public List<Parameter> getParameters() {
+		return _params;
+	}
+	
+	public int getParameterCount() {
+		return _params.size();
+	}
+	
+	
+	/**
+	 * A parameter 
+	 *
+	 */
+	public static class Parameter {
+		public static enum Mode {IN,OUT,INOUT,CURSOR};
+		private final String name;
+		private final Class<?> type;
+		private final Mode mode;
+		
+		public Parameter(String name, Class<?> type, Mode mode) {
+			this.name = name;
+			this.type = type;
+			this.mode = mode;
+		}
+	}
+	
+	
+
+}

Propchange: openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/QueryMetaData.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/QueryMetaData.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/QueryMetaData.java (original)
+++ openjpa/sandboxes/21/openjpa-kernel/src/main/java/org/apache/openjpa/meta/QueryMetaData.java Wed May  8 21:38:29 2013
@@ -20,7 +20,6 @@ package org.apache.openjpa.meta;
 
 import java.io.File;
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -34,11 +33,12 @@ import org.apache.openjpa.lib.util.Order
 import org.apache.openjpa.lib.xml.Commentable;
 
 /**
- * Holds metadata about named queries.
- *  Information stored in this instance gets transfered to
+ * Holds metadata about named queries. 
+ * Information stored in this instance gets transfered to
  * new {@link Query} instances.
  *
  * @author Steve Kim
+ * @author Pinaki Poddar
  */
 @SuppressWarnings("serial")
 public class QueryMetaData
@@ -72,18 +72,28 @@ public class QueryMetaData
     
     
     /**
-     * Construct with the given name.
+     * Construct with the given name within the given scope.
      */
-    protected QueryMetaData(String name, boolean convertPositionalParametersToNamed) {
+    public QueryMetaData(Class<?> scope, String name) {
+    	_class = scope;
         _name = name;
-        _convertPositionalParametersToNamed = convertPositionalParametersToNamed;
     }
     
-    protected QueryMetaData(String name, Query q, boolean convertPositionalParametersToNamed) {
-    	_name = name;
-    	_convertPositionalParametersToNamed = convertPositionalParametersToNamed;
+    public QueryMetaData(String name, Query q) {
+    	_name  = name;
+    	_class = null;
      	setFrom(q);
     }
+    
+    
+    public boolean getConvertPositionalParametersToNamed() {
+    	return _convertPositionalParametersToNamed;
+    }
+    
+    public QueryMetaData setConvertPositionalParametersToNamed(boolean convert) {
+    	_convertPositionalParametersToNamed = convert;
+    	return this;
+    }
 
     /**
      * Return the name for this query.
@@ -218,7 +228,7 @@ public class QueryMetaData
      * Set query template information into the given concrete
      * query instance. However, the language, query string, and
      * candidate class are assumed to be declared in the query
-     * instantiation, and hints are not transferred.
+     * instantiation.
      */
     public void setInto(Query query) {
         if (_candidate != null)

Added: openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java?rev=1480473&view=auto
==============================================================================
--- openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java (added)
+++ openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java Wed May  8 21:38:29 2013
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.lib.rop;
+
+public interface BatchedResultObjectProvider extends ResultObjectProvider {
+    public ResultObjectProvider getResultObject() throws Exception;
+    public boolean hasMoreResults();
+    public boolean getExecutionResult();
+    public int getUpdateCount();
+
+}

Propchange: openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Services.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Services.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Services.java (original)
+++ openjpa/sandboxes/21/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/Services.java Wed May  8 21:38:29 2013
@@ -59,7 +59,7 @@ public class Services {
      * Return an array of Strings of class names of all known service
      * implementors of the specified interface or class.
      */
-    public static String[] getImplementors(Class serviceClass) {
+    public static String[] getImplementors(Class<?> serviceClass) {
         return getImplementors(serviceClass, null);
     }
 
@@ -67,8 +67,7 @@ public class Services {
      * Return an array of Strings of class names of all known service
      * implementors of the specified interface or class.
      */
-    public static String[] getImplementors(Class serviceClass,
-        ClassLoader loader) {
+    public static String[] getImplementors(Class<?> serviceClass, ClassLoader loader) {
         return getImplementors(serviceClass.getName(), loader);
     }
 
@@ -86,22 +85,18 @@ public class Services {
      * implementors of the specified class name, as resolved by the specified
      * {@link ClassLoader}.
      */
-    public static String[] getImplementors(String serviceName,
-        ClassLoader loader) {
+    public static String[] getImplementors(String serviceName, ClassLoader loader) {
         if (loader == null)
-            loader = AccessController.doPrivileged(
-                J2DoPrivHelper.getContextClassLoaderAction());
+            loader = AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction());
 
         try {
-            Set resourceList = new TreeSet();
-            Enumeration resources = AccessController.doPrivileged(
-                J2DoPrivHelper.getResourcesAction(loader,
-                        PREFIX + serviceName));
-            while (resources.hasMoreElements())
-                addResources((URL) resources.nextElement(), resourceList);
-
-            return (String[]) resourceList.toArray(new String[resourceList
-                .size()]);
+            Set<String> resourceList = new TreeSet<String>();
+            Enumeration<URL> resources = AccessController.doPrivileged(
+                J2DoPrivHelper.getResourcesAction(loader, PREFIX + serviceName));
+            while (resources.hasMoreElements()) {
+                addResources(resources.nextElement(), resourceList);
+            }
+            return resourceList.toArray(new String[resourceList.size()]);
         } catch (PrivilegedActionException pae) {
             // silently swallow all exceptions.
         } catch (IOException ioe) {
@@ -115,7 +110,7 @@ public class Services {
      * Set. Class names are separated by lines. Lines starting with '#' are
      * ignored.
      */
-    private static void addResources(URL url, Set set) throws IOException {
+    private static void addResources(URL url, Set<String> set) throws IOException {
         InputStream in = null;
         BufferedReader reader = null;
         URLConnection urlCon = null;
@@ -156,14 +151,14 @@ public class Services {
         }
     }
 
-    public static Class[] getImplementorClasses(Class serviceClass) {
-        return getImplementorClasses(serviceClass.getName(), null);
+    public static <T> Class<T>[] getImplementorClasses(Class<T> serviceClass) {
+        return (Class<T>[])getImplementorClasses(serviceClass.getName(), null);
     }
 
-    public static Class[] getImplementorClasses(Class serviceClass,
+    public static <T> Class<T>[] getImplementorClasses(Class<T> serviceClass,
         ClassLoader loader) {
-        Set invalid = new HashSet();
-        Class[] classes = getImplementorClasses(serviceClass.getName(), loader);
+        Set<Class<?>> invalid = new HashSet<Class<?>>();
+        Class<?>[] classes = getImplementorClasses(serviceClass.getName(), loader);
 
         // filter out any classes that have any classloader issues wrt.
         // the specified service class.
@@ -171,11 +166,11 @@ public class Services {
             if (!serviceClass.isAssignableFrom(classes[i]))
                 invalid.add(classes[i]);
         if (invalid.size() != 0) {
-            List list = new ArrayList(Arrays.asList(classes));
+            List<Class<?>> list = new ArrayList<Class<?>>(Arrays.asList(classes));
             list.removeAll(invalid);
-            return (Class[]) list.toArray(new Class[list.size()]);
+            return (Class<T>[]) list.toArray(new Class[list.size()]);
         } else {
-            return classes;
+            return (Class<T>[]) classes;
         }
     }
 
@@ -184,12 +179,11 @@ public class Services {
      * specified class name(as resolved by the current thread's context class
      * loader).
      */
-    public static Class[] getImplementorClasses(String serviceName) {
+    public static Class<?>[] getImplementorClasses(String serviceName) {
         return getImplementorClasses(serviceName, null);
     }
 
-    public static Class[] getImplementorClasses(String serviceName,
-        ClassLoader loader) {
+    public static Class<?>[] getImplementorClasses(String serviceName, ClassLoader loader) {
         try {
             return getImplementorClasses(serviceName, loader, true);
         } catch (Exception cnfe) {
@@ -206,17 +200,16 @@ public class Services {
      * the classloader; otherwise, resolution failures will throw a
      * {@link ClassNotFoundException}.
      */
-    public static Class[] getImplementorClasses(String serviceName,
+    public static Class<?>[] getImplementorClasses(String serviceName,
         ClassLoader loader, boolean skipMissing) throws ClassNotFoundException {
         if (loader == null)
-            loader = AccessController.doPrivileged(
-                J2DoPrivHelper.getContextClassLoaderAction());
+            loader = AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction());
 
         String[] names = getImplementors(serviceName, loader);
         if (names == null)
             return new Class[0];
 
-        List classes = new ArrayList(names.length);
+        List<Class<?>> classes = new ArrayList<Class<?>>(names.length);
         for (int i = 0; i < names.length; i++) {
             try {
                 classes.add(Class.forName(names[i], false, loader));

Modified: openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java (original)
+++ openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java Wed May  8 21:38:29 2013
@@ -49,12 +49,15 @@ import javax.persistence.MapKeyEnumerate
 import javax.persistence.MapKeyJoinColumn;
 import javax.persistence.MapKeyJoinColumns;
 import javax.persistence.MapKeyTemporal;
+import javax.persistence.NamedStoredProcedureQueries;
+import javax.persistence.NamedStoredProcedureQuery;
 import javax.persistence.PrimaryKeyJoinColumn;
 import javax.persistence.PrimaryKeyJoinColumns;
 import javax.persistence.SecondaryTable;
 import javax.persistence.SecondaryTables;
 import javax.persistence.SqlResultSetMapping;
 import javax.persistence.SqlResultSetMappings;
+import javax.persistence.StoredProcedureParameter;
 import javax.persistence.Table;
 import javax.persistence.TableGenerator;
 import javax.persistence.Temporal;
@@ -73,6 +76,7 @@ import org.apache.openjpa.jdbc.meta.Fiel
 import org.apache.openjpa.jdbc.meta.FieldMappingInfo;
 import org.apache.openjpa.jdbc.meta.MappingInfo;
 import org.apache.openjpa.jdbc.meta.MappingRepository;
+import org.apache.openjpa.jdbc.meta.MultiQueryResultSetMapping;
 import org.apache.openjpa.jdbc.meta.QueryResultMapping;
 import org.apache.openjpa.jdbc.meta.SequenceMapping;
 import org.apache.openjpa.jdbc.meta.ValueMapping;
@@ -85,14 +89,18 @@ import org.apache.openjpa.jdbc.schema.Co
 import org.apache.openjpa.jdbc.schema.Schemas;
 import org.apache.openjpa.jdbc.schema.Unique;
 import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.kernel.QueryLanguages;
 import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.meta.SourceTracker;
 import org.apache.openjpa.lib.util.J2DoPrivHelper;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
 import org.apache.openjpa.meta.JavaTypes;
 import org.apache.openjpa.meta.MetaDataContext;
+import org.apache.openjpa.meta.MultiQueryMetaData;
 import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser;
+
 import static org.apache.openjpa.persistence.jdbc.MappingTag.*;
 import org.apache.openjpa.util.InternalException;
 import org.apache.openjpa.util.MetaDataException;
@@ -200,6 +208,8 @@ public class AnnotationPersistenceMappin
         _tags.put(XSecondaryTable.class, X_SECONDARY_TABLE);
         _tags.put(XSecondaryTables.class, X_SECONDARY_TABLES);
         _tags.put(XTable.class, X_TABLE);
+        _tags.put(NamedStoredProcedureQueries.class, MappingTag.STOREDPROCEDURE_QUERIES);
+        _tags.put(NamedStoredProcedureQuery.class, MappingTag.STOREDPROCEDURE_QUERY);
     }
 
     public AnnotationPersistenceMappingParser(JDBCConfiguration conf) {
@@ -221,6 +231,14 @@ public class AnnotationPersistenceMappin
                 case TABLE_GEN:
                     parseTableGenerator(pkg, (TableGenerator) anno);
                     break;
+                case STOREDPROCEDURE_QUERIES:
+                    if (isQueryMode())
+                    	parseNamedStoredProcedureQueries(pkg, ((NamedStoredProcedureQueries) anno).value());
+                    break;
+                case STOREDPROCEDURE_QUERY:
+                    if (isQueryMode())
+                    	parseNamedStoredProcedureQueries(pkg, ((NamedStoredProcedureQuery) anno));
+                    break;
                 default:
                     throw new UnsupportedException(_loc.get("unsupported", pkg,
                         anno.toString()));
@@ -397,6 +415,14 @@ public class AnnotationPersistenceMappin
                 case X_SECONDARY_TABLE:
                 case X_SECONDARY_TABLES:
                     // no break; not supported yet
+                case STOREDPROCEDURE_QUERIES:
+                    if (isQueryMode() && (meta.getSourceMode() & MODE_QUERY)==0)
+                    	parseNamedStoredProcedureQueries(_cls, ((NamedStoredProcedureQueries) anno).value());
+                    break;
+                case STOREDPROCEDURE_QUERY:
+                    if (isQueryMode() && (meta.getSourceMode() & MODE_QUERY)==0)
+                    	parseNamedStoredProcedureQueries(_cls, ((NamedStoredProcedureQuery) anno));
+                    break;
                 default:
                     throw new UnsupportedException(_loc.get("unsupported", cm,
                         anno));
@@ -597,8 +623,7 @@ public class AnnotationPersistenceMappin
             if (log.isTraceEnabled())
                 log.trace(_loc.get("parse-sqlrsmapping", anno.name()));
 
-            QueryResultMapping result = repos.getCachedQueryResultMapping
-                (null, anno.name());
+            QueryResultMapping result = repos.getCachedQueryResultMapping(null, anno.name());
             if (result != null) {
                 if (log.isWarnEnabled())
                     log.warn(_loc.get("dup-sqlrsmapping", anno.name(), cm));
@@ -606,15 +631,12 @@ public class AnnotationPersistenceMappin
             }
 
             result = repos.addQueryResultMapping(null, anno.name());
-            result.setSource(getSourceFile(), cm.getDescribedType(),
-                result.SRC_ANNOTATIONS);
+            result.setSource(getSourceFile(), cm.getDescribedType(), SourceTracker.SRC_ANNOTATIONS);
 
             for (EntityResult entity : anno.entities()) {
-                QueryResultMapping.PCResult entityResult = result.addPCResult
-                    (entity.entityClass());
+                QueryResultMapping.PCResult entityResult = result.addPCResult(entity.entityClass());
                 if (!StringUtils.isEmpty(entity.discriminatorColumn()))
-                    entityResult.addMapping(entityResult.DISCRIMINATOR,
-                        entity.discriminatorColumn());
+                    entityResult.addMapping(QueryResultMapping.PCResult.DISCRIMINATOR, entity.discriminatorColumn());
 
                 for (FieldResult field : entity.fields()) {
                     DBIdentifier sColName = DBIdentifier.newColumn(field.column(), delimit());
@@ -2140,4 +2162,47 @@ public class AnnotationPersistenceMappin
     private boolean delimit() {
         return _dict.getDelimitIdentifiers();
     }
+
+	private void parseNamedStoredProcedureQueries(AnnotatedElement el, NamedStoredProcedureQuery... procs) {
+		for (NamedStoredProcedureQuery proc : procs) {
+			if (StringUtils.isEmpty(proc.name())) 
+	            throw new MetaDataException(_loc.get("stored-proc-no-name", el));
+			if (StringUtils.isEmpty(proc.procedureName())) 
+	            throw new MetaDataException(_loc.get("stored-proc-no-dbname", el));
+			
+			// Query metadata name 
+			MultiQueryMetaData meta = new MultiQueryMetaData(_cls, proc.name());
+			addQueryMetaData(el, meta);
+			meta.setResultSetMappingName(meta.getName()+ ".ResultSetMapping");
+	        meta.setLanguage(QueryLanguages.LANG_SQL);
+	        // Important: The query string is the name of the database stored procedure 
+	        meta.setQueryString(proc.procedureName());
+	
+	        // For each mapping name/result class, add a component metadata
+	        // The spec restricts that either ResultMappingName or ResultClasses be specified, 
+	        // but not both.
+	        // This is relevant because the order of mapping must match the order in which the
+	        // results are returned 
+	        MultiQueryResultSetMapping compositeMapping = new MultiQueryResultSetMapping(
+	        		meta.getName()+ ".ResultSetMapping", (MappingRepository)_repos);
+	        Class<?>[] resultClasses = proc.resultClasses();
+	        String[] resultSetMappings = proc.resultSetMappings();
+	        if (resultClasses.length > 0 && resultSetMappings.length > 0) 
+	        	throw new MetaDataException(_loc.get("stored-proc-both-mapping", el));
+	        for (Class<?> res : resultClasses) {
+	            meta.addComponent().setResultType(res);
+	        }
+	        for (String mapping : resultSetMappings) {
+	        	meta.addComponent().setResultSetMappingName(mapping);
+	        }
+	        StoredProcedureParameter[] params = proc.parameters();
+	        for (StoredProcedureParameter param : params) {
+	        	MultiQueryMetaData.Parameter p = new MultiQueryMetaData.Parameter(
+	        			param.name(), param.type(), toKernelParameterMode(param.mode()));
+	        	meta.registerParameter(p);
+	        }
+	        addHints(meta, proc.hints());
+	        addSourceInfo(el, meta);
+		}
+	}
 }

Modified: openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java (original)
+++ openjpa/sandboxes/21/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java Wed May  8 21:38:29 2013
@@ -58,6 +58,8 @@ enum MappingTag {
     SECONDARY_TABLES,
     SQL_RESULT_SET_MAPPING,
     SQL_RESULT_SET_MAPPINGS,
+    STOREDPROCEDURE_QUERIES,
+    STOREDPROCEDURE_QUERY,
     TABLE,
     TABLE_GEN,
     TEMPORAL,

Modified: openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTestBroker.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTestBroker.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTestBroker.java (original)
+++ openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTestBroker.java Wed May  8 21:38:29 2013
@@ -57,7 +57,7 @@ public class CacheTestBroker extends Bro
             super(broker, language, query);
         }
 
-        protected Object toResult(StoreQuery q, StoreQuery.Executor ex,
+        public Object toResult(StoreQuery q, StoreQuery.Executor ex,
             ResultObjectProvider rop, StoreQuery.Range range)
             throws Exception {
             boolean cached = rop instanceof ListResultObjectProvider

Added: openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/TestStoredProcedure.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/TestStoredProcedure.java?rev=1480473&view=auto
==============================================================================
--- openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/TestStoredProcedure.java (added)
+++ openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/TestStoredProcedure.java Wed May  8 21:38:29 2013
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.jdbc.mapping;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Parameter;
+import javax.persistence.StoredProcedureQuery;
+
+import org.apache.openjpa.jdbc.sql.MySQLDictionary;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+
+/**
+ * Tests Stored Procedure related methods of JPA 2.1
+ * <br>
+ * This test creates a Stored Procedure named {@code MIGRATION} that returns multiple result sets.
+ * <br>
+ * The data for the test is stored in two simple tables {@code PERSON} and {@code CITY}.
+ * The stored procedure moves few people meeting certain criteria from one city to another. 
+ * <br>
+ * The data is hand crafted and hence it is possible to verify data integrity before and
+ * after the stored procedure is executed.
+ * <p>
+ * <b>NOTE</b>: The Stored Procedure is written in MySQL syntax. So the test is skipped
+ * unless MySQL database is configured.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class TestStoredProcedure extends SingleEMFTestCase {
+	static String PROCEDURE = "MIGRATION";
+	public static Random rng = new Random();
+	
+	private static int AGE_THRESHOLD = 20;
+	private static final String[] CITIES = {"Los Angeles", "San Francisco", "Dallas", "Bangalore","Bombay"};
+	private static final Map<String, int[]> POPULATION = new TreeMap<String, int[]>();
+	private static final int NPERSON = 100;
+	public void setUp() throws Exception {
+		super.setUp(USE_SINGLETON);
+		Connection con = emf.createEntityManager().unwrap(Connection.class);
+		if (!isDefined(con, PROCEDURE)) {
+			dropTables(con, "PERSON", "CITY");
+			createTables(con);
+			loadData(con, NPERSON);
+			createProcedure(con, PROCEDURE);
+		}
+	}
+	
+	public void testStoredProcedureByDatabaseProcedureName() {
+		if (getDBDictionary() instanceof MySQLDictionary == false) {
+			System.err.println("*** Skipping test " + this.getClass().getName() + ". Runs only with MySQL");
+			return;
+		}
+		EntityManager em = emf.createEntityManager();
+		StoredProcedureQuery spq = em.createStoredProcedureQuery(PROCEDURE);
+		spq.setParameter(1, AGE_THRESHOLD);
+		spq.setParameter(2, CITIES[0]);
+		spq.setParameter(3, CITIES[1]);
+		spq.setParameter(4, NPERSON);
+
+		assertTrue(spq.execute());
+		int rsCount = 0;
+		List<?> result = spq.getResultList();
+		System.err.println("Result Set " + (++rsCount));
+		print(result);
+		while (spq.hasMoreResults()) {
+			System.err.println("Result Set " + (++rsCount));
+			print(spq.getResultList());
+		}
+		assertEquals(3, rsCount);
+		
+		System.err.println("Update Count = " + spq.getUpdateCount());
+		Set<Parameter<?>> params = spq.getParameters();
+		for (Parameter<?> p : params) {
+			System.err.println(p);
+		}
+	}
+	
+	void print(List<?> result) {
+		for (Object row : result) {
+			if (row.getClass().isArray()) {
+				System.err.println(Arrays.toString((Object[])row));
+			} else {
+				System.err.println(row);
+			}
+		}
+	}
+	
+	public void createProcedure(Connection con, String proc) throws Exception {
+		// Move people who lives in city C1 to city C2 only if population of C1 > M and age of person < A
+		// Result Set #1 =  persons who have been moved 
+		// Result Set #2 =  cities with their population before migration
+		// Result Set #3 =  cities with their population after migration
+		// Result Set #2 =  names of the original cities from which people have been moved
+		// INOUT  M      =  the population threashold (in), the population of C1 after move
+		// OUT T         = total number of people moved in INOUT variable
+		// UPDATE COUNT  = total number of people moved 
+		String createSQL = 
+			  "CREATE PROCEDURE " + proc 
+              + "(IN A INT,"  	        // Input age threshold
+              + " IN C1 VARCHAR(20),"   // Original City
+              + " IN C2 VARCHAR(20),"   // Target City
+              + " INOUT M INT,"         // Input population threshold, output 
+              + " OUT T INT) "          // Total population
+              + "BEGIN "
+              // Result Set #1: All the cities with current population count
+              + "SELECT c.NAME,c.POPULATION FROM CITY c; "
+              // ResultSet #2: select persons who will be moved
+              + "SELECT p.NAME,p.AGE, c.NAME " 
+              + "   FROM PERSON p JOIN CITY c "
+              + "   WHERE p.CITY=c.NAME AND p.AGE < A AND c.NAME=C1 AND c.POPULATION < M;" 
+              + "SELECT COUNT(*) INTO T " 
+              + "   FROM PERSON p JOIN CITY c "
+              + "   WHERE p.CITY=c.NAME AND p.AGE < A AND c.NAME=C1 AND c.POPULATION < M;" 
+              // Update those persons' to their new city
+              + "UPDATE PERSON p SET p.CITY=C2 WHERE p.CITY=C1 AND p.AGE < A;"
+              + "SELECT p.CITY, COUNT(p.CITY) from PERSON p GROUP BY p.CITY;"
+              // Update population of all the cities
+              + "UPDATE CITY c SET c.POPULATION=(SELECT COUNT(*) FROM PERSON p WHERE p.CITY=c.NAME);"
+              + "END";
+		
+		try {
+			con.setAutoCommit(false);
+			CallableStatement stmt = con.prepareCall(createSQL);
+			stmt.execute();
+		} catch (SQLException e) {
+			System.err.println(e.getMessage());
+		} finally {
+			con.commit();
+		}
+	}
+	
+	public void dropProcedure(Connection con, String proc) {
+		try {
+			String dropSQL = "DROP PROCEDURE " + proc;
+			CallableStatement stmt = con.prepareCall(dropSQL);
+			stmt.execute();
+		} catch (SQLException e) {
+			System.err.println(e.getMessage());
+		}
+	}
+	
+	public boolean isDefined(Connection con, String proc) {
+		try {
+			return con.getMetaData().getProcedures(null, null, proc).next();
+		} catch (SQLException ex) {
+			return false;
+		}
+	}
+	public void createTables(Connection con) throws SQLException {
+		String createTable = "CREATE TABLE IF NOT EXISTS PERSON (" 
+			               + "NAME VARCHAR(20) PRIMARY KEY, AGE INT, CITY VARCHAR(20));";
+		
+		CallableStatement stmt = con.prepareCall(createTable);
+		stmt.execute();
+		
+		createTable  = "CREATE TABLE IF NOT EXISTS CITY (" 
+            + "NAME VARCHAR(20) PRIMARY KEY, POPULATION INT);";
+		stmt.execute(createTable);
+	}
+	
+	public void dropTables(Connection con, String... tables) throws SQLException {
+		for (String table : tables) {
+			String dropTable = "DROP TABLE IF EXISTS " + table;
+			CallableStatement stmt = con.prepareCall(dropTable);
+			stmt.execute();
+		}
+	}
+	
+	public void loadData(Connection con, int P) throws SQLException {
+		// Insert cities with 0 populations 
+		// Insert PEOPLE into Random cities with trandom age
+		PreparedStatement stmt = con.prepareStatement("INSERT INTO PERSON VALUES (?,?,?)");
+		for (int i = 0; i < P; i++) {
+			int age = rng.nextInt(100);
+			String city = CITIES[rng.nextInt(CITIES.length)];
+			int[] pop = POPULATION.get(city);
+			if (pop == null) pop = new int[2];
+			pop[age > AGE_THRESHOLD ? 1 : 0]++;
+			POPULATION.put(city, pop);
+
+			stmt.setString(1, "Person"+i);
+			stmt.setInt(2, age);
+			stmt.setString(3, city);
+			stmt.addBatch();
+		}
+		stmt.executeBatch();
+		stmt.clearBatch();
+		 
+		stmt = con.prepareStatement("INSERT INTO CITY VALUES (?,?)");
+		System.err.println("Populated database with " + NPERSON + " persons in " + CITIES.length + "cities");
+		System.err.println("[City]   [Age <" + AGE_THRESHOLD + "] + [Age >= " + AGE_THRESHOLD + "] = TOTAL");
+		
+		for (Map.Entry<String, int[]> e : POPULATION.entrySet()) {
+			String city = e.getKey();
+			int[]  pop  = e.getValue();
+			System.err.println(city + " " + pop[0] + "+" + pop[1] + " = " + (pop[0]+pop[1]));
+			
+			stmt.setString(1, city);
+			stmt.setInt(2,    pop[0]+pop[1]);
+			stmt.addBatch();
+		}
+		stmt.executeBatch();
+		stmt.clearBatch();
+	}
+
+}

Propchange: openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/TestStoredProcedure.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Game.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Game.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Game.java (original)
+++ openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Game.java Wed May  8 21:38:29 2013
@@ -32,18 +32,42 @@ import javax.persistence.GeneratedValue;
 import javax.persistence.Id;
 import javax.persistence.Inheritance;
 import javax.persistence.InheritanceType;
+import javax.persistence.NamedStoredProcedureQueries;
+import javax.persistence.NamedStoredProcedureQuery;
+
+import org.apache.openjpa.persistence.jdbc.query.TestNativeQueryProcedures;
 
 /**
  * Simple unrelated persistent entity used to test logically union queries. 
  * This class is root of an inheritance hierarchy using TABLE PER CLASS 
  * strategy. Polymorphic queries on this class needs to run logical union
  * of queries on all known subclasses. 
+ * <br>
+ * This class annotates Stored Procedure.
+ * 
+ * @see TestNativeQueryProcedures
  * 
  * @author Pinaki Poddar
  *
  */
 @Entity
 @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
+
+/**
+ * The procedures should be defined in the database.
+ * TestNativeQueryProcedures defines these queries during setUp().
+ */
+@NamedStoredProcedureQueries({
+	@NamedStoredProcedureQuery(
+		name="GAME_1", 
+		procedureName="GET_TWO_APPLICANTS", 	                   
+		resultClasses={Applicant.class, Game.class}),
+//	@NamedStoredProcedureQuery(
+//		name="GAME", 
+//		procedureName="X", 	
+//		resultSetMappings={"single","multiple"},                 
+//		resultClasses={String.class, Integer.class}),
+})
 public class Game {
 	@Id
 	@GeneratedValue

Modified: openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java (original)
+++ openjpa/sandboxes/21/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/procedure/DerbyProcedureList.java Wed May  8 21:38:29 2013
@@ -73,6 +73,7 @@ public class DerbyProcedureList extends 
         		.setResult(2)
 		        .setExternalName(this.getClass(), "getTwoApplicantsAndGames", String.class,String.class,
 		        		ResultSet[].class, ResultSet[].class));
+        
     }
 
     /**

Modified: openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java
URL: http://svn.apache.org/viewvc/openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java?rev=1480473&r1=1480472&r2=1480473&view=diff
==============================================================================
--- openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java (original)
+++ openjpa/sandboxes/21/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java Wed May  8 21:38:29 2013
@@ -93,7 +93,8 @@ public abstract class AbstractQuery<X> i
     }
 
     public boolean isNative() {
-        return QueryLanguages.LANG_SQL.equals(getLanguage());
+        return QueryLanguages.LANG_SQL.equals(getLanguage()) 
+            || QueryLanguages.LANG_STORED_PROC.equals(getLanguage());
     }
 
     protected abstract void assertOpen();
@@ -116,7 +117,7 @@ public abstract class AbstractQuery<X> i
      * 
      * @return empty map if no parameter is declared or no parameter is bound to this query. 
      */
-    Map<Object, Object> getParameterValues() {
+    public Map<Object, Object> getParameterValues() {
         Map<Object, Object> result = new HashMap<Object, Object>();
         if (_boundParams == null || _boundParams.isEmpty())
             return result;



Mime
View raw message