openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fa...@apache.org
Subject svn commit: r738940 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/exps/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ openjpa-kernel/sr...
Date Thu, 29 Jan 2009 17:51:36 GMT
Author: fancy
Date: Thu Jan 29 17:51:35 2009
New Revision: 738940

URL: http://svn.apache.org/viewvc?rev=738940&view=rev
Log:
OPENJPA-865 JPA2 Query support for collection-valued input parameter in in-expression

Added:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/CollectionParam.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CollectionParam.java
Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
    openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/exps/localizer.properties
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/expressions/TestEntityTypeExpression.java

Added: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/CollectionParam.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/CollectionParam.java?rev=738940&view=auto
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/CollectionParam.java
(added)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/CollectionParam.java
Thu Jan 29 17:51:35 2009
@@ -0,0 +1,194 @@
+/*
+ * 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.exps;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.meta.Discriminator;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.kernel.exps.Parameter;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.ImplHelper;
+
+/**
+ * A collection-valued input parameter in an in-expression.
+ *
+ * @author Catalina Wei
+ */
+public class CollectionParam
+    extends Const
+    implements Parameter {
+    private static final Localizer _loc = Localizer.forPackage(
+        CollectionParam.class);
+
+    private final String _name;
+    private Class _type = null;
+    private int _idx = -1;
+    private boolean _container = false;
+
+    /**
+     * Constructor. Supply parameter name and type.
+     */
+    public CollectionParam(String name, Class type) {
+        _name = name;
+        setImplicitType(type);
+    }
+
+    public String getName() {
+        return _name;
+    }
+
+    public String getParameterName() {
+        return getName();
+    }
+
+    public Class getType() {
+        return _type;
+    }
+
+    public void setImplicitType(Class type) {
+        _type = type;
+        _container = (getMetaData() == null || !ImplHelper.isManagedType(
+            getMetaData().getRepository().getConfiguration(), type))
+            && (Collection.class.isAssignableFrom(type)
+            || Map.class.isAssignableFrom(type));
+    }
+
+    public int getIndex() {
+        return _idx;
+    }
+
+    public void setIndex(int idx) {
+        _idx = idx;
+    }
+
+    public Object getValue(Object[] params) {
+        return Filters.convert(params[_idx], getType());
+    }
+
+    public Object getValue(ExpContext ctx, ExpState state) {
+        ParamExpState pstate = (ParamExpState) state;
+        if (pstate.discValue[0] != null)
+            return Arrays.asList(pstate.discValue);
+        else
+            return getValue(ctx.params);
+    }
+
+    public Object getSQLValue(Select sel, ExpContext ctx, ExpState state) {
+        return ((ParamExpState) state).sqlValue;
+    }
+
+    public ExpState initialize(Select sel, ExpContext ctx, int flags) {
+        return new ParamExpState(ctx.params[_idx]);
+    }
+
+    /**
+     * Expression state.
+     */
+    public static class ParamExpState
+        extends ConstExpState {
+
+        public int size = 0;
+        public Object[] sqlValue = null;
+        public int[] otherLength;
+        public ClassMapping[] mapping = null;
+        public Discriminator[] disc = null;
+        public Object discValue[] = null;
+        
+        ParamExpState(Object params) {
+            if (params instanceof Collection)
+                size = ((Collection) params).size();
+            sqlValue = new Object[size];
+            otherLength = new int[size];
+            mapping = new ClassMapping[size];
+            disc = new Discriminator[size];
+            discValue = new Object[size];
+            for (int i = 0; i < size; i++) {
+                sqlValue[i] = null;
+                otherLength[i] = 1;
+                mapping[i] = null;
+                disc[i] = null;
+                discValue[i] = null;
+            }
+        }
+    } 
+
+    public void calculateValue(Select sel, ExpContext ctx, ExpState state, 
+        Val other, ExpState otherState) {
+        super.calculateValue(sel, ctx, state, other, otherState);
+        ParamExpState pstate = (ParamExpState) state;
+        Object value = getValue(ctx.params);
+
+        if (!(value instanceof Collection))
+            throw new IllegalArgumentException(_loc.get(
+                "not-collection-parm", _name).toString());
+
+        if (((Collection) value).isEmpty())
+            throw new IllegalArgumentException(_loc.get(
+                "empty-collection-parm", _name).toString());
+
+        Iterator itr = ((Collection) value).iterator();
+        for (int i = 0; i < pstate.size && itr.hasNext(); i++) {
+            Object val = itr.next();
+            if (other != null && !_container) {
+                pstate.sqlValue[i] = other.toDataStoreValue(sel, ctx,
+                    otherState, val);
+                pstate.otherLength[i] = other.length(sel, ctx, otherState);
+                if (other instanceof Type) {
+                    pstate.mapping[i] = ctx.store.getConfiguration().
+                    getMappingRepositoryInstance().getMapping((Class) val,
+                        ctx.store.getContext().getClassLoader(), true);
+                    pstate.disc[i] = pstate.mapping[i].getDiscriminator();
+                    pstate.discValue[i] = pstate.disc != null ?
+                        pstate.disc[i].getValue() : null;
+                }
+            } else if (ImplHelper.isManageable(val)) {
+                ClassMapping mapping = ctx.store.getConfiguration().
+                getMappingRepositoryInstance().getMapping(val.getClass(),
+                    ctx.store.getContext().getClassLoader(), true);
+                pstate.sqlValue[i] = mapping.toDataStoreValue(val,
+                    mapping.getPrimaryKeyColumns(), ctx.store);
+                pstate.otherLength[i] = mapping.getPrimaryKeyColumns().length;
+            } else
+                pstate.sqlValue[i] = val;
+        }
+    }
+
+    public void appendTo(Select sel, ExpContext ctx, ExpState state, 
+        SQLBuffer sql, int index) {
+        ParamExpState pstate = (ParamExpState) state;
+        for (int i = 0; i < pstate.size; i++) {
+            if (pstate.otherLength[i] > 1)
+                sql.appendValue(((Object[]) pstate.sqlValue[i])[index], 
+                        pstate.getColumn(index));
+            else if (pstate.cols != null)
+                sql.appendValue(pstate.sqlValue[i], pstate.getColumn(index));
+            else if (pstate.discValue[i] != null)
+                sql.appendValue(pstate.discValue[i]);
+            else
+                sql.appendValue(pstate.sqlValue[i], pstate.getColumn(index));
+        }
+    }
+}

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java?rev=738940&r1=738939&r2=738940&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
(original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
Thu Jan 29 17:51:35 2009
@@ -275,6 +275,10 @@
         return new Param(name, type);
     }
 
+    public Parameter newCollectionValuedParameter(String name, Class type) {
+        return new CollectionParam(name, type);
+    }
+
     public Value newExtension(FilterListener listener, Value target,
         Value arg) {
         return new Extension((JDBCFilterListener) listener,

Modified: openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/exps/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/exps/localizer.properties?rev=738940&r1=738939&r2=738940&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/exps/localizer.properties
(original)
+++ openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/exps/localizer.properties
Thu Jan 29 17:51:35 2009
@@ -28,3 +28,6 @@
 cant-convert: Attempt to compare incompatible types "{0}" and "{1}".
 invalid-unbound-var: Invalid unbound variable "{0}" in query.
 no-order-column: Field "{0}" does not have order column defined".
+not-collection-parm: Invalid input parameter "{0}", a collection-valued \
+    input parameter is expected.
+empty-collection-parm: Input parameter "{0}" is empty.
\ No newline at end of file

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CollectionParam.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CollectionParam.java?rev=738940&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CollectionParam.java
(added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CollectionParam.java
Thu Jan 29 17:51:35 2009
@@ -0,0 +1,69 @@
+/*
+ * 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.exps;
+
+import org.apache.openjpa.kernel.StoreContext;
+
+/**
+ * Represents a collection valued input parameter.
+ *
+ * @author Catalina Wei
+ */
+class CollectionParam
+    extends Val
+    implements Parameter {
+
+    private String _name = null;
+    private Class _type = null;
+    private int _index = -1;
+
+    /**
+     * Constructor. Provide parameter name and type.
+     */
+    public CollectionParam(String name, Class type) {
+        _name = name;
+        _type = type;
+    }
+
+    public String getParameterName() {
+        return _name;
+    }
+
+    public Class getType() {
+        return _type;
+    }
+
+    public void setImplicitType(Class type) {
+        _type = type;
+    }
+
+    public void setIndex(int index) {
+        _index = index;
+    }
+
+    public Object getValue(Object[] params) {
+        return params[_index];
+    }
+
+    protected Object eval(Object candidate, Object orig,
+        StoreContext ctx, Object[] params) {
+        return getValue(params);
+    }
+}
+

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java?rev=738940&r1=738939&r2=738940&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
(original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
Thu Jan 29 17:51:35 2009
@@ -248,6 +248,12 @@
     public Parameter newParameter(String name, Class type);
 
     /**
+     * Return a value representing a collection-valued parameter. The
+     * type may be <code>Object</code> if the parameter is not declared.
+     */
+    public Parameter newCollectionValuedParameter(String name, Class type);
+
+    /**
      * Return the value of the given extension.
      */
     public Value newExtension(FilterListener listener, Value target,

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java?rev=738940&r1=738939&r2=738940&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
(original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
Thu Jan 29 17:51:35 2009
@@ -508,6 +508,10 @@
         return new Param(name, type);
     }
 
+    public Parameter newCollectionValuedParameter(String name, Class type) {
+        return new CollectionParam(name, type);
+    }
+
     public Value newExtension(FilterListener listener, Value target,
         Value arg) {
         return new Extension(listener, (Val) target, (Val) arg);

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java?rev=738940&r1=738939&r2=738940&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
(original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
Thu Jan 29 17:51:35 2009
@@ -827,8 +827,7 @@
                 return getParameter(node.text, true);
 
             case JJTCOLLECTIONPARAMETER:
-                // TODO: support collection valued parameters
-                return getParameter(onlyChild(node).text, true);
+                return getCollectionValuedParameter(node);
 
             case JJTOR: // x OR y
                 return factory.or(getExpression(left(node)),
@@ -1327,6 +1326,47 @@
     }
 
     /**
+     * Record the names and order of collection valued input parameters.
+     */
+    private Parameter getCollectionValuedParameter(JPQLNode node) {        
+        JPQLNode child = onlyChild(node);
+        String id = child.text;
+        boolean positional = child.id == JJTPOSITIONALINPUTPARAMETER;
+
+        if (parameterTypes == null)
+            parameterTypes = new LinkedMap(6);
+        if (!parameterTypes.containsKey(id))
+            parameterTypes.put(id, TYPE_OBJECT);
+
+        Class type = Object.class;
+        ClassMetaData meta = null;
+        int index;
+        if (positional) {
+            try {
+                // indexes in JPQL are 1-based, as opposed to 0-based in
+                // the core ExpressionFactory
+                index = Integer.parseInt(id) - 1;
+            } catch (NumberFormatException e) {
+                throw parseException(EX_USER, "bad-positional-parameter",
+                    new Object[]{ id }, e);
+            }
+
+            if (index < 0)
+                throw parseException(EX_USER, "bad-positional-parameter",
+                    new Object[]{ id }, null);
+        } else {
+            // otherwise the index is just the current size of the params
+            index = parameterTypes.indexOf(id);
+        }
+
+        Parameter param = factory.newCollectionValuedParameter(id, type);
+        param.setMetaData(meta);
+        param.setIndex(index);
+
+        return param;
+    }
+
+    /**
      * Checks to see if we should evaluate for a NOT expression.
      */
     private Expression evalNot(boolean not, Expression exp) {

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/expressions/TestEntityTypeExpression.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/expressions/TestEntityTypeExpression.java?rev=738940&r1=738939&r2=738940&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/expressions/TestEntityTypeExpression.java
(original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/expressions/TestEntityTypeExpression.java
Thu Jan 29 17:51:35 2009
@@ -79,15 +79,38 @@
         List<CompUser> rs = null;
         CompUser user = null;
 
-//      TODO: test when support for collection valued parameters is available
-//        Collection params = new ArrayList();
-//        params.add(FemaleUser.class);
-//        params.add(MaleUser.class);
-//        query = "SELECT e FROM CompUser e where TYPE(e) = :params";
-//        rs =  em.createQuery(query).
-//            setParameter("params", params).getResultList();
-//        user = rs.get(0);
-//        assertEquals("the name is not shannon", "Shannon ", user.getName());
+        // test collection-valued input parameters in in-expressions
+        Collection params = new ArrayList(2);
+        params.add(FemaleUser.class);
+        params.add(MaleUser.class);
+
+        Collection params2 = new ArrayList(3);
+        params2.add(36);
+        params2.add(29);
+        params2.add(19);
+        String param3 = "PC";
+
+        query = "SELECT e FROM CompUser e where TYPE(e) in ?1 and e.age in ?2" +
+                " and e.computerName = ?3";
+        rs = em.createQuery(query).
+            setParameter(1, params).
+            setParameter(2, params2).
+            setParameter(3, param3).getResultList();
+        user = rs.get(0);
+        assertEquals("the name is not shannon", "Shannon ", user.getName());
+
+        query = "SELECT e FROM CompUser e where TYPE(e) in ?1 and e.age in ?2";
+        rs = em.createQuery(query).
+            setParameter(1, params).
+            setParameter(2, params2).getResultList();
+        user = rs.get(0);
+        assertEquals("the name is not shannon", "Shannon ", user.getName());
+
+        query = "SELECT e FROM CompUser e where TYPE(e) in :params";
+        rs = em.createQuery(query).
+            setParameter("params", params).getResultList();
+        user = rs.get(0);
+        assertEquals("the name is not shannon", "Shannon ", user.getName());
         
         query = "SELECT TYPE(e) FROM MaleUser e where TYPE(e) = MaleUser";
         rs = em.createQuery(query).getResultList();



Mime
View raw message