mirror of https://github.com/apache/openjpa.git
OPENJPA-502
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@614812 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6a29ebffe4
commit
5a1faec471
|
@ -23,6 +23,29 @@ package org.apache.openjpa.conf;
|
|||
*/
|
||||
public class Compatibility {
|
||||
|
||||
/**
|
||||
* If a JPQL statement is not compliant with the JPA specification,
|
||||
* fail to parse it.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static final int JPQL_STRICT = 0;
|
||||
|
||||
/**
|
||||
* If a JPQL statement is not compliant with the JPA specification,
|
||||
* warn the first time that statement is parsed.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static final int JPQL_WARN = 1;
|
||||
|
||||
/**
|
||||
* Allow non-compliant extensions of JPQL.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static final int JPQL_EXTENDED = 2;
|
||||
|
||||
private boolean _strictIdValues = false;
|
||||
private boolean _hollowLookups = true;
|
||||
private boolean _checkStore = false;
|
||||
|
@ -30,6 +53,7 @@ public class Compatibility {
|
|||
private boolean _closeOnCommit = true;
|
||||
private boolean _quotedNumbers = false;
|
||||
private boolean _nonOptimisticVersionCheck = false;
|
||||
private int _jpql = JPQL_STRICT;
|
||||
|
||||
/**
|
||||
* Whether to require exact identity value types when creating object
|
||||
|
@ -146,8 +170,7 @@ public class Compatibility {
|
|||
* in a datastore transaction. Version of OpenJPA prior to 0.4.1 always
|
||||
* forced a version check.
|
||||
*/
|
||||
public void setNonOptimisticVersionCheck
|
||||
(boolean nonOptimisticVersionCheck) {
|
||||
public void setNonOptimisticVersionCheck(boolean nonOptimisticVersionCheck){
|
||||
_nonOptimisticVersionCheck = nonOptimisticVersionCheck;
|
||||
}
|
||||
|
||||
|
@ -159,4 +182,37 @@ public class Compatibility {
|
|||
public boolean getNonOptimisticVersionCheck() {
|
||||
return _nonOptimisticVersionCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not JPQL extensions are allowed. Defaults to
|
||||
* {@link #JPQL_STRICT}.
|
||||
*
|
||||
* @since 1.1.0
|
||||
* @see #JPQL_WARN
|
||||
* @see #JPQL_STRICT
|
||||
* @see #JPQL_EXTENDED
|
||||
*/
|
||||
public int getJPQL() {
|
||||
return _jpql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not JPQL extensions are allowed. Possible values: "warn",
|
||||
* "strict", "extended".
|
||||
*
|
||||
* @since 1.1.0
|
||||
* @see #JPQL_WARN
|
||||
* @see #JPQL_STRICT
|
||||
* @see #JPQL_EXTENDED
|
||||
*/
|
||||
public void setJPQL(String jpql) {
|
||||
if ("warn".equals(jpql))
|
||||
_jpql = JPQL_WARN;
|
||||
else if ("strict".equals(jpql))
|
||||
_jpql = JPQL_STRICT;
|
||||
else if ("extended".equals(jpql))
|
||||
_jpql = JPQL_EXTENDED;
|
||||
else
|
||||
throw new IllegalArgumentException(jpql);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,6 +119,10 @@ public class ExpressionStoreQuery
|
|||
public OpenJPAConfiguration getConfiguration() {
|
||||
return ctx.getStoreContext().getConfiguration();
|
||||
}
|
||||
|
||||
public QueryContext getQueryContext() {
|
||||
return ctx;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -46,8 +46,7 @@ public interface StoreContext {
|
|||
|
||||
/**
|
||||
* Return the broker for this context, if possible. Note that a broker
|
||||
* will be unavailable in remote contexts, and this method may throw
|
||||
* an exception to that effect.
|
||||
* will be unavailable in remote contexts, and this method may return null.
|
||||
*/
|
||||
public Broker getBroker();
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.openjpa.kernel.exps;
|
||||
|
||||
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
||||
import org.apache.openjpa.kernel.QueryContext;
|
||||
|
||||
/**
|
||||
* A Resolver is used to resolve listeners and class or entity names
|
||||
|
@ -51,4 +52,11 @@ public interface Resolver {
|
|||
* Return the OpenJPA configuration.
|
||||
*/
|
||||
public OpenJPAConfiguration getConfiguration ();
|
||||
|
||||
/**
|
||||
* The {@link QueryContext} for which this resolver was created
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public QueryContext getQueryContext();
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ import org.apache.commons.collections.map.LinkedMap;
|
|||
import org.apache.openjpa.kernel.ExpressionStoreQuery;
|
||||
import org.apache.openjpa.kernel.QueryContext;
|
||||
import org.apache.openjpa.kernel.QueryOperations;
|
||||
import org.apache.openjpa.kernel.StoreContext;
|
||||
import org.apache.openjpa.kernel.BrokerFactory;
|
||||
import org.apache.openjpa.kernel.exps.AbstractExpressionBuilder;
|
||||
import org.apache.openjpa.kernel.exps.Expression;
|
||||
import org.apache.openjpa.kernel.exps.ExpressionFactory;
|
||||
|
@ -44,12 +46,15 @@ import org.apache.openjpa.kernel.exps.QueryExpressions;
|
|||
import org.apache.openjpa.kernel.exps.Subquery;
|
||||
import org.apache.openjpa.kernel.exps.Value;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.lib.log.Log;
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.FieldMetaData;
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
import org.apache.openjpa.meta.ValueMetaData;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
import org.apache.openjpa.util.UserException;
|
||||
import org.apache.openjpa.conf.Compatibility;
|
||||
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
||||
import serp.util.Numbers;
|
||||
|
||||
/**
|
||||
|
@ -1078,12 +1083,15 @@ public class JPQLExpressionBuilder
|
|||
return factory.getCurrentTimestamp();
|
||||
|
||||
case JJTSELECTEXTENSION:
|
||||
assertQueryExtensions("SELECT");
|
||||
return eval(onlyChild(node));
|
||||
|
||||
case JJTGROUPBYEXTENSION:
|
||||
assertQueryExtensions("GROUP BY");
|
||||
return eval(onlyChild(node));
|
||||
|
||||
case JJTORDERBYEXTENSION:
|
||||
assertQueryExtensions("ORDER BY");
|
||||
return eval(onlyChild(node));
|
||||
|
||||
default:
|
||||
|
@ -1092,6 +1100,39 @@ public class JPQLExpressionBuilder
|
|||
}
|
||||
}
|
||||
|
||||
private void assertQueryExtensions(String clause) {
|
||||
OpenJPAConfiguration conf = resolver.getConfiguration();
|
||||
switch(conf.getCompatibilityInstance().getJPQL()) {
|
||||
case Compatibility.JPQL_WARN:
|
||||
// check if we've already warned for this query-factory combo
|
||||
StoreContext ctx = resolver.getQueryContext().getStoreContext();
|
||||
String query = currentQuery();
|
||||
if (ctx.getBroker() != null && query != null) {
|
||||
String key = getClass().getName() + ":" + query;
|
||||
BrokerFactory factory = ctx.getBroker().getBrokerFactory();
|
||||
Object hasWarned = factory.getUserObject(key);
|
||||
if (hasWarned != null)
|
||||
break;
|
||||
else
|
||||
factory.putUserObject(key, Boolean.TRUE);
|
||||
}
|
||||
Log log = conf.getLog(OpenJPAConfiguration.LOG_QUERY);
|
||||
if (log.isWarnEnabled())
|
||||
log.warn(_loc.get("query-extensions-warning", clause,
|
||||
currentQuery()));
|
||||
break;
|
||||
case Compatibility.JPQL_STRICT:
|
||||
throw new ParseException(_loc.get("query-extensions-error",
|
||||
clause, currentQuery()).getMessage());
|
||||
case Compatibility.JPQL_EXTENDED:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Compatibility.getJPQL() == "
|
||||
+ conf.getCompatibilityInstance().getJPQL());
|
||||
}
|
||||
}
|
||||
|
||||
protected void setImplicitTypes(Value val1, Value val2, Class expected) {
|
||||
super.setImplicitTypes(val1, val2, expected);
|
||||
|
||||
|
|
|
@ -64,6 +64,18 @@ public class ParseException
|
|||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* String constructor. Constructing the exception in this
|
||||
* manner makes the exception behave in the normal way - i.e., as
|
||||
* documented in the class "Throwable". The fields "errorToken",
|
||||
* "expectedTokenSequences", and "tokenImage" do not contain
|
||||
* relevant information. The JavaCC generated code does not use
|
||||
* these constructors.
|
||||
*/
|
||||
public ParseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has the standard behavior when this object has been
|
||||
* created using the standard constructors. Otherwise, it uses
|
||||
|
|
|
@ -64,7 +64,6 @@ import java.io.*;
|
|||
public class JPQL
|
||||
{
|
||||
String jpql;
|
||||
boolean extensionsEnabled = true;
|
||||
|
||||
|
||||
public JPQL (String jpql)
|
||||
|
@ -503,7 +502,7 @@ void select_expression() #SELECTEXPRESSION : { }
|
|||
}
|
||||
|
||||
|
||||
void select_extension() #SELECTEXTENSION(extensionsEnabled) : { }
|
||||
void select_extension() #SELECTEXTENSION : { }
|
||||
{
|
||||
scalar_function()
|
||||
}
|
||||
|
@ -627,7 +626,7 @@ void groupby_item() : { }
|
|||
}
|
||||
|
||||
|
||||
void groupby_extension() #GROUPBYEXTENSION(extensionsEnabled) : { }
|
||||
void groupby_extension() #GROUPBYEXTENSION : { }
|
||||
{
|
||||
scalar_function()
|
||||
}
|
||||
|
@ -1098,7 +1097,7 @@ void orderby_item() #ORDERBYITEM : { }
|
|||
}
|
||||
|
||||
|
||||
void orderby_extension() #ORDERBYEXTENSION(extensionsEnabled) : { }
|
||||
void orderby_extension() #ORDERBYEXTENSION : { }
|
||||
{
|
||||
aggregate_select_expression()
|
||||
}
|
||||
|
|
|
@ -58,3 +58,11 @@ unknown-identifier: Undeclared identifier "{0}".
|
|||
update-constant-value: Update expression "{0}" may only use literals \
|
||||
or parameters as update values.
|
||||
bad-parse: Encountered "{0}" at character {1}, but expected: {2}.
|
||||
query-extensions-warning: This JPQL query uses non-standard OpenJPA \
|
||||
extensions in the {0} clause. JPQL string: "{1}". Query execution will \
|
||||
proceed. The openjpa.Compatibility configuration setting is configured to \
|
||||
log a warning the first time a given extended query is encountered.
|
||||
query-extensions-error: This JPQL query uses non-standard OpenJPA \
|
||||
extensions in the {0} clause. JPQL string: "{1}". The \
|
||||
openjpa.Compatibility configuration setting is configured to disallow \
|
||||
JPQL extensions.
|
||||
|
|
|
@ -38,7 +38,8 @@ public abstract class GroupingTestCase
|
|||
protected abstract void prepareQuery(Query q);
|
||||
|
||||
public void setUp() {
|
||||
super.setUp(AllFieldTypes.class, CLEAR_TABLES);
|
||||
super.setUp(AllFieldTypes.class, CLEAR_TABLES,
|
||||
"openjpa.Compatibility", "JPQL=warn");
|
||||
|
||||
AllFieldTypes pc1 = new AllFieldTypes();
|
||||
AllFieldTypes pc2 = new AllFieldTypes();
|
||||
|
|
|
@ -25,7 +25,8 @@ import org.apache.openjpa.persistence.test.SingleEMTestCase;
|
|||
public class TestSubstring extends SingleEMTestCase {
|
||||
|
||||
public void setUp() {
|
||||
super.setUp(SimpleEntity.class, CLEAR_TABLES, "openjpa.Log", "SQL=TRACE");
|
||||
super.setUp(SimpleEntity.class, CLEAR_TABLES,
|
||||
"openjpa.Compatibility", "JPQL=extended");
|
||||
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
|
Loading…
Reference in New Issue