You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2013/05/08 23:38:30 UTC
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...
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;