You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by rm...@apache.org on 2015/06/07 03:05:23 UTC

svn commit: r1683972 [1/2] - in /openjpa/branches/openjpa_jpa-2.1: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/identifier/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ openjp...

Author: rmannibucau
Date: Sun Jun  7 01:05:22 2015
New Revision: 1683972

URL: http://svn.apache.org/r1683972
Log:
OPENJPA-2592 basic stored procedure impl import

Added:
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/TestStoredProcedure.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/derby/
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/derby/Procedures.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/entity/
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/entity/EntityWithStoredProcedure.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/StoredProcedureQueryImpl.java
Modified:
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/identifier/DBIdentifier.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/AbstractPersistenceTestCase.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/MetaDataTag.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java
    openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/identifier/DBIdentifier.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/identifier/DBIdentifier.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/identifier/DBIdentifier.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/identifier/DBIdentifier.java Sun Jun  7 01:05:22 2015
@@ -46,6 +46,7 @@ public class DBIdentifier extends Identi
         INDEX,
         FOREIGN_KEY,
         CONSTANT,
+        PROCEDURE,
         NULL
     }
     
@@ -603,6 +604,10 @@ public class DBIdentifier extends Identi
         return newIdentifier(name,id, toUpper, delimit, false);
     }
 
+    public static DBIdentifier newProcedure(String name) {
+        return newIdentifier(name, DBIdentifierType.PROCEDURE);
+    }
+
     /**
      * Constructs a new identifier (potentially a compound QualifiedDBIdentifier) with the provided 
      * name an type. Optionally, converting the name to upper case and delimiting it.

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java Sun Jun  7 01:05:22 2015
@@ -910,6 +910,9 @@ public class JDBCStoreManager implements
         if (QueryLanguages.LANG_PREPARED_SQL.equals(language)) {
             return new PreparedSQLStoreQuery(this);
         }
+        if (QueryLanguages.LANG_STORED_PROC.equals(language)) {
+            return new StoredProcedureQuery(this);
+        }
         return null;
     }
     

Added: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java?rev=1683972&view=auto
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java (added)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java Sun Jun  7 01:05:22 2015
@@ -0,0 +1,212 @@
+/*
+ * 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 org.apache.openjpa.jdbc.meta.MappingRepository;
+import org.apache.openjpa.jdbc.meta.QueryResultMapping;
+import org.apache.openjpa.jdbc.schema.Column;
+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.QueryContext;
+import org.apache.openjpa.kernel.QueryOperations;
+import org.apache.openjpa.kernel.StoreQuery;
+import org.apache.openjpa.lib.rop.ResultObjectProvider;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.MultiQueryMetaData;
+import org.apache.openjpa.meta.QueryMetaData;
+import org.apache.openjpa.util.InternalException;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.Arrays.asList;
+
+/**
+ * Executes a stored procedure.
+ *
+ * @author ppoddar
+ *
+ */
+@SuppressWarnings("serial")
+public class StoredProcedureQuery extends AbstractStoreQuery {
+    private static final Object[] NO_PARAM = new Object[0];
+
+    JDBCStore _store;
+    StoredProcedure _proc;
+    private MultiQueryMetaData _meta;
+
+    public StoredProcedureQuery(JDBCStore store) {
+        _store = store;
+    }
+
+    public int getOperation() {
+        return QueryOperations.OP_SELECT;
+    }
+
+    public StoredProcedure getProcedure() {
+        return _proc;
+    }
+
+    public DBDictionary getDictionary() {
+        return _store.getDBDictionary();
+    }
+
+    @Override
+    public boolean setQuery(Object meta) {
+        if (meta == null || meta instanceof MultiQueryMetaData) {
+            _meta = (MultiQueryMetaData)meta;
+            return true;
+        } else {
+            throw new InternalException("Unknown " + meta);
+        }
+    }
+
+    public Executor newDataStoreExecutor(ClassMetaData meta,  boolean subclasses) {
+        List<QueryResultMapping> mappings = null;
+        List<Class<?>> classes = null;
+        if (_meta != null) {
+            List<QueryMetaData> parts = _meta.getComponents();
+            if (parts != null && !parts.isEmpty()) {
+                mappings = new ArrayList<QueryResultMapping>();
+                classes = new ArrayList<Class<?>>();
+                MappingRepository repos = _store.getConfiguration().getMappingRepositoryInstance();
+                for (QueryMetaData part : parts) {
+                    QueryResultMapping mapping = repos.getQueryResultMapping(ctx.getResultMappingScope(),
+                            part.getResultSetMappingName(),
+                            null, true);
+                    if (mapping != null) {
+                        mappings.add(mapping);
+                    }
+                    if (part.getResultType() != null) {
+                        classes.add(part.getResultType());
+                    }
+                }
+            }
+        }
+        return new StoredProcedureQueryExecutor(this, mappings, classes);
+    }
+
+    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 final List<Class<?>> _resultClasses;
+        private final List<QueryResultMapping> _resultMappings;
+
+        public StoredProcedureQueryExecutor(StoredProcedureQuery q, List<QueryResultMapping> resultMapping,
+                                            List<Class<?>> classes) {
+            QueryContext ctx = q.getContext();
+            _resultMappings = resultMapping;
+            _resultClasses = classes;
+            // 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());
+
+                final StoredProcedureQuery spq = StoredProcedureQuery.class.cast(q);
+                for (Column c : spq.getProcedure().getInColumns()) {
+                    dict.setUnknown(stmnt, c.getIndex() + 1, params[c.getIndex()], c);
+                }
+                for (Column c : spq.getProcedure().getInOutColumns()) {
+                    final int index = c.getIndex() + 1;
+                    stmnt.registerOutParameter(index, c.getType());
+                    dict.setUnknown(stmnt, index, params[index - 1], c);
+                }
+                for (Column c : spq.getProcedure().getOutColumns()) {
+                    stmnt.registerOutParameter(c.getIndex() + 1, c.getType());
+                }
+
+                JDBCFetchConfiguration fetch = (JDBCFetchConfiguration)q.getContext().getFetchConfiguration();
+                ResultObjectProvider rop = new XROP(_resultMappings, _resultClasses, _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 NO_PARAM;
+            Object[] array = new Object[userParams.size()];
+            int i = 0;
+            StoredProcedureQuery storedProcedureQuery = StoredProcedureQuery.class.cast(q);
+            for (final Column[] columns : asList(
+                    storedProcedureQuery.getProcedure().getInColumns(),
+                    storedProcedureQuery.getProcedure().getInOutColumns())) {
+                for (Column c : columns) {
+                    array[i] = userParams.get(c.getIdentifier().getName());
+                    if (array[i++] == null) {
+                        userParams.get(c.getIndex());
+                    }
+                }
+            }
+            return array;
+        }
+
+    }
+}

Added: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java?rev=1683972&view=auto
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java (added)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/XROP.java Sun Jun  7 01:05:22 2015
@@ -0,0 +1,205 @@
+/*
+ * 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 org.apache.openjpa.jdbc.meta.QueryResultMapping;
+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;
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * Gets multiple Result Object Providers each with different mapping.
+ *
+ * @author Pinaki Poddar
+ *
+ */
+public class XROP implements BatchedResultObjectProvider {
+    private final CallableStatement stmt;
+    private final JDBCFetchConfiguration fetch;
+    private final List<QueryResultMapping> _multi;
+    private final List<Class<?>> _resultClasses;
+    private int index;
+    private final JDBCStore store;
+    // Result of first execution
+    private boolean executionResult;
+
+    public XROP(List<QueryResultMapping> mappings, List<Class<?>> classes,
+                JDBCStore store, JDBCFetchConfiguration fetch,
+                CallableStatement stmt) {
+        _multi = mappings;
+        _resultClasses = classes;
+        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.
+     *
+     * @return a provider or null if the underlying statement has no more results.
+     */
+    @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);
+        try {
+            if (_resultClasses != null && _resultClasses.size() > index) {
+                Class<?> mapping = _resultClasses.get(index);
+                if (mapping != null) {
+                    return new GenericResultObjectProvider(mapping, store, fetch, res);
+                }
+            }
+            if (_multi != null && _multi.size() > index) {
+                QueryResultMapping mapping = _multi.get(index);
+                if (mapping != null) {
+                    return new MappedQueryResultObjectProvider(mapping, store, fetch, res);
+                }
+            }
+            return new SQLProjectionResultObjectProvider(store, fetch, res, null);
+        } finally {
+            index++;
+        }
+    }
+
+
+    /**
+     * 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 {
+            return stmt.getMoreResults();
+        } catch (SQLException e) {
+            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;
+        }
+    }
+
+    @Override
+    public Object getOut(String name) {
+        try {
+            return stmt.getObject(name);
+        } catch (SQLException e) {
+            return null;
+        }
+    }
+
+    @Override
+    public Object getOut(int position) {
+        try {
+            return stmt.getObject(position);
+        } catch (SQLException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 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);
+    }
+
+}

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java Sun Jun  7 01:05:22 2015
@@ -210,7 +210,7 @@ public class MappingRepository extends M
      * Return the query result mapping for the given name.
      */
     public QueryResultMapping getQueryResultMapping(Class<?> cls, String name, ClassLoader loader, boolean mustExist) {
-        QueryResultMapping res = null;
+        QueryResultMapping res;
         if (_locking) {
             synchronized (this) {
                 res = getQueryResultMappingInternal(cls, name, loader);
@@ -232,13 +232,13 @@ public class MappingRepository extends M
 
         // check cache
         Object key = getQueryResultKey(cls, name);
-        QueryResultMapping res = (QueryResultMapping) _results.get(key);
+        QueryResultMapping res = _results.get(key);
         if (res != null)
             return res;
 
         // get metadata for class, which will find results in metadata file
         if (cls != null && getMetaData(cls, envLoader, false) != null) {
-            res = (QueryResultMapping) _results.get(key);
+            res = _results.get(key);
             if (res != null)
                 return res;
         }
@@ -250,7 +250,7 @@ public class MappingRepository extends M
                     .getResultSetMappingScope(name, envLoader);
         // not in cache; load
         getMetaDataFactory().load(cls, MODE_META | MODE_MAPPING, envLoader);
-        return (QueryResultMapping) _results.get(key);
+        return _results.get(key);
     }
 
     /**

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/QueryResultMapping.java Sun Jun  7 01:05:22 2015
@@ -262,6 +262,7 @@ public class QueryResultMapping
         private Map<List<MetaDataContext>, ColumnMap> _mappings = null;
         private Map<List<MetaDataContext>, FetchInfo> _eager = null; 
         private FetchInfo _fetchInfo = null; // for top-level
+        private Collection<String> _constructorParams = null;
 
         /**
          * Supply candidate type on construction.
@@ -546,6 +547,13 @@ public class QueryResultMapping
                 info.excludes.clear(fm.getIndex());
             }
         }
+
+        public void addConstructorParam(final String name) {
+            if (_constructorParams == null) {
+                _constructorParams = new ArrayList<String>();
+            }
+            _constructorParams.add(name);
+        }
     }
 
     /**

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java Sun Jun  7 01:05:22 2015
@@ -62,6 +62,9 @@ public class Column
     private DBIdentifier _typeName = DBIdentifier.NULL;
     private int _javaType = JavaTypes.OBJECT;
     private int _size = 0;
+    private int _precision = -1;
+    private int _scale     = -1;
+    private int _radix     = 10;
     private int _decimals = 0;
     private String _defaultStr = null;
     private Object _default = null;
@@ -377,6 +380,29 @@ public class Column
         _decimals = digits;
     }
 
+    public int getPrecision() {
+        return _precision;
+    }
+
+    public void setPrecision(int p) {
+        _precision = p;
+    }
+
+    public int getScale() {
+        return _scale;
+    }
+
+    public void setScale(int s) {
+        _scale = s;
+    }
+    public int getRadix() {
+        return _radix;
+    }
+
+    public void setRadix(int r) {
+        _radix = r;
+    }
+
     /**
      * Return the default value set for the column, if any.
      */
@@ -492,6 +518,22 @@ public class Column
     }
 
     /**
+     * Sets nullability of this receiver by the given flag.
+     * @param flag one of the JDBC nullability flag namely
+     * <LI> {@link DatabaseMetaData#columnNullableUnknown} : not known if the column can be set to null value
+     * <LI> {@link DatabaseMetaData#columnNullable} : the column can be set to null value
+     * <LI> {@link DatabaseMetaData#columnNoNulls} : the column can not be set to null value
+     */
+    public void setNullability(short flag) {
+        switch (flag) {
+            case DatabaseMetaData.columnNullableUnknown : _notNull = null; break;
+            case DatabaseMetaData.columnNullable : _notNull = false; break;
+            case DatabaseMetaData.columnNoNulls : _notNull = true; break;
+
+        }
+    }
+
+    /**
      * Whether this column is auto-assigned a value on insert.
      */
     public boolean isAutoAssigned() {
@@ -610,7 +652,7 @@ public class Column
     /**
      * Set the column's 0-based index in the owning table.
      */
-    void setIndex(int index) {
+    public void setIndex(int index) {
         _index = index;
     }
 

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java Sun Jun  7 01:05:22 2015
@@ -60,6 +60,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 
 import javax.sql.DataSource;
 
@@ -4702,6 +4703,47 @@ public class DBDictionary
         return toDBName(namingUtil.getGeneratedKeySequenceName(col, maxAutoAssignNameLength));
     }
 
+    protected Map<String, StoredProcedure> _procs = new TreeMap<String, StoredProcedure>();
+
+    /**
+     * Gets the metadata of the stored procedure by the given name either from the cached version or
+     * by enquiring the database.
+     * @param meta the database meta data
+     * @param catalog the catalog name or null
+     * @param schema the schema name or null
+     * @param procedure the procedure name
+     * @return metadata about the named procedure or null
+     * @throws SQLException when metadata query goes wrong
+     */
+    public StoredProcedure getStoredProcedure(DatabaseMetaData meta, DBIdentifier catalog, DBIdentifier schema,
+                                              String procedure) throws SQLException {
+        if (_procs.containsKey(procedure)) {
+            return _procs.get(procedure);
+        }
+        ResultSet rs = meta.getProcedureColumns(
+                getCatalogNameForMetadata(catalog),
+                getSchemaNameForMetadata(schema),
+                procedure,
+                null);
+        StoredProcedure sp = null;
+        if (rs.next()) {
+            sp = new StoredProcedure(rs);
+        } else {
+            ResultSet rsExist = meta.getProcedures(
+                    getCatalogNameForMetadata(catalog),
+                    getSchemaNameForMetadata(schema),
+                    procedure);
+            if (rsExist.next()) {
+                sp = new StoredProcedure((String) null);
+                sp.setCatalog(catalog);
+                sp.setSchema(schema);
+                sp.setName(procedure);
+            }
+        }
+        _procs.put(procedure, sp);
+        return sp;
+    }
+
     ///////////////////////////////
     // Configurable implementation
     ///////////////////////////////

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java Sun Jun  7 01:05:22 2015
@@ -59,6 +59,7 @@ public class ResultSetResult
     private final Statement _stmnt;
     private final ResultSet _rs;
     private final DBDictionary _dict;
+    private boolean _closeStatement = true;
     private boolean _closeConn = true;
     private int _row = -1;
     private int _size = -1;
@@ -178,13 +179,17 @@ public class ResultSetResult
         _closeConn = closeConn;
     }
 
+    public void setCloseStatement(boolean closeStatement) {
+        _closeStatement = closeStatement;
+    }
+
     public void close() {
         super.close();
         try {
             _rs.close();
         } catch (SQLException se) {
         }
-        if (_stmnt != null)
+        if (_stmnt != null && _closeStatement)
             try {
                 _stmnt.close();
             } catch (SQLException se) {

Added: openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java?rev=1683972&view=auto
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java (added)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/StoredProcedure.java Sun Jun  7 01:05:22 2015
@@ -0,0 +1,338 @@
+/*
+ * 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.sql;
+
+import org.apache.openjpa.jdbc.identifier.DBIdentifier;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.Schemas;
+import org.apache.openjpa.meta.MultiQueryMetaData;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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
+ * its SQL body or parameters can be added.
+ * <br>
+ * This class can generate the SQL statement to create, drop or delete this procedure.
+ *
+ *
+ * @author Pinaki Poddar
+ *
+ */
+public class StoredProcedure {
+    private DBIdentifier _catalog;
+    private DBIdentifier _schema;
+    private DBIdentifier _name;
+    private List<Column> _cols = new ArrayList<Column>();
+    private List<String> _params = new ArrayList<String>();
+
+
+    private List<String> _sql = new ArrayList<String>();
+    private final boolean _fromDatabase;
+
+    /**
+     * An enumeration on type of parameter for a Stored Procedure.
+     * The enumerted values has the same ordinal numbers as found
+     * in corresponding integer values in {@link DatabaseMetaData}.
+     */
+    public enum PARAM {UNKNOW, IN, INOUT, RESULT, OUT, RETURN}
+
+    public enum SQL {NONE,MODIFY,READ, CONTAINS};
+
+    /**
+     * Create a procedure of the given name.
+     */
+    public StoredProcedure(String name) {
+        _name = DBIdentifier.newProcedure(name);
+        _fromDatabase = false;
+    }
+
+    /**
+     * <pre>
+     *
+     * 	1. PROCEDURE_CAT - String - the procedure catalog name
+     * 	2. PROCEDURE_SCHEM - String - the procedure schema name (possibly null)
+     * 	3. PROCEDURE_NAME - String - the procedure name
+     * 	4. COLUMN_NAME - String - the name of the column
+     * 	5. COLUMN_TYPE - short - the kind of column or parameter, as follows:
+     * 			DatabaseMetaData.procedureColumnUnknown - type unknown
+     * 			DatabaseMetaData.procedureColumnIn - an IN parameter
+     * 			DatabaseMetaData.procedureColumnInOut - an INOUT parameter
+     * 			DatabaseMetaData.procedureColumnOut - an OUT parameter
+     * 			DatabaseMetaData.procedureColumnReturn - a return value
+     * 			DatabaseMetaData.procedureReturnsResult - a result column in a result set
+     * 	6. DATA_TYPE - int - the SQL type of the data, as in java.sql.Types
+     * 	7. TYPE_NAME - String - the SQL type name, for a UDT it is fully qualified
+     * 	8. PRECISION - int - the precision
+     * 	9. LENGTH - int - the length of the data in bytes
+     * 	10.SCALE - short - the scale for numeric types
+     * 	11.RADIX - short - the Radix for numeric data (typically 2 or 10)
+     * 	12.NULLABLE - short - can the data contain null:
+     * 			DatabaseMetaData.procedureNoNulls - NULLs not permitted
+     * 			DatabaseMetaData.procedureNullable - NULLs are permitted
+     * 			DatabaseMetaData.procedureNullableUnknown - NULL status unknown
+     * 	13.REMARKS - String - an explanatory comment about the data item
+     * </pre>
+     **/
+
+    public StoredProcedure(ResultSet rs) throws SQLException {
+        _fromDatabase = true;
+        int i = 0;
+        do {
+            if (i == 0) {
+                // get stored procedure metadata
+                _catalog = DBIdentifier.newCatalog(rs.getString(1));
+                _schema = DBIdentifier.newSchema(rs.getString(2));
+                _name = DBIdentifier.newIdentifier(rs.getString(3), DBIdentifier.DBIdentifierType.PROCEDURE, false);
+            }
+            Column col = new Column();
+            _cols.add(col);
+            col.setIdentifier(DBIdentifier.newColumn(rs.getString(4)));
+            col.setFlag(rs.getShort(5), true);
+            col.setType(rs.getInt(6));
+            col.setTypeIdentifier(DBIdentifier.newConstant(rs.getString(7)));
+            col.setPrecision(rs.getInt(8));
+            col.setSize(rs.getInt(9));
+            col.setScale(rs.getInt(10));
+            col.setRadix(rs.getShort(11));
+            col.setNullability(rs.getShort(12));
+            col.setComment(rs.getString(13));
+            col.setIndex(i);
+            _params.add(col.getIdentifier().getName() + " " + col.getTypeIdentifier().getName());
+            i++;
+        } while (rs.next());
+    }
+
+    public void setCatalog(DBIdentifier catalog) {
+        this._catalog = catalog;
+    }
+
+    public void setSchema(DBIdentifier schema) {
+        this._schema = schema;
+    }
+
+    public void setName(String name) {
+        this._name = DBIdentifier.newIdentifier(name, DBIdentifier.DBIdentifierType.PROCEDURE, false);
+    }
+
+    public Column[] getInColumns() {
+        return getColumns((short)DatabaseMetaData.procedureColumnIn);
+    }
+
+    public Column[] getInOutColumns() {
+        return getColumns((short)DatabaseMetaData.procedureColumnInOut);
+    }
+
+    public Column[] getOutColumns() {
+        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
+     * @return
+     */
+    int countColumn(short flag) {
+        int count = 0;
+        for (Column col : _cols) {
+            if (col.getFlag(flag)) count++;
+        }
+        return count;
+    }
+
+    Column[] getColumns(short flag) { // TODO: cache?
+        List<Column> cols = null;
+        for (Column col : _cols) {
+            if (col.getFlag(flag)) {
+                if (cols == null) cols = new ArrayList<Column>();
+                cols.add(col);
+            }
+        }
+        return cols == null ? Schemas.EMPTY_COLUMNS : cols.toArray(new Column[cols.size()]);
+    }
+
+
+    /**
+     * Gets the name of this procedure.
+     */
+    public String getName() {
+        return _name.getName();
+    }
+
+    /**
+     * Adds an {@code IN} parameter of the given name and type.
+     * @param var name of the variable
+     * @param typeName name of the SQL type e.g. {@code VARCAR(32)}
+     * @return this procedure instance
+     */
+    public StoredProcedure addParameter(String var, String typeName) {
+        return addParameter(PARAM.IN, var, typeName);
+    }
+    /**
+     * Adds the given parameter declaration.
+     *
+     * @param param type of parameter.
+     * @param var name of the variable
+     * @param typeName name of the SQL type e.g. {@code VARCAR(32)}
+     * @return this procedure instance
+     */
+    public StoredProcedure addParameter(PARAM param, String var, String typeName) {
+        assertMutable();
+
+        _params.add(param + " " + var + " " + typeName);
+        return this;
+    }
+
+    public StoredProcedure setLanguage(String language) {
+        _sql.add("LANGUAGE " + language);
+        return this;
+    }
+
+    /**
+     * Gets the SQL for creating this procedure.
+     */
+    public String getCreateSQL() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("CREATE PROCEDURE ");
+        buf.append(_name);
+        buf.append(" (");
+        for (Iterator<String> p = _params.iterator(); p.hasNext();) {
+            buf.append(p.next());
+            buf.append(p.hasNext() ? "," : "");
+        }
+        buf.append(") ");
+        //buf.append("(");
+        for (String s : _sql) buf.append(s).append(" ");
+        //buf.append(")");
+
+        return buf.toString().trim();
+    }
+
+    /**
+     * Gets the SQL for dropping this procedure.
+     */
+    public String getDropSQL() {
+        return "DROP PROCEDURE " + _name;
+    }
+
+    /**
+     * Gets the SQL for calling this procedure.
+     */
+    public String getCallSQL() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("CALL ");
+        buf.append(_name); buf.append(" (");
+        for (Iterator<String> p = _params.iterator(); p.hasNext();) {
+            p.next();
+            buf.append("?");
+            if (p.hasNext()) buf.append(",");
+        }
+        buf.append(")");
+        return buf.toString().trim();
+    }
+
+    /**
+     * Adds a read SQL statement via an external method.
+     */
+    public StoredProcedure setSQL(SQL sql) {
+        switch (sql) {
+            case CONTAINS : _sql.add("CONTAINS SQL"); break;
+            case NONE     : _sql.add("NO SQL"); break;
+            case MODIFY   : _sql.add("MODIFIES SQL DATA"); break;
+            case READ     : _sql.add("READS SQL DATA"); break;
+        }
+        return this;
+    }
+
+    /**
+     * Sets the language whose parameter passing convention will be used to pass paramater values.
+     * @param lang
+     * @return
+     */
+    public StoredProcedure setParameterStyle(String lang) {
+        _sql.add("PARAMETER STYLE " + lang);
+        return this;
+    }
+
+    public StoredProcedure setExternalName(Class<?> cls, String method, Class<?>... paramTypes) {
+        assertStaticMethod(cls, method, paramTypes);
+        _sql.add("EXTERNAL NAME '" + cls.getName() + '.' + method + "'");
+        return this;
+    }
+
+    public StoredProcedure setResult(int i) {
+        return setResult(i, false);
+    }
+
+    public StoredProcedure setResult(int i, boolean dynamic) {
+        assertMutable();
+        _sql.add((dynamic ? "DYNAMIC " : "") + "RESULT SETS " + i);
+        return this;
+    }
+
+    private void assertStaticMethod(Class<?> cls, String method, Class<?>...paramTypes) {
+        try {
+            Method m = cls.getMethod(method, paramTypes);
+            if (m == null || !Modifier.isStatic(m.getModifiers())) {
+                throw new RuntimeException("No static method " + method + " with arguments "
+                        + Arrays.toString(paramTypes) + " in " + cls);
+            }
+        } catch (Exception ex) {
+            throw new RuntimeException("No static method " + method + " with arguments "
+                    + Arrays.toString(paramTypes) + " in " + cls, ex);
+        }
+    }
+
+    private void assertMutable() {
+        if (_fromDatabase) {
+            throw new IllegalStateException(this + " is not mutable");
+        }
+    }
+
+    public String toString() {
+        return getName();
+    }
+}

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java Sun Jun  7 01:05:22 2015
@@ -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;
@@ -1226,6 +1227,9 @@ public class QueryImpl
     protected 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/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryLanguages.java Sun Jun  7 01:05:22 2015
@@ -34,6 +34,7 @@ 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";
 

Added: openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java?rev=1683972&view=auto
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java (added)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryResultCallback.java Sun Jun  7 01:05:22 2015
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+/**
+ * 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 {
+        return kernel.toResult(storeQuery, executor, parent.getResultObject(), range);
+    }
+
+    public boolean hasMoreResults() {
+        return parent.hasMoreResults();
+    }
+
+    public boolean getExecutionResult() {
+        return parent.getExecutionResult();
+    }
+
+    public int getUpdateCount() {
+        return parent.getUpdateCount();
+    }
+
+    public Object getOut(int position) {
+        return parent.getOut(position);
+    }
+
+    public Object getOut(String name) {
+        return parent.getOut(name);
+    }
+}

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java Sun Jun  7 01:05:22 2015
@@ -2002,7 +2002,7 @@ public class MetaDataRepository implemen
             return null;
 
         // check cache
-        QueryMetaData qm = (QueryMetaData) _queries.get(name);
+        QueryMetaData qm = _queries.get(name);
         if (qm != null)
             return qm;
 
@@ -2030,10 +2030,10 @@ public class MetaDataRepository implemen
     public QueryMetaData[] getQueryMetaDatas() {
         if (_locking) {
             synchronized (this) {
-                return (QueryMetaData[]) _queries.values().toArray(new QueryMetaData[_queries.size()]);
+                return _queries.values().toArray(new QueryMetaData[_queries.size()]);
             }
         } else {
-            return (QueryMetaData[]) _queries.values().toArray(new QueryMetaData[_queries.size()]);
+            return _queries.values().toArray(new QueryMetaData[_queries.size()]);
         }
     }
     
@@ -2072,10 +2072,22 @@ public class MetaDataRepository implemen
         }
     }
 
+    public QueryMetaData addQueryMetaData(QueryMetaData meta) {
+        if (_locking) {
+            synchronized (this) {
+                final QueryMetaData queryMetaData = _queries.get(meta.getName());
+                return queryMetaData != null ? queryMetaData : _queries.put(meta.getName(), meta);
+            }
+        } else {
+            final QueryMetaData queryMetaData = _queries.get(meta.getName());
+            return queryMetaData != null ? queryMetaData : _queries.put(meta.getName(), meta);
+        }
+    }
+
     /**
      * Create a new query metadata instance.
      */
-    protected QueryMetaData newQueryMetaData(Class<?> cls, String name) {
+    public QueryMetaData newQueryMetaData(Class<?> cls, String name) {
         QueryMetaData meta =
             new QueryMetaData(name, _conf.getCompatibilityInstance().getConvertPositionalParametersToNamed());
         meta.setDefiningType(cls);
@@ -2118,7 +2130,7 @@ public class MetaDataRepository implemen
      * Searches all cached query metadata by name.
      */
     public QueryMetaData searchQueryMetaDataByName(String name) {        
-        return (QueryMetaData) _queries.get(name);
+        return _queries.get(name);
     }
     
     /**

Added: openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java?rev=1683972&view=auto
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java (added)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MultiQueryMetaData.java Sun Jun  7 01:05:22 2015
@@ -0,0 +1,189 @@
+/*
+ * 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;
+
+import org.apache.openjpa.kernel.QueryLanguages;
+
+
+
+/**
+ * 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 java.sql.ResultSet},
+ * each being mapped with a different mapping specification.
+ *
+ *
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public class MultiQueryMetaData extends QueryMetaData {
+    private final String _procedureName;
+    private final boolean _isTemporary;
+    private final List<QueryMetaData> _parts = new ArrayList<QueryMetaData>();
+    private final List<Parameter> _params = new ArrayList<MultiQueryMetaData.Parameter>();
+
+    /**
+     * Create this meta data given a scope of definition, a logical identifier, a procedure name
+     * and whether its usage is temporary.
+     * @param scope defining scope
+     * @param logicalName name as an identifier
+     * @param procedureName name of the database procedure
+     */
+    public MultiQueryMetaData(Class<?> scope, String logicalName, String procedureName, boolean isTemporary) {
+        super(logicalName, false);
+        setLanguage(QueryLanguages.LANG_STORED_PROC);
+        setSource(null, scope, -1, null);
+        _procedureName = procedureName;
+        _isTemporary = isTemporary;
+    }
+
+    public String getProcedureName() {
+        return _procedureName;
+    }
+
+    public List<QueryMetaData> getComponents() {
+        return _parts;
+    }
+
+    /**
+     * Affirms if this metadata is ephimeral.
+     * Ephimenral metadata is removed from the repository after usage.
+     * @return
+     */
+    public boolean isEphimeral() {
+        return _isTemporary;
+    }
+
+    @Override
+    public void setResultSetMappingName(String name) {
+        throw new UnsupportedOperationException("Not allowed to set mapping name. It is automatically set");
+    }
+
+    @Override
+    public void setResultType(Class cls) {
+        throw new UnsupportedOperationException("Not allowed to set result type. It is automatically set");
+    }
+
+    public void addComponent(Class<?> resultClass) {
+        QueryMetaData part = newQueryMetaData();
+        part.setResultType(resultClass);
+        _parts.add(part);
+    }
+
+    public void addComponent(String mappingName) {
+        QueryMetaData part = newQueryMetaData();
+        part.setResultSetMappingName(mappingName);
+        _parts.add(part);
+    }
+
+    private QueryMetaData newQueryMetaData() {
+        QueryMetaData part = new QueryMetaData(getName() + "#" + _parts.size(), false);
+        part.setLanguage(getLanguage());
+        part.setSource(null, getDefiningType(), -1, null);
+        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 enum Mode {IN,OUT,INOUT,CURSOR};
+        private final String name;
+        private final Class<?> type;
+        private final Mode mode;
+        private final int position;
+
+        public Parameter(String name, Class<?> type, Mode mode) {
+            this.name = name;
+            this.type = type;
+            this.mode = mode;
+            this.position = -1;
+        }
+
+        public Parameter(int position, Class<?> type, Mode mode) {
+            this.name = null;
+            this.type = type;
+            this.mode = mode;
+            this.position = position;
+        }
+
+        public int getPosition() {
+            return position;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Class<?> getType() {
+            return type;
+        }
+
+        public Mode getMode() {
+            return mode;
+        }
+    }
+
+
+
+}

Added: openjpa/branches/openjpa_jpa-2.1/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java?rev=1683972&view=auto
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java (added)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-lib/src/main/java/org/apache/openjpa/lib/rop/BatchedResultObjectProvider.java Sun Jun  7 01:05:22 2015
@@ -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.lib.rop;
+
+
+/**
+ * A provider for multiple result sets. 
+ * This provider acts as a container of other result providers. The underlying  providers
+ * contain the actual data and are {@link ResultObjectProvider#getResultObject() iterated}
+ * for the results, while this provider iterates over its underlying providers.
+ * <br>
+ * Designed for the specific purpose of getting results from the execution of Stored Procedures
+ * that can produce more than one result set and an optional update count. Few methods related
+ * to iterating multiple results and update count mirror the methods in JDBC {@link java.sql.Statement}.
+ * <br>
+ *
+ * @see org.apache.openjpa.kernel.QueryResultCallback
+ *
+ * @author Pinaki Poddar
+ *
+ */
+public interface BatchedResultObjectProvider extends ResultObjectProvider {
+    /**
+     * Gets the next result object provider from its batch. 
+     */
+    ResultObjectProvider getResultObject() throws Exception;
+
+    /**
+     * Affirms if this batch contains more results.
+     */
+    boolean hasMoreResults();
+
+    /**
+     * Gets the result of executing the underlying JDBC statement. 
+     * @return a boolean value whose semantics is same as {@link java.sql.PreparedStatement#execute()}. 
+     */
+    boolean getExecutionResult();
+
+
+    /**
+     * Gets the count of  records updated by the underlying JDBC statement. 
+     * @return an integer value whose semantics is same as {@link java.sql.CallableStatement#getUpdateCount()}.
+     */
+    int getUpdateCount();
+
+    Object getOut(String name);
+    Object getOut(int position);
+}

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java Sun Jun  7 01:05:22 2015
@@ -34,6 +34,7 @@ import javax.persistence.AttributeOverri
 import javax.persistence.AttributeOverrides;
 import javax.persistence.CollectionTable;
 import javax.persistence.ColumnResult;
+import javax.persistence.ConstructorResult;
 import javax.persistence.DiscriminatorColumn;
 import javax.persistence.DiscriminatorValue;
 import javax.persistence.EntityResult;
@@ -620,6 +621,9 @@ public class AnnotationPersistenceMappin
                     entityResult.addMapping(field.name(), sColName.getName());
                 }
             }
+            for (ConstructorResult constructorResult : anno.classes()) {
+                throw new UnsupportedOperationException("JPA 2.1, not yet impl");
+            }
             for (ColumnResult column : anno.columns()) {
                 DBIdentifier sName = DBIdentifier.newColumn(column.name(), delimit());
                 result.addColumnResult(sName.getName());
@@ -1577,9 +1581,9 @@ public class AnnotationPersistenceMappin
             }
             if (xmlRootElementClass != null
                 && StringUtils.isEmpty(pcols[i].columnDefinition())
-                && (AccessController.doPrivileged(J2DoPrivHelper
+                && AccessController.doPrivileged(J2DoPrivHelper
                     .isAnnotationPresentAction(fm.getDeclaredType(),
-                        xmlRootElementClass))).booleanValue()) {
+                        xmlRootElementClass)).booleanValue()) {
                 DBDictionary dict = ((MappingRepository) getRepository())
                     .getDBDictionary();
                 if (dict.supportsXMLColumn)

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/MappingTag.java Sun Jun  7 01:05:22 2015
@@ -114,5 +114,5 @@ enum MappingTag {
     X_MAPPING_OVERRIDES,
     X_SECONDARY_TABLE,
     X_SECONDARY_TABLES,
-    X_TABLE,
+    X_TABLE
 }

Added: openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/TestStoredProcedure.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/TestStoredProcedure.java?rev=1683972&view=auto
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/TestStoredProcedure.java (added)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/TestStoredProcedure.java Sun Jun  7 01:05:22 2015
@@ -0,0 +1,171 @@
+/*
+ * 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.procedure;
+
+import org.apache.openjpa.jdbc.procedure.derby.Procedures;
+import org.apache.openjpa.jdbc.procedure.entity.EntityWithStoredProcedure;
+import org.apache.openjpa.jdbc.sql.DerbyDictionary;
+import org.apache.openjpa.persistence.test.DatabasePlatform;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+import java.util.Iterator;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+import javax.persistence.StoredProcedureQuery;
+
+@DatabasePlatform("org.apache.derby.jdbc.EmbeddedDriver")
+public class TestStoredProcedure extends SingleEMFTestCase {
+    @Override
+    public void setUp() {
+        setUp(
+                "openjpa.RuntimeUnenhancedClasses", "unsupported",
+                "openjpa.DynamicEnhancementAgent", "false",
+                EntityWithStoredProcedure.class, EntityWithStoredProcedure.Mapping2.class);
+        setSupportedDatabases(DerbyDictionary.class);
+    }
+
+    public void testSimple() {
+        Procedures.simpleCalled = false;
+
+        EntityManager em = emf.createEntityManager();
+        exec(em, "CREATE PROCEDURE TESTSIMPLE() " +
+                "PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
+                "'" + Procedures.class.getName() + ".simple'");
+        StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.simple");
+        assertFalse(procedure.execute());
+        em.close();
+        assertTrue(Procedures.simpleCalled);
+    }
+
+    public void testInParams() {
+        Procedures.inParamsInteger = -1;
+        Procedures.inParamsString = null;
+
+        EntityManager em = emf.createEntityManager();
+        exec(em, "CREATE PROCEDURE TESTINS(some_number INTEGER,some_string VARCHAR(255)) " +
+                "PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
+                "'" + Procedures.class.getName() + ".inParams'");
+        StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.inParams");
+        procedure.setParameter("SOME_NUMBER", 2015);
+        procedure.setParameter("SOME_STRING", "openjpa");
+        assertFalse(procedure.execute());
+        assertEquals(2015, Procedures.inParamsInteger);
+        assertEquals("openjpa", Procedures.inParamsString);
+
+        // null case
+        Procedures.inParamsInteger = -1;
+        Procedures.inParamsString = null;
+        StoredProcedureQuery procedure2 = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.inParams");
+        procedure2.setParameter("SOME_NUMBER", 20152);
+        assertFalse(procedure2.execute());
+        em.close();
+        assertEquals(20152, Procedures.inParamsInteger);
+        assertNull(Procedures.inParamsString);
+    }
+
+    public void testOut() {
+        EntityManager em = emf.createEntityManager();
+        exec(em, "CREATE PROCEDURE XTWO(IN some_number INTEGER,OUT x2 INTEGER) " +
+                "PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
+                "'" + Procedures.class.getName() + ".x2'");
+        StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.x2");
+        procedure.setParameter("SOME_NUMBER", 5);
+        assertFalse(procedure.execute());
+        // assertEquals(10, procedure.getOutputParameterValue("result")); //  not impl by derby
+        assertEquals(10, procedure.getOutputParameterValue(2));
+        em.close();
+    }
+
+    public void testInOut() {
+        EntityManager em = emf.createEntityManager();
+        exec(em, "CREATE PROCEDURE XINOUT(INOUT P INTEGER) " +
+                "PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
+                "'" + Procedures.class.getName() + ".inout'");
+        StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.inout");
+        procedure.setParameter("P", 5);
+        assertFalse(procedure.execute());
+        // assertEquals(10, procedure.getOutputParameterValue("p")); //  not impl by derby
+        assertEquals(10, procedure.getOutputParameterValue(1));
+        em.close();
+    }
+
+    public void testMapping() {
+        EntityManager em = emf.createEntityManager();
+        {
+            em.getTransaction().begin();
+            for (int i = 0; i < 2; i++) {
+                final EntityWithStoredProcedure entity = new EntityWithStoredProcedure();
+                entity.setId(1 + i);
+                entity.setName("#" + entity.getId());
+                em.persist(entity);
+            }
+            em.getTransaction().commit();
+            em.clear();
+        }
+
+        exec(em, "CREATE PROCEDURE MAPPING() " +
+                "PARAMETER STYLE JAVA LANGUAGE JAVA DYNAMIC RESULT SETS 2 EXTERNAL NAME " +
+                "'" + Procedures.class.getName() + ".mapping'");
+        StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.mapping");
+        assertTrue(procedure.execute());
+        final Iterator r1 = procedure.getResultList().iterator();
+        final EntityWithStoredProcedure next1 = EntityWithStoredProcedure.class.cast(r1.next());
+        assertEquals(1, next1.getId());
+        assertEquals("#1", next1.getName());
+        assertNotNull(next1);
+        final EntityWithStoredProcedure next2 = EntityWithStoredProcedure.class.cast(r1.next());
+        assertNotNull(next2);
+        assertEquals(2, next2.getId());
+        assertEquals("#2", next2.getName());
+        assertFalse(r1.hasNext());
+        assertTrue(procedure.hasMoreResults());
+        final Iterator r2 = procedure.getResultList().iterator();
+        final EntityWithStoredProcedure.Mapping2 next3 = EntityWithStoredProcedure.Mapping2.class.cast(r2.next());
+        assertNotNull(next3);
+        assertFalse(r2.hasNext());
+        assertEquals(next2.getId(), next3.getId());
+        assertEquals(next2.getName(), next3.getName());
+
+        {
+            em.getTransaction().begin();
+            for (int i = 0; i < 2; i++) {
+                em.remove(em.find(EntityWithStoredProcedure.class, i + 1L));
+            }
+            em.getTransaction().commit();
+            em.clear();
+        }
+        em.close();
+    }
+
+    private void exec(final EntityManager em, final String proc) {
+        final EntityTransaction tx = em.getTransaction();
+        tx.begin();
+        try {
+            em.createNativeQuery(proc).executeUpdate();
+            tx.commit();
+        } catch (final Exception e) { // already exists or another error
+            e.printStackTrace();
+            try {
+                tx.rollback();
+            } catch (final Exception ignored) {
+                // no-op
+            }
+        }
+    }
+}

Added: openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/derby/Procedures.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/derby/Procedures.java?rev=1683972&view=auto
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/derby/Procedures.java (added)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/derby/Procedures.java Sun Jun  7 01:05:22 2015
@@ -0,0 +1,59 @@
+/*
+ * 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.procedure.derby;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+
+import static junit.framework.Assert.fail;
+
+public final class Procedures {
+    public static boolean simpleCalled;
+
+    public static void simple() {
+        simpleCalled = true;
+    }
+
+    public static int inParamsInteger;
+    public static String inParamsString;
+
+    public static void inParams(int integer, String string) {
+        inParamsInteger = integer;
+        inParamsString = string;
+    }
+
+    public static void x2(int integer, int[] out) {
+        out[0] = integer * 2;
+    }
+
+    public static void inout(int[] p) {
+        p[0] = p[0] * 2;
+    }
+
+    public static void mapping(ResultSet[] r0, ResultSet[] r1) {
+        try {
+            Connection c = DriverManager.getConnection("jdbc:default:connection");
+            r0[0] = c.createStatement().executeQuery("SELECT * FROM EntityWithStoredProcedure order by id");
+            r1[0] = c.createStatement().executeQuery("SELECT * FROM EntityWithStoredProcedure where id = 2");
+        } catch (final Exception ex) {
+            fail(ex.getMessage());
+        }
+    }
+}

Added: openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/entity/EntityWithStoredProcedure.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/entity/EntityWithStoredProcedure.java?rev=1683972&view=auto
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/entity/EntityWithStoredProcedure.java (added)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/procedure/entity/EntityWithStoredProcedure.java Sun Jun  7 01:05:22 2015
@@ -0,0 +1,145 @@
+/*
+ * 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.procedure.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.EntityResult;
+import javax.persistence.Id;
+import javax.persistence.NamedStoredProcedureQueries;
+import javax.persistence.NamedStoredProcedureQuery;
+import javax.persistence.SqlResultSetMapping;
+import javax.persistence.SqlResultSetMappings;
+import javax.persistence.StoredProcedureParameter;
+
+import static javax.persistence.ParameterMode.INOUT;
+import static javax.persistence.ParameterMode.OUT;
+
+@Entity
+@NamedStoredProcedureQueries({
+        @NamedStoredProcedureQuery(
+                name = "EntityWithStoredProcedure.simple",
+                procedureName = "TESTSIMPLE"
+        ),
+        @NamedStoredProcedureQuery(
+                name = "EntityWithStoredProcedure.inParams",
+                procedureName = "TESTINS",
+                parameters = {
+                        @StoredProcedureParameter(name = "SOME_NUMBER", type = Integer.class),
+                        @StoredProcedureParameter(name = "SOME_STRING", type = String.class)
+                }
+        ),
+        @NamedStoredProcedureQuery(
+                name = "EntityWithStoredProcedure.x2",
+                procedureName = "XTWO",
+                parameters = {
+                        @StoredProcedureParameter(name = "SOME_NUMBER", type = Integer.class),
+                        @StoredProcedureParameter(name = "RESULT", type = Integer.class, mode = OUT)
+                }
+        ),
+        @NamedStoredProcedureQuery(
+                name = "EntityWithStoredProcedure.inout",
+                procedureName = "XINOUT",
+                parameters = {
+                        @StoredProcedureParameter(name = "P ", type = Integer.class, mode = INOUT)
+                }
+        ),
+        @NamedStoredProcedureQuery(
+                name = "EntityWithStoredProcedure.mapping",
+                procedureName = "MAPPING",
+                resultSetMappings = {"mapping1", "mapping2"}
+        )
+})
+@SqlResultSetMappings({
+        @SqlResultSetMapping(
+                name = "mapping1",
+                entities = @EntityResult(entityClass = EntityWithStoredProcedure.class)
+        ),
+        @SqlResultSetMapping(
+                name = "mapping2",
+                entities = @EntityResult(entityClass = EntityWithStoredProcedure.Mapping2.class)
+        )
+})
+public class EntityWithStoredProcedure {
+    @Id
+    private long id;
+    private String name;
+
+    public EntityWithStoredProcedure() {
+        // no-op
+    }
+
+    public EntityWithStoredProcedure(final long id, final String name) {
+        this.id = id;
+        this.name = name;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        EntityWithStoredProcedure that = (EntityWithStoredProcedure) o;
+        return id == that.id && name.equals(that.name);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = (int) (id ^ (id >>> 32));
+        result = 31 * result + name.hashCode();
+        return result;
+    }
+
+    @Entity
+    public static class Mapping2 {
+        @Id
+        private long id;
+        private String name;
+
+        public long getId() {
+            return id;
+        }
+
+        public void setId(long id) {
+            this.id = id;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+}

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/AbstractPersistenceTestCase.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/AbstractPersistenceTestCase.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/AbstractPersistenceTestCase.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/AbstractPersistenceTestCase.java Sun Jun  7 01:05:22 2015
@@ -223,9 +223,9 @@ public abstract class AbstractPersistenc
      * Safely close the given factory.
      */
     protected boolean closeEMF(EntityManagerFactory emf) {
-        boolean brc = false;
+        boolean brc;
         if (emf == null || !emf.isOpen()) {
-            return brc;
+            return false;
         }
         try {
             closeAllOpenEMs(emf);

Modified: openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java
URL: http://svn.apache.org/viewvc/openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java?rev=1683972&r1=1683971&r2=1683972&view=diff
==============================================================================
--- openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java (original)
+++ openjpa/branches/openjpa_jpa-2.1/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java Sun Jun  7 01:05:22 2015
@@ -83,6 +83,10 @@ public abstract class AbstractQuery<X> i
         return result;
     }
 
+    public boolean isProcedure() {
+        return QueryLanguages.LANG_STORED_PROC.equals(getLanguage());
+    }
+
     public boolean isNative() {
         return QueryLanguages.LANG_SQL.equals(getLanguage());
     }
@@ -131,8 +135,8 @@ public abstract class AbstractQuery<X> i
             if (pos < 1) {
                 throw new IllegalArgumentException(_loc.get("illegal-index", pos).getMessage());
             }
-            Parameter<?> param = null;
-            if (isNative()) {
+            Parameter<?> param;
+            if (isNative() || isProcedure()) {
                 param = new ParameterImpl<Object>(pos, Object.class);
                 declareParameter(pos, param);
             } else {