diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java index 453b76d27..9c58d35a2 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java @@ -55,17 +55,17 @@ public abstract class AbstractExpressionBuilder { protected static final int EX_UNSUPPORTED = 2; // common implicit type settings - protected static final Class TYPE_OBJECT = Object.class; - protected static final Class TYPE_STRING = String.class; - protected static final Class TYPE_CHAR_OBJ = Character.class; - protected static final Class TYPE_NUMBER = Number.class; - protected static final Class TYPE_COLLECTION = Collection.class; - protected static final Class TYPE_MAP = Map.class; + public static final Class TYPE_OBJECT = Object.class; + public static final Class TYPE_STRING = String.class; + public static final Class TYPE_CHAR_OBJ = Character.class; + public static final Class TYPE_NUMBER = Number.class; + public static final Class TYPE_COLLECTION = Collection.class; + public static final Class TYPE_MAP = Map.class; // contains types for setImplicitTypes - protected static final int CONTAINS_TYPE_ELEMENT = 1; - protected static final int CONTAINS_TYPE_KEY = 2; - protected static final int CONTAINS_TYPE_VALUE = 3; + public static final int CONTAINS_TYPE_ELEMENT = 1; + public static final int CONTAINS_TYPE_KEY = 2; + public static final int CONTAINS_TYPE_VALUE = 3; private static final Localizer _loc = Localizer.forPackage (AbstractExpressionBuilder.class); @@ -366,7 +366,7 @@ public abstract class AbstractExpressionBuilder { /** * Perform conversions to make values compatible. */ - private void convertTypes(Value val1, Value val2) { + public static void convertTypes(Value val1, Value val2) { Class t1 = val1.getType(); Class t2 = val2.getType(); @@ -415,7 +415,7 @@ public abstract class AbstractExpressionBuilder { /** * Perform conversions to make values compatible. */ - private void convertTypesQuotedNumbers(Value val1, Value val2) { + public static void convertTypesQuotedNumbers(Value val1, Value val2) { Class t1 = val1.getType(); Class t2 = val2.getType(); @@ -457,7 +457,7 @@ public abstract class AbstractExpressionBuilder { /** * Return true if given class can be used as a number. */ - private static boolean isNumeric(Class type) { + public static boolean isNumeric(Class type) { type = Filters.wrap(type); return Number.class.isAssignableFrom(type) || type == Character.TYPE || type == TYPE_CHAR_OBJ; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java index c0809443a..e352c7dad 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java @@ -413,33 +413,32 @@ public class TestTypesafeCriteria extends SQLListenerTestCase { assertEquivalence(q, jpql); } - @AllowFailure public void testParameters1() { String jpql = "SELECT c FROM Customer c Where c.status = :stat"; CriteriaQuery q = cb.create(); Root c = q.from(Customer.class); - Parameter param = cb.parameter(Integer.class); + Parameter param = cb.parameter(Integer.class, "stat"); q.select(c).where(cb.equal(c.get(Customer_.status), param)); assertEquivalence(q, jpql, new String[]{"stat"}, new Object[] {1}); } - @AllowFailure public void testParameters2() { - String jpql = "SELECT c FROM Customer c Where c.status = :stat AND c.name = :name"; + String jpql = "SELECT c FROM Customer c Where c.status = :stat AND " + + "c.name = :name"; CriteriaQuery q = cb.create(); Root c = q.from(Customer.class); Parameter param1 = cb.parameter(Integer.class, "stat"); Parameter param2 = cb.parameter(String.class, "name"); - q.select(c).where(cb.equal(c.get(Customer_.status), param1), - cb.equal(c.get(Customer_.name), param2)); + q.select(c).where(cb.and(cb.equal(c.get(Customer_.status), param1), + cb.equal(c.get(Customer_.name), param2))); - assertEquivalence(q, jpql, new String[] { "stat", "name" }, new Object[] { 1, "test" }); + assertEquivalence(q, jpql, new String[] { "stat", "name" }, + new Object[] { 1, "test" }); } - @AllowFailure public void testParameters3() { - String jpql = "SELECT c FROM Customer c Where c.status = :1"; + String jpql = "SELECT c FROM Customer c Where c.status = ?1"; CriteriaQuery q = cb.create(); Root c = q.from(Customer.class); Parameter param = cb.parameter(Integer.class); @@ -447,31 +446,31 @@ public class TestTypesafeCriteria extends SQLListenerTestCase { assertEquivalence(q, jpql, new Object[] { 1 }); } - @AllowFailure public void testParameters4() { - String jpql = "SELECT c FROM Customer c Where c.status = :1 AND c.name = :2"; + String jpql = "SELECT c FROM Customer c Where c.status = ?1 AND " + + "c.name = ?2"; CriteriaQuery q = cb.create(); Root c = q.from(Customer.class); Parameter param1 = cb.parameter(Integer.class); Parameter param2 = cb.parameter(Integer.class); - q.select(c).where(cb.equal(c.get(Customer_.status), param1), - cb.equal(c.get(Customer_.name), param2)); + q.select(c).where(cb.and(cb.equal(c.get(Customer_.status), param1), + cb.equal(c.get(Customer_.name), param2))); assertEquivalence(q, jpql, new Object[] { 1, "test" }); } - // collection-valued input parameter + // do not support collection-valued input parameter @AllowFailure public void testParameters5() { String jpql = "SELECT c FROM Customer c Where c.status IN (:coll)"; CriteriaQuery q = cb.create(); Root c = q.from(Customer.class); Parameter param1 = cb.parameter(List.class); - q.select(c).where(cb.equal(c.get(Customer_.status), param1)); + //q.select(c).where(cb.in(c.get(Customer_.status)).value(params1)); List vals = new ArrayList(); vals.add(1); vals.add(2); - assertEquivalence(q, jpql, new String[] {"coll"}, new Object[] {vals}); + //assertEquivalence(q, jpql, new String[] {"coll"}, new Object[] {vals}); } @AllowFailure diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java index 425900690..64f9440c9 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java @@ -34,10 +34,14 @@ import javax.persistence.criteria.Selection; import javax.persistence.criteria.Subquery; import javax.persistence.metamodel.Entity; +import org.apache.commons.collections.map.LinkedMap; +import org.apache.openjpa.kernel.exps.AbstractExpressionBuilder; import org.apache.openjpa.kernel.exps.ExpressionFactory; +import org.apache.openjpa.kernel.exps.Path; import org.apache.openjpa.kernel.exps.QueryExpressions; import org.apache.openjpa.kernel.exps.Value; import org.apache.openjpa.meta.ClassMetaData; +import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.persistence.meta.MetamodelImpl; import org.apache.openjpa.persistence.meta.Types; @@ -57,6 +61,7 @@ public class CriteriaQueryImpl implements CriteriaQuery { private List> _groups; private PredicateImpl _having; private Boolean _distinct; + private LinkedMap _parameterTypes; public CriteriaQueryImpl(MetamodelImpl model) { this._model = model; @@ -164,6 +169,14 @@ public class CriteriaQueryImpl implements CriteriaQuery { return null; } + public LinkedMap getParameterTypes() { + return _parameterTypes; + } + + public void setParameterTypes(LinkedMap parameterTypes) { + _parameterTypes = parameterTypes; + } + /** * Populate kernel expressions. */ @@ -184,11 +197,11 @@ public class CriteriaQueryImpl implements CriteriaQuery { // exps.fetchInnerPaths = null; // String[] // exps.fetchPaths = null; // String[] exps.filter = _where == null ? factory.emptyExpression() - : _where.toKernelExpression(factory, _model); + : _where.toKernelExpression(factory, _model, this); evalGrouping(exps, factory); exps.having = _having == null ? factory.emptyExpression() - : _having.toKernelExpression(factory, _model); + : _having.toKernelExpression(factory, _model, this); evalOrdering(exps, factory); // exps.operation = QueryOperations.OP_SELECT; @@ -199,6 +212,8 @@ public class CriteriaQueryImpl implements CriteriaQuery { exps.projections = toValues(factory, getSelectionList()); // exps.range = null; // Value[] // exps.resultClass = null; // Class + if (_parameterTypes != null) + exps.parameterTypes = _parameterTypes; return exps; } @@ -214,7 +229,7 @@ public class CriteriaQueryImpl implements CriteriaQuery { OrderImpl order = (OrderImpl)_orders.get(i); //Expression expr = order.getExpression(); //exps.ordering[i] = Expressions.toValue( - // (ExpressionImpl)expr, factory, _model); + // (ExpressionImpl)expr, factory, _model, this); //exps.orderingClauses[i] = assemble(firstChild); //exps.orderingAliases[i] = firstChild.text; @@ -231,7 +246,7 @@ public class CriteriaQueryImpl implements CriteriaQuery { for (int i = 0; i < groupByCount; i++) { Expression groupBy = _groups.get(i); exps.grouping[i] = Expressions.toValue( - (ExpressionImpl)groupBy, factory, _model);; + (ExpressionImpl)groupBy, factory, _model, this);; } } @@ -244,9 +259,68 @@ public class CriteriaQueryImpl implements CriteriaQuery { Value[] result = new Value[sels.size()]; int i = 0; for (Selection s : sels) { - result[i++] = ((ExpressionImpl)s).toValue(factory, _model); + result[i++] = ((ExpressionImpl)s).toValue(factory, _model, + this); } return result; } + void setImplicitTypes(Value val1, Value val2, Class expected) { + Class c1 = val1.getType(); + Class c2 = val2.getType(); + boolean o1 = c1 == AbstractExpressionBuilder.TYPE_OBJECT; + boolean o2 = c2 == AbstractExpressionBuilder.TYPE_OBJECT; + + if (o1 && !o2) { + val1.setImplicitType(c2); + if (val1.getMetaData() == null && !val1.isXPath()) + val1.setMetaData(val2.getMetaData()); + } else if (!o1 && o2) { + val2.setImplicitType(c1); + if (val2.getMetaData() == null && !val1.isXPath()) + val2.setMetaData(val1.getMetaData()); + } else if (o1 && o2 && expected != null) { + // we never expect a pc type, so don't bother with metadata + val1.setImplicitType(expected); + val2.setImplicitType(expected); + } else if (AbstractExpressionBuilder.isNumeric(val1.getType()) + != AbstractExpressionBuilder.isNumeric(val2.getType())) { + AbstractExpressionBuilder.convertTypes(val1, val2); + } + + // as well as setting the types for conversions, we also need to + // ensure that any parameters are declared with the correct type, + // since the JPA spec expects that these will be validated + org.apache.openjpa.kernel.exps.Parameter param = + val1 instanceof org.apache.openjpa.kernel.exps.Parameter ? + (org.apache.openjpa.kernel.exps.Parameter) val1 + : val2 instanceof org.apache.openjpa.kernel.exps.Parameter ? + (org.apache.openjpa.kernel.exps.Parameter) val2 : null; + Path path = val1 instanceof Path ? (Path) val1 + : val2 instanceof Path ? (Path) val2 : null; + + // we only check for parameter-to-path comparisons + if (param == null || path == null || _parameterTypes == null) + return; + + FieldMetaData fmd = path.last(); + if (fmd == null) + return; + + //TODO: + //if (expected == null) + // checkEmbeddable(path); + + Class type = path.getType(); + if (type == null) + return; + + Object paramKey = param.getParameterKey(); + if (paramKey == null) + return; + + // make sure we have already declared the parameter + if (_parameterTypes.containsKey(paramKey)) + _parameterTypes.put(paramKey, type); + } } diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java index f9c17429d..e5e829029 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java @@ -21,6 +21,7 @@ package org.apache.openjpa.persistence.criteria; import java.util.Collection; +import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.QueryBuilder.In; @@ -39,12 +40,14 @@ import org.apache.openjpa.persistence.meta.MetamodelImpl; public abstract class ExpressionImpl extends SelectionImpl implements Expression { - Value toValue(ExpressionFactory factory, MetamodelImpl model) { + Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { throw new AbstractMethodError(this.getClass().getName()); } org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { throw new AbstractMethodError(this.getClass().getName()); } diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java index 8e9736a96..cf462f473 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.QueryBuilder; @@ -38,8 +39,8 @@ import org.apache.openjpa.persistence.meta.MetamodelImpl; public class Expressions { static Value toValue(ExpressionImpl e, ExpressionFactory factory, - MetamodelImpl model) { - Value v = e.toValue(factory, model); + MetamodelImpl model, CriteriaQuery q) { + Value v = e.toValue(factory, model, q); return v; } @@ -107,8 +108,9 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { - return factory.abs(Expressions.toValue(e, factory, model)); + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { + return factory.abs(Expressions.toValue(e, factory, model, q)); } } @@ -125,8 +127,9 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { - Value v = factory.count(Expressions.toValue(e, factory, model)); + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { + Value v = factory.count(Expressions.toValue(e, factory, model, q)); return _distinct ? factory.distinct(v) : v; } } @@ -137,8 +140,9 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { - return factory.avg(Expressions.toValue(e, factory, model)); + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { + return factory.avg(Expressions.toValue(e, factory, model, q)); } } @@ -148,8 +152,9 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { - return factory.sqrt(Expressions.toValue(e, factory, model)); + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { + return factory.sqrt(Expressions.toValue(e, factory, model, q)); } } @@ -159,8 +164,9 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { - return factory.max(Expressions.toValue(e, factory, model)); + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { + return factory.max(Expressions.toValue(e, factory, model, q)); } } @@ -170,8 +176,9 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { - return factory.min(Expressions.toValue(e, factory, model)); + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { + return factory.min(Expressions.toValue(e, factory, model, q)); } } @@ -185,8 +192,9 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { - return factory.size(Expressions.toValue(e, factory, model)); + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { + return factory.size(Expressions.toValue(e, factory, model, q)); } } @@ -197,8 +205,9 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { - return factory.cast(Expressions.toValue(e, factory, model), b); + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { + return factory.cast(Expressions.toValue(e, factory, model, q), b); } } public static class Concat extends BinarayFunctionalExpression { @@ -215,10 +224,11 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.concat( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -246,11 +256,12 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return JPQLExpressionBuilder.convertSubstringArguments(factory, - Expressions.toValue(e, factory, model), - from == null ? null : from.toValue(factory, model), - len == null ? null : len.toValue(factory, model)); + Expressions.toValue(e, factory, model, q), + from == null ? null : from.toValue(factory, model, q), + len == null ? null : len.toValue(factory, model, q)); } } @@ -286,7 +297,8 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { Boolean spec = null; if (ts != null) { switch (ts) { @@ -296,8 +308,8 @@ public class Expressions { } } return factory.trim( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model), spec); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q), spec); } } @@ -324,12 +336,13 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return (e2 == null) - ? factory.sum(Expressions.toValue(e1, factory, model)) + ? factory.sum(Expressions.toValue(e1, factory, model, q)) : factory.add( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -349,10 +362,11 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.multiply( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -372,10 +386,11 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.subtract( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -396,10 +411,11 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.divide( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -417,10 +433,11 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.mod( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -430,7 +447,8 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.getCurrentDate(); } } @@ -441,7 +459,8 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.getCurrentTime(); } } @@ -453,7 +472,8 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.getCurrentTimestamp(); } } @@ -475,21 +495,21 @@ public class Expressions { @Override org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, CriteriaQuery q) { boolean isTypeExpr = false; - Value val1 = Expressions.toValue(e1, factory, model); - Value val2 = Expressions.toValue(e2, factory, model); + Value val1 = Expressions.toValue(e1, factory, model, q); + Value val2 = Expressions.toValue(e2, factory, model, q); if (e1 instanceof PathImpl) { PathImpl path = (PathImpl)e1; isTypeExpr = path.isTypeExpr(); if (isTypeExpr) { ((Constant)e2).setTypeLit(isTypeExpr); - val2 = Expressions.toValue(e2, factory, model); + val2 = Expressions.toValue(e2, factory, model, q); Class clzz = (Class)((Literal)val2).getValue(); val2.setMetaData(((Types.Managed)model.type(clzz)).meta); } } - + ((CriteriaQueryImpl)q).setImplicitTypes(val1, val2, null); if (!negate) return factory.equal(val1, val2); else @@ -508,10 +528,10 @@ public class Expressions { @Override org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, CriteriaQuery q) { return factory.greaterThan( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -526,10 +546,10 @@ public class Expressions { @Override org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, CriteriaQuery q) { return factory.greaterThanEqual( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -545,10 +565,10 @@ public class Expressions { @Override org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, CriteriaQuery q) { return factory.lessThan( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -563,10 +583,10 @@ public class Expressions { @Override org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, CriteriaQuery q) { return factory.lessThanEqual( - Expressions.toValue(e1, factory, model), - Expressions.toValue(e2, factory, model)); + Expressions.toValue(e1, factory, model, q), + Expressions.toValue(e2, factory, model, q)); } } @@ -601,7 +621,8 @@ public class Expressions { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { if (!typeLit) return factory.newLiteral(arg, 1); else @@ -625,13 +646,14 @@ public class Expressions { @Override public org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { if (!negate) return factory.isEmpty( - Expressions.toValue(collection, factory, model)); + Expressions.toValue(collection, factory, model, q)); else return factory.isNotEmpty( - Expressions.toValue(collection, factory, model)); + Expressions.toValue(collection, factory, model, q)); } } @@ -661,10 +683,11 @@ public class Expressions { @Override public org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.contains( - Expressions.toValue(collection, factory, model), - Expressions.toValue(element, factory, model)); + Expressions.toValue(collection, factory, model, q), + Expressions.toValue(element, factory, model, q)); } } @@ -704,11 +727,12 @@ public class Expressions { @Override public org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { return factory.matches( - Expressions.toValue(str, factory, model), - Expressions.toValue(pattern, factory, model), "_", "%", - Expressions.toValue(escapeChar, factory, model).toString()); + Expressions.toValue(str, factory, model, q), + Expressions.toValue(pattern, factory, model, q), "_", "%", + Expressions.toValue(escapeChar, factory, model, q).toString()); } } @@ -737,12 +761,13 @@ public class Expressions { @Override public org.apache.openjpa.kernel.exps.Value toValue( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { Value[] vs = new Value[values.size()]; int i = 0; for (Expression e : values) vs[i++] = Expressions.toValue((ExpressionImpl)e, - factory, model); + factory, model, q); return factory.coalesceExpression(vs); } } @@ -756,9 +781,9 @@ public class Expressions { @Override org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, CriteriaQuery q) { return factory.equal( - Expressions.toValue(e, factory, model), + Expressions.toValue(e, factory, model, q), factory.getNull()); } } @@ -772,9 +797,9 @@ public class Expressions { @Override org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, CriteriaQuery q) { return factory.notEqual( - Expressions.toValue(e, factory, model), + Expressions.toValue(e, factory, model, q), factory.getNull()); } } @@ -804,11 +829,11 @@ public class Expressions { @Override org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, CriteriaQuery q) { IsNotNull notNull = new Expressions.IsNotNull(e); return factory.and( - super.toKernelExpression(factory, model), - notNull.toKernelExpression(factory, model)); + super.toKernelExpression(factory, model, q), + notNull.toKernelExpression(factory, model, q)); } } @@ -857,21 +882,22 @@ public class Expressions { @Override public org.apache.openjpa.kernel.exps.Value toValue( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { int size = whens.size(); org.apache.openjpa.kernel.exps.Expression[] exps = new org.apache.openjpa.kernel.exps.Expression[size]; for (int i = 0; i < size; i++) { org.apache.openjpa.kernel.exps.Expression expr = ((Expressions.BinaryLogicalExpression)whens.get(i)). - toKernelExpression(factory, model); + toKernelExpression(factory, model, q); Value action = Expressions.toValue( - (ExpressionImpl)thens.get(i), factory, model); + (ExpressionImpl)thens.get(i), factory, model, q); exps[i] = factory.whenCondition(expr, action); } Value other = Expressions.toValue( - (ExpressionImpl)otherwise, factory, model); + (ExpressionImpl)otherwise, factory, model, q); return factory.generalCaseExpression(exps, other); } } @@ -929,9 +955,10 @@ public class Expressions { @Override public org.apache.openjpa.kernel.exps.Value toValue( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { Value caseOperandExpr = Expressions.toValue( - (ExpressionImpl)caseOperand, factory, model); + (ExpressionImpl)caseOperand, factory, model, q); int size = whens.size(); org.apache.openjpa.kernel.exps.Expression[] exps = new org.apache.openjpa.kernel.exps.Expression[size]; @@ -940,12 +967,12 @@ public class Expressions { //TODO: Boolean literal, String literal val = factory.newLiteral(whens.get(i), Literal.TYPE_NUMBER); Value action = Expressions.toValue( - (ExpressionImpl)thens.get(i), factory, model); + (ExpressionImpl)thens.get(i), factory, model, q); exps[i] = factory.whenScalar(val, action); } Value other = Expressions.toValue( - (ExpressionImpl)otherwise, factory, model); + (ExpressionImpl)otherwise, factory, model, q); return factory.simpleCaseExpression(caseOperandExpr, exps, other); } } diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterImpl.java index 4a81a875a..88bd557b2 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterImpl.java @@ -18,7 +18,14 @@ */ package org.apache.openjpa.persistence.criteria; +import java.util.Collection; import javax.persistence.Parameter; +import javax.persistence.criteria.CriteriaQuery; +import org.apache.commons.collections.map.LinkedMap; +import org.apache.openjpa.kernel.exps.ExpressionFactory; +import org.apache.openjpa.kernel.exps.Value; +import org.apache.openjpa.meta.ClassMetaData; +import org.apache.openjpa.persistence.meta.MetamodelImpl; /** * Parameter of a criteria query. @@ -48,4 +55,40 @@ public class ParameterImpl extends ExpressionImpl implements Parameter{ return position; } + @Override + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { + boolean positional = false; + LinkedMap parameterTypes = ((CriteriaQueryImpl)q).getParameterTypes(); + if (parameterTypes == null) { + parameterTypes = new LinkedMap(6); + ((CriteriaQueryImpl)q).setParameterTypes(parameterTypes); + } + if (name == null) { + position = parameterTypes.size() + 1; + positional = true; + } + + Object paramKey = name == null ? Integer.valueOf(position) : name; + if (!parameterTypes.containsKey(paramKey)) + parameterTypes.put(paramKey, Object.class); + + ClassMetaData meta = null; + Class clzz = getJavaType(); + int index; + if (positional) + index = position - 1; + else + // otherwise the index is just the current size of the params + index = parameterTypes.indexOf(paramKey); + + boolean isCollectionValued = Collection.class.isAssignableFrom(clzz); + org.apache.openjpa.kernel.exps.Parameter param = isCollectionValued + ? factory.newCollectionValuedParameter(paramKey, Object.class) + : factory.newParameter(paramKey, Object.class); + param.setMetaData(meta); + param.setIndex(index); + + return param; + } } diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PathImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PathImpl.java index f7a6b407b..ef513a36f 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PathImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PathImpl.java @@ -19,6 +19,7 @@ package org.apache.openjpa.persistence.criteria; +import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Path; import javax.persistence.metamodel.AbstractCollection; @@ -65,12 +66,13 @@ public class PathImpl extends ExpressionImpl implements Path { } @Override - public Value toValue(ExpressionFactory factory, MetamodelImpl model) { + public Value toValue(ExpressionFactory factory, MetamodelImpl model, + CriteriaQuery q) { Value var = null; if (_parent != null) { org.apache.openjpa.kernel.exps.Path path = (org.apache.openjpa.kernel.exps.Path) - _parent.toValue(factory, model); + _parent.toValue(factory, model, q); path.get(member.fmd, false); var = path; } else { diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PredicateImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PredicateImpl.java index 2aafa9492..b252d90c5 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PredicateImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/PredicateImpl.java @@ -21,6 +21,7 @@ package org.apache.openjpa.persistence.criteria; import java.util.ArrayList; import java.util.List; +import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Predicate; @@ -80,18 +81,18 @@ public class PredicateImpl extends ExpressionImpl @Override org.apache.openjpa.kernel.exps.Expression toKernelExpression( - ExpressionFactory factory, MetamodelImpl model) { + ExpressionFactory factory, MetamodelImpl model, CriteriaQuery q) { if (_exps == null || _exps.isEmpty()) return factory.emptyExpression(); if (_exps.size() == 1) return ((ExpressionImpl)_exps.get(0)) - .toKernelExpression(factory, model); + .toKernelExpression(factory, model, q); ExpressionImpl e1 = (ExpressionImpl)_exps.get(0); ExpressionImpl e2 = (ExpressionImpl)_exps.get(1); org.apache.openjpa.kernel.exps.Expression ke1 = - e1.toKernelExpression(factory, model); + e1.toKernelExpression(factory, model, q); org.apache.openjpa.kernel.exps.Expression ke2 = - e2.toKernelExpression(factory, model); + e2.toKernelExpression(factory, model, q); org.apache.openjpa.kernel.exps.Expression result = _op == BooleanOperator.AND ? factory.and(ke1,ke2) : factory.or(ke1, ke2); @@ -99,8 +100,8 @@ public class PredicateImpl extends ExpressionImpl for (int i = 2; i < _exps.size(); i++) { ExpressionImpl e = (ExpressionImpl)_exps.get(i); result = _op == BooleanOperator.AND - ? factory.and(result, e.toKernelExpression(factory, model)) - : factory.or(result, e.toKernelExpression(factory, model)); + ? factory.and(result, e.toKernelExpression(factory, model, q)) + : factory.or(result, e.toKernelExpression(factory,model,q)); } return _negated ? factory.not(result) : result; }