You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by st...@apache.org on 2013/10/25 17:13:11 UTC

svn commit: r1535760 - in /openjpa/trunk: openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/ openjpa-persistence-jdbc/src/test/resources/META-INF/ openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ openjpa-persistence...

Author: struberg
Date: Fri Oct 25 15:13:10 2013
New Revision: 1535760

URL: http://svn.apache.org/r1535760
Log:
OPENJPA-2018 correctly handle select IN with arrays

txs to rmannibucau for the patch.
Applied with minor changes

Added:
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/OpenJPA2018Test.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/User2018.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/openjpa2018.xml   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/BindableParameter.java
Modified:
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/OpenJPA2018Test.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/OpenJPA2018Test.java?rev=1535760&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/OpenJPA2018Test.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/OpenJPA2018Test.java Fri Oct 25 15:13:10 2013
@@ -0,0 +1,119 @@
+/*
+ * 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.openjpa2018;
+
+import junit.framework.TestCase;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.ParameterExpression;
+import javax.persistence.criteria.Root;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+public class OpenJPA2018Test extends TestCase {
+    private EntityManager em;
+    private EntityTransaction transaction;
+    private EntityManagerFactory factory;
+
+    @Override
+    public void setUp() {
+        factory = OpenJPAPersistence.createEntityManagerFactory("openjpa2018", "META-INF/openjpa2018.xml");
+        em = factory.createEntityManager();
+        transaction = em.getTransaction();
+        transaction.begin();
+    }
+
+    @Override
+    public void tearDown() {
+        transaction.rollback();
+        em.close();
+        factory.close();
+    }
+
+    public void testInCriteriaWithArray() {
+
+        User2018 user = new User2018();
+        em.persist(user);
+        em.flush();
+
+        CriteriaBuilder builder = em.getCriteriaBuilder();
+
+        CriteriaQuery<User2018> criteria = builder.createQuery(User2018.class);
+        Root<User2018> root = criteria.from(User2018.class);
+        criteria.where(root.get("id").in(builder.parameter(Long[].class)));
+
+        TypedQuery<User2018> query = em.createQuery(criteria);
+        for (ParameterExpression parameter : criteria.getParameters()) {
+            query.setParameter(parameter, new Long[] { user.id });
+        }
+
+        List<User2018> result = query.getResultList();
+        assertTrue(!result.isEmpty());
+    }
+
+    public void testInCriteriaWithCollection() {
+
+        User2018 user = new User2018();
+        em.persist(user);
+        em.flush();
+
+        CriteriaBuilder builder = em.getCriteriaBuilder();
+
+        CriteriaQuery<User2018> criteria = builder.createQuery(User2018.class);
+        Root<User2018> root = criteria.from(User2018.class);
+        criteria.where(root.get("id").in(builder.parameter(Collection.class)));
+
+        TypedQuery<User2018> query = em.createQuery(criteria);
+        for (ParameterExpression parameter : criteria.getParameters()) {
+            query.setParameter(parameter, Arrays.asList(user.id));
+        }
+
+        List<User2018> result = query.getResultList();
+        assertTrue(!result.isEmpty());
+    }
+
+    public void testId() {
+
+        User2018 user = new User2018();
+        em.persist(user);
+        em.flush();
+
+        CriteriaBuilder builder = em.getCriteriaBuilder();
+
+        CriteriaQuery<User2018> criteria = builder.createQuery(User2018.class);
+        Root<User2018> root = criteria.from(User2018.class);
+        criteria.where(builder.equal(root.get("id"), user.id));
+
+        TypedQuery<User2018> query = em.createQuery(criteria);
+        for (ParameterExpression parameter : criteria.getParameters()) {
+            query.setParameter(parameter, user.id);
+        }
+
+        List<User2018> result = query.getResultList();
+        assertTrue(!result.isEmpty());
+    }
+
+}

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/User2018.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/User2018.java?rev=1535760&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/User2018.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/openjpa2018/User2018.java Fri Oct 25 15:13:10 2013
@@ -0,0 +1,30 @@
+/*
+ * 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.openjpa2018;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class User2018 {
+
+    @Id @GeneratedValue Long id;
+}
+

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/openjpa2018.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/openjpa2018.xml?rev=1535760&view=auto
==============================================================================
Binary file - no diff available.

Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/resources/META-INF/openjpa2018.xml
------------------------------------------------------------------------------
    svn:mime-type = application/xml

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java?rev=1535760&r1=1535759&r2=1535760&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java Fri Oct 25 15:13:10 2013
@@ -39,6 +39,7 @@ import org.apache.openjpa.kernel.QueryLa
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.lib.util.OrderedMap;
 import org.apache.openjpa.meta.QueryMetaData;
+import org.apache.openjpa.persistence.criteria.BindableParameter;
 
 /**
  * An abstract implementation of the Query interface.
@@ -345,7 +346,10 @@ public abstract class AbstractQuery<X> i
     }
 
     public <T> OpenJPAQuery<X> setParameter(Parameter<T> p, T arg1) {
-        bindValue((Parameter<T>) p, arg1);
+        bindValue(p, arg1);
+        if (BindableParameter.class.isInstance(p)) {
+            BindableParameter.class.cast(p).setValue(arg1);
+        }
         return this;
     }
 

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/BindableParameter.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/BindableParameter.java?rev=1535760&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/BindableParameter.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/BindableParameter.java Fri Oct 25 15:13:10 2013
@@ -0,0 +1,24 @@
+/*
+ * 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.criteria;
+
+public interface BindableParameter {
+    void setValue(Object value);
+    Object value();
+}

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java?rev=1535760&r1=1535759&r2=1535760&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java Fri Oct 25 15:13:10 2013
@@ -19,6 +19,8 @@
 
 package org.apache.openjpa.persistence.criteria;
 
+import java.lang.reflect.Array;
+import java.lang.reflect.ParameterizedType;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
@@ -1446,17 +1448,47 @@ class Expressions {
                 Expressions.Equal e = (Expressions.Equal)_exps.get(0);
                 ExpressionImpl<?> e2 = e.e2;
                 ExpressionImpl<?> e1 = e.e1;
-                Value val2 = Expressions.toValue(e2, factory, q);
-                if (!(val2 instanceof Literal)) {
-                    Value val1 = Expressions.toValue(e1, factory, q);
-                    Expressions.setImplicitTypes(val1, val2, e1.getJavaType(), q);
-                    inExpr = factory.contains(val2, val1);
-                    return isNegated() ? factory.not(inExpr) : inExpr;
-                } else if (((Literal)val2).getParseType() == Literal.TYPE_COLLECTION) {
-                    Collection coll = (Collection)((Literal)val2).getValue();
+
+                Class<?> e1JavaType = e1.getJavaType();
+                Class<?> e2jt = e2.getJavaType();
+
+                // array
+                if (BindableParameter.class.isInstance(e2) && BindableParameter.class.cast(e2).value() != null &&
+                    ((e2jt.isArray() && e2jt.getComponentType().equals(e1JavaType))
+                    || (Class.class.isInstance(e2jt) ||
+                        (ParameterizedType.class.isInstance(e2jt)
+                            && ParameterizedType.class.cast(e2jt).getActualTypeArguments().length > 0
+                            && e1JavaType.equals(ParameterizedType.class.cast(e2jt).getActualTypeArguments()[0]))))) {
+                    final BindableParameter bp = BindableParameter.class.cast(e2);
+                    final Object value = bp.value();
+
                     _exps.clear();
-                    for (Object v : coll) {
-                        add(new Expressions.Equal(e1,v));
+                    if (value == null) {
+                        add(new Expressions.Equal(e1, null));
+                    } else if (value.getClass().isArray()) {
+                        final int len = Array.getLength(value);
+                        for (int i = 0; i < len; i++) {
+                            add(new Expressions.Equal(e1, Array.get(value, i)));
+                        }
+                    } else if (Collection.class.isInstance(value)) {
+                        for (final Object item : Collection.class.cast(value)) {
+                            add(new Expressions.Equal(e1, item));
+                        }
+                    }
+                } else {
+                    // normal case
+                    Value val2 = Expressions.toValue(e2, factory, q);
+                    if (!(val2 instanceof Literal)) {
+                        Value val1 = Expressions.toValue(e1, factory, q);
+                        Expressions.setImplicitTypes(val1, val2, e1.getJavaType(), q);
+                        inExpr = factory.contains(val2, val1);
+                        return isNegated() ? factory.not(inExpr) : inExpr;
+                    } else if (((Literal)val2).getParseType() == Literal.TYPE_COLLECTION) {
+                        Collection coll = (Collection)((Literal)val2).getValue();
+                        _exps.clear();
+                        for (Object v : coll) {
+                            add(new Expressions.Equal(e1,v));
+                        }
                     }
                 }
             } 

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java?rev=1535760&r1=1535759&r2=1535760&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ParameterExpressionImpl.java Fri Oct 25 15:13:10 2013
@@ -39,16 +39,17 @@ import org.apache.openjpa.util.InternalE
  * @param <T> the type of value held by this parameter.
  */
 class ParameterExpressionImpl<T> extends ExpressionImpl<T> 
-    implements ParameterExpression<T> {
+    implements ParameterExpression<T>, BindableParameter {
     private String _name;
     private int _index = 0; // index of the parameter as seen by the kernel, not position
-	
-	/**
-	 * Construct a Parameter of given expected value type and name.
-	 * 
-	 * @param cls expected value type
-	 * @param name name of the parameter which can be null.
-	 */
+    private Object value;
+
+    /**
+     * Construct a Parameter of given expected value type and name.
+     *
+     * @param cls expected value type
+     * @param name name of the parameter which can be null.
+     */
     public ParameterExpressionImpl(Class<T> cls, String name) {
         super(cls);
         if (name != null)
@@ -84,7 +85,17 @@ class ParameterExpressionImpl<T> extends
 
         return buf.toString();
     }
-    
+
+    @Override
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    @Override
+    public Object value() {
+        return value;
+    }
+
     @Override
     public Value toValue(ExpressionFactory factory, CriteriaQueryImpl<?> q) {
         Class<?> clzz = getJavaType();