OPENJPA-1999: Optional support for non-sequential positional parameters - used Rick's provided patch for trunk.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1134128 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Heath Thomann 2011-06-09 23:16:09 +00:00
parent b9e61a8923
commit cabf34a6fd
9 changed files with 136 additions and 21 deletions

View File

@ -69,6 +69,7 @@ public class Compatibility {
private boolean _checkDatabaseForCascadePersistToDetachedEntity = false;
private boolean _overrideContextClassloader = true;
private boolean _parseAnnotationsForQueryMode = true;
private boolean _convertPositionalParametersToNamed = false;
/**
* Whether to require exact identity value types when creating object
@ -330,6 +331,14 @@ public class Compatibility {
public boolean getIgnoreDetachedStateFieldForProxySerialization() {
return _ignoreDetachedStateFieldForProxySerialization;
}
public boolean getConvertPositionalParametersToNamed() {
return _convertPositionalParametersToNamed;
}
public void setConvertPositionalParametersToNamed(boolean c) {
_convertPositionalParametersToNamed = c;
}
/**
* Whether OpenJPA should flush changes before detaching or serializing an

View File

@ -2038,7 +2038,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
* Create a new query metadata instance.
*/
protected QueryMetaData newQueryMetaData(Class<?> cls, String name) {
QueryMetaData meta = new QueryMetaData(name);
QueryMetaData meta =
new QueryMetaData(name, _conf.getCompatibilityInstance().getConvertPositionalParametersToNamed());
meta.setDefiningType(cls);
return meta;
}

View File

@ -25,6 +25,8 @@ import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.kernel.Query;
import org.apache.openjpa.kernel.QueryLanguages;
import org.apache.openjpa.kernel.jpql.JPQLParser;
import org.apache.openjpa.lib.meta.SourceTracker;
import org.apache.openjpa.lib.xml.Commentable;
@ -59,12 +61,14 @@ public class QueryMetaData
private int _lineNum;
private int _colNum;
private String _srcName;
private boolean _convertPositionalParametersToNamed;
/**
* Construct with the given name.
*/
protected QueryMetaData(String name) {
protected QueryMetaData(String name, boolean convertPositionalParametersToNamed) {
_name = name;
_convertPositionalParametersToNamed = convertPositionalParametersToNamed;
}
/**
@ -155,6 +159,9 @@ public class QueryMetaData
* The full query string, or null if none.
*/
public void setQueryString(String query) {
if (query != null && _convertPositionalParametersToNamed && JPQLParser.LANG_JPQL.equals(_language)) {
query = query.replaceAll("[\\?]", "\\:_");
}
_query = query;
}

View File

@ -44,7 +44,9 @@ import javax.persistence.Table;
query="select a from simple a where a.id=:id and a.name=:name"),
@NamedQuery(name="FindOne",
query="select s from simple s where s.name = ?1"),
@NamedQuery(name="FindAll", query="select s from simple s")
@NamedQuery(name="FindAll", query="select s from simple s"),
@NamedQuery(name="SelectWithPositionalParameterNonOneStart",
query="select a from simple a where a.id=?900 and a.name=?2")
})
@NamedNativeQueries( {

View File

@ -0,0 +1,75 @@
/*
* 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.query;
import javax.persistence.EntityManager;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
* This test was added for OPENJPA-1999. 'Add' support for allowing positional parameters to start at something other
* than 1 and allow for missing parameters.
*/
public class TestQueryConvertPositionalParameters extends SingleEMFTestCase {
EntityManager _em;
long _id;
String _name;
@Override
public void setUp() {
super.setUp(SimpleEntity.class, "openjpa.Compatibility", "ConvertPositionalParametersToNamed=true");
_em = emf.createEntityManager();
_em.getTransaction().begin();
SimpleEntity se = new SimpleEntity();
_name = "name--" + System.currentTimeMillis();
se.setName(_name);
_em.persist(se);
_em.getTransaction().commit();
_id = se.getId();
_em.clear();
}
@Override
public void tearDown() throws Exception {
if (_em.getTransaction().isActive()) {
_em.getTransaction().rollback();
}
_em.close();
// TODO Auto-generated method stub
super.tearDown();
}
public void testNamedPositionalStartAtNonOne() {
SimpleEntity se =
_em.createNamedQuery("SelectWithPositionalParameterNonOneStart", SimpleEntity.class).setParameter(900, _id)
.setParameter(2, _name).getSingleResult();
assertNotNull(se);
}
public void testJPQLPositionalStartAtNonOne() {
int idPos = 7;
int namePos = 908;
SimpleEntity se =
_em.createQuery("Select s FROM simple s where s.id=?" + idPos + " and s.name=?" + namePos,
SimpleEntity.class).setParameter(idPos, _id).setParameter(namePos, _name).getSingleResult();
assertNotNull(se);
}
}

View File

@ -1822,8 +1822,8 @@ public class AnnotationPersistenceMetaDataParser
continue;
}
meta = getRepository().addQueryMetaData(_cls, query.name());
meta.setQueryString(query.query());
meta.setLanguage(JPQLParser.LANG_JPQL);
meta.setQueryString(query.query());
for (QueryHint hint : query.hints())
meta.addHint(hint.name(), hint.value());
LockModeType lmt = processNamedQueryLockModeType(query);
@ -1895,8 +1895,8 @@ public class AnnotationPersistenceMetaDataParser
}
meta = getRepository().addQueryMetaData(null, query.name());
meta.setQueryString(query.query());
meta.setLanguage(QueryLanguages.LANG_SQL);
meta.setQueryString(query.query());
Class<?> res = query.resultClass();
if (ImplHelper.isManagedType(getConfiguration(), res))
meta.setCandidateType(res);

View File

@ -113,7 +113,8 @@ public class EntityManagerImpl
private EntityManagerFactoryImpl _emf;
private Map<FetchConfiguration,FetchPlan> _plans = new IdentityHashMap<FetchConfiguration,FetchPlan>(1);
protected RuntimeExceptionTranslator _ret = PersistenceExceptions.getRollbackTranslator(this);
private boolean _convertPositionalParams = false;
public EntityManagerImpl() {
// for Externalizable
}
@ -129,6 +130,9 @@ public class EntityManagerImpl
_emf = factory;
_broker = new DelegatingBroker(broker, _ret);
_broker.setImplicitBehavior(this, _ret);
_convertPositionalParams =
factory.getConfiguration().getCompatibilityInstance().getConvertPositionalParametersToNamed();
}
/**
@ -977,6 +981,10 @@ public class EntityManagerImpl
public OpenJPAQuery createQuery(String language, String query) {
assertNotCloseInvoked();
try {
// We need
if (query != null && _convertPositionalParams && JPQLParser.LANG_JPQL.equals(language)) {
query = query.replaceAll("[\\?]", "\\:_");
}
String qid = query;
PreparedQuery pq = JPQLParser.LANG_JPQL.equals(language)
? getPreparedQuery(qid) : null;
@ -1017,11 +1025,10 @@ public class EntityManagerImpl
_broker.getClassLoader(), true);
String qid = meta.getQueryString();
PreparedQuery pq = JPQLParser.LANG_JPQL.equals(meta.getLanguage())
? getPreparedQuery(qid) : null;
org.apache.openjpa.kernel.Query del = (pq == null || !pq.isInitialized())
? _broker.newQuery(meta.getLanguage(), meta.getQueryString())
: _broker.newQuery(pq.getLanguage(), pq);
PreparedQuery pq = JPQLParser.LANG_JPQL.equals(meta.getLanguage()) ? getPreparedQuery(qid) : null;
org.apache.openjpa.kernel.Query del =
(pq == null || !pq.isInitialized()) ? _broker.newQuery(meta.getLanguage(), meta.getQueryString())
: _broker.newQuery(pq.getLanguage(), pq);
if (pq != null) {
pq.setInto(del);
@ -1060,7 +1067,8 @@ public class EntityManagerImpl
}
protected <T> QueryImpl<T> newQueryImpl(org.apache.openjpa.kernel.Query kernelQuery) {
return new QueryImpl<T>(this, _ret, kernelQuery);
return new QueryImpl<T>(this, _ret, kernelQuery, _convertPositionalParams
&& !kernelQuery.getLanguage().equals(QueryLanguages.LANG_SQL));
}
/**

View File

@ -93,6 +93,7 @@ public class QueryImpl<X> implements OpenJPAQuerySPI<X>, Serializable {
private transient ReentrantLock _lock = null;
private HintHandler _hintHandler;
private boolean _relaxBindParameterTypeChecking;
final private boolean _convertPositionalParams;
/**
* Constructor; supply factory exception translator and delegate.
@ -101,19 +102,21 @@ public class QueryImpl<X> implements OpenJPAQuerySPI<X>, Serializable {
* @param ret Exception translator for this query
* @param query The underlying "kernel" query.
*/
public QueryImpl(EntityManagerImpl em, RuntimeExceptionTranslator ret, org.apache.openjpa.kernel.Query query) {
_em = em;
_query = new DelegatingQuery(query, ret);
_lock = new ReentrantLock();
}
public QueryImpl(EntityManagerImpl em, RuntimeExceptionTranslator ret, org.apache.openjpa.kernel.Query query,
boolean convertPositionalParams) {
_em = em;
_query = new DelegatingQuery(query, ret);
_lock = new ReentrantLock();
_convertPositionalParams = convertPositionalParams;
}
/**
* Constructor; supply factory and delegate.
*
* @deprecated
*/
public QueryImpl(EntityManagerImpl em, org.apache.openjpa.kernel.Query query) {
this(em, null, query);
public QueryImpl(EntityManagerImpl em, org.apache.openjpa.kernel.Query query, boolean convertPositionalParams) {
this(em, null, query, convertPositionalParams);
}
/**
@ -677,6 +680,10 @@ public class QueryImpl<X> implements OpenJPAQuerySPI<X>, Serializable {
* parameter of the query or if the argument is of incorrect type
*/
public OpenJPAQuery<X> setParameter(int pos, Object value) {
if (_convertPositionalParams == true) {
return setParameter("_"+String.valueOf(pos), value);
}
_query.assertOpen();
_em.assertNotCloseInvoked();
_query.lock();
@ -868,6 +875,9 @@ public class QueryImpl<X> implements OpenJPAQuerySPI<X>, Serializable {
* the same parameter position is bound already.
*/
public <T> Parameter<T> getParameter(int pos, Class<T> type) {
if (_convertPositionalParams == true) {
return getParameter("_"+String.valueOf(pos), type);
}
Parameter<?> param = getParameter(pos);
if (param.getParameterType().isAssignableFrom(type))
throw new IllegalArgumentException(param + " does not match the requested type " + type);
@ -944,6 +954,9 @@ public class QueryImpl<X> implements OpenJPAQuerySPI<X>, Serializable {
* @throws IllegalArgumentException if the parameter with the given position does not exist
*/
public Parameter<?> getParameter(int pos) {
if(_convertPositionalParams == true){
return getParameter("_"+String.valueOf(pos));
}
Parameter<?> param = getDeclaredParameters().get(pos);
if (param == null)
throw new IllegalArgumentException(_loc.get("param-missing-pos",

View File

@ -1704,8 +1704,8 @@ public class XMLPersistenceMetaDataParser
meta = getRepository().addQueryMetaData(null, name);
meta.setDefiningType(_cls);
meta.setQueryString(attrs.getValue("query"));
meta.setLanguage(JPQLParser.LANG_JPQL);
meta.setQueryString(attrs.getValue("query"));
String lockModeStr = attrs.getValue("lock-mode");
LockModeType lmt = processNamedQueryLockModeType(log, lockModeStr, name);
if (lmt != null) {
@ -1808,8 +1808,8 @@ public class XMLPersistenceMetaDataParser
meta = getRepository().addQueryMetaData(null, name);
meta.setDefiningType(_cls);
meta.setQueryString(attrs.getValue("query"));
meta.setLanguage(QueryLanguages.LANG_SQL);
meta.setQueryString(attrs.getValue("query"));
String val = attrs.getValue("result-class");
if (val != null) {
Class<?> type = classForName(val);