/* * 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.jdbc.query; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.Query; import org.apache.openjpa.persistence.ArgumentException; import org.apache.openjpa.persistence.jdbc.query.domain.Binder; import org.apache.openjpa.persistence.test.AllowFailure; import org.apache.openjpa.persistence.test.SingleEMFTestCase; /** * Tests validation of positional and named parameter binding for JPQL queries. * * * @author Pinaki Poddar * */ public class TestQueryParameterBinding extends SingleEMFTestCase { private static String JPQL = "SELECT p FROM Binder p "; private static int INT_VALUE = 1; private static String STR_VALUE = "2"; private static double DBL_VALUE = 3.0; private EntityManager em; @Override public void setUp() throws Exception { super.setUp(CLEAR_TABLES, Binder.class); em = emf.createEntityManager(); em.getTransaction().begin(); em.persist(new Binder(INT_VALUE, STR_VALUE, DBL_VALUE)); em.getTransaction().commit(); } public void testPositionalParameterWithPositionalBindingSucceeds() { String JPQL_POSITIONAL = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3"; Query q = em.createQuery(JPQL_POSITIONAL); q.setParameter(1, INT_VALUE); q.setParameter(2, STR_VALUE); q.setParameter(3, DBL_VALUE); assertEquals(1, q.getResultList().size()); } public void testPositionalParameterWithNamedBindingFails() { String JPQL_POSITIONAL = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3"; Query q = em.createQuery(JPQL_POSITIONAL); assertSetParameterFails(q, "p1", INT_VALUE); } public void testPositionalParameterWithInsufficientValuesFails() { String JPQL_POSITIONAL = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3"; Query q = em.createQuery(JPQL_POSITIONAL); q.setParameter(1, INT_VALUE); q.setParameter(2, STR_VALUE); fail(q); } public void testPositionalParameterWithExtraValuesFails() { String JPQL_POSITIONAL = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3"; Query q = em.createQuery(JPQL_POSITIONAL); q.setParameter(1, INT_VALUE); q.setParameter(2, STR_VALUE); q.setParameter(3, DBL_VALUE); assertSetParameterFails(q, 4, 4); } public void testPositionalParameterWithRepeatedValuesSucceeds() { String jPQL_POSITIONAL_REPEATED_PARAM = JPQL + "WHERE p.p1=?1 OR p.p1=?1 AND p.p3=?2"; Query q = em.createQuery(jPQL_POSITIONAL_REPEATED_PARAM); q.setParameter(1, INT_VALUE); q.setParameter(2, DBL_VALUE); assertEquals(1,q.getResultList().size()); } @AllowFailure public void testPositionalParameterWithGapSucceeds() { String JPQL_POSITIONAL_GAP_IN_PARAM = JPQL + "WHERE p.p1=?1 AND p.p2=?3"; Query q = em.createQuery(JPQL_POSITIONAL_GAP_IN_PARAM); q.setParameter(1, INT_VALUE); q.setParameter(3, STR_VALUE); assertEquals(1,q.getResultList().size()); } public void testPositionalParameterWithGapFails() { String JPQL_POSITIONAL_GAP_IN_PARAM = JPQL + "WHERE p.p1=?1 AND p.p3=?3"; Query q = em.createQuery(JPQL_POSITIONAL_GAP_IN_PARAM); q.setParameter(1, INT_VALUE); q.setParameter(3, DBL_VALUE); assertSetParameterFails(q, 2, STR_VALUE); fail(q); } public void testNamedParameterWithNamedBindingSucceeds() { String JPQL_NAMED = JPQL + "WHERE p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3"; Query q = em.createQuery(JPQL_NAMED); q.setParameter("p1", INT_VALUE); q.setParameter("p2", STR_VALUE); q.setParameter("p3", DBL_VALUE); assertEquals(1, q.getResultList().size()); } public void testNamedParameterWithPositionalBindingFails() { String JPQL_NAMED = JPQL + "WHERE p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3"; Query q = em.createQuery(JPQL_NAMED); assertSetParameterFails(q, 1, INT_VALUE); } public void testNamedParameterWithInsufficientValuesFails() { String JPQL_NAMED = JPQL + "WHERE p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3"; Query q = em.createQuery(JPQL_NAMED); q.setParameter("p1", INT_VALUE); q.setParameter("p2", STR_VALUE); fail(q); } public void testNamedParameterWithExtraValuesFails() { String JPQL_NAMED = JPQL + "WHERE p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3"; Query q = em.createQuery(JPQL_NAMED); q.setParameter("p1", INT_VALUE); q.setParameter("p2", STR_VALUE); q.setParameter("p3", DBL_VALUE); assertSetParameterFails(q, "p4", 4); } public void testNamedParameterWithRepeatedValuesSucceeds() { String jPQL_NAMED_REPEATED_PARAM = JPQL + "WHERE p.p1=:p1 OR p.p1=:p1 AND p.p3=:p2"; Query q = em.createQuery(jPQL_NAMED_REPEATED_PARAM); q.setParameter("p1", INT_VALUE); q.setParameter("p2", DBL_VALUE); assertEquals(1,q.getResultList().size()); } public void testNamedParameterWithGapSucceeds() { String JPQL_NAMED_GAP_IN_PARAM = JPQL + "WHERE p.p1=:p1 AND p.p2=:p3"; Query q = em.createQuery(JPQL_NAMED_GAP_IN_PARAM); q.setParameter("p1", INT_VALUE); q.setParameter("p3", STR_VALUE); assertEquals(1,q.getResultList().size()); } public void testNamedParameterWithGapFails() { String JPQL_NAMED_GAP_IN_PARAM = JPQL + "WHERE p.p1=:p1 AND p.p3=:p3"; Query q = em.createQuery(JPQL_NAMED_GAP_IN_PARAM); q.setParameter("p1", INT_VALUE); q.setParameter("p3", DBL_VALUE); assertSetParameterFails(q, "p2", STR_VALUE); } public void testNamedParameterWithWrongType() { String JPQL_NAMED = JPQL + "WHERE p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3"; Query q = em.createQuery(JPQL_NAMED); q.setParameter("p1", INT_VALUE); assertSetParameterFails(q, "p2", DBL_VALUE); assertSetParameterFails(q, "p3", STR_VALUE); } public void testPositionalParameterWithWrongType() { String JPQL_POSITIONAL = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3"; Query q = em.createQuery(JPQL_POSITIONAL); q.setParameter(1, INT_VALUE); assertSetParameterFails(q, 2, DBL_VALUE); } public void testNamedParameterWithNullValue() { String JPQL_POSITIONAL = JPQL + "WHERE p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3"; Query q = em.createQuery(JPQL_POSITIONAL); q.setParameter("p1", INT_VALUE); q.setParameter("p2", null); assertSetParameterFails(q, "p3", null); // Parameter<double> can not be set to null } public void testPositionalParameterWithNullValue() { String JPQL_POSITIONAL = JPQL + "WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3"; Query q = em.createQuery(JPQL_POSITIONAL); q.setParameter(1, INT_VALUE); q.setParameter(2, null); // Parameter<String> can be set to null assertSetParameterFails(q, 3, null); // Parameter<double> can not be set to null } public void testPositionalParameterWithSingleResult() { Query q = em.createNamedQuery("JPQL_POSITIONAL"); // "SELECT p FROM Binder p WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3" q.setParameter(1, INT_VALUE); q.setParameter(2, null); // Parameter<String> can be set to null assertSetParameterFails(q, 3, null); // Parameter<double> can not be set to null } public void testPositionalParameterWithNativeQuery() { Query q = em.createNamedQuery("SQL_POSITIONAL"); // "SELECT p.id FROM Binder WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3" q.setParameter(1, INT_VALUE); q.setParameter(2, STR_VALUE); q.setParameter(3, DBL_VALUE); assertEquals(1,q.getResultList().size()); } public void testPositionalParameterWithNativeQueryFails() { Query q = em.createNamedQuery("SQL_POSITIONAL"); // "SELECT p.id FROM Binder WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3" q.setParameter(1, INT_VALUE); q.setParameter(2, STR_VALUE); fail(q); } public void testPositionalParameterWithNativeQueryFailsWithGap() { Query q = em.createNamedQuery("SQL_POSITIONAL"); // "SELECT p.id FROM Binder WHERE p.p1=?1 AND p.p2=?2 AND p.p3=?3" q.setParameter(1, INT_VALUE); q.setParameter(3, DBL_VALUE); fail(q); } public void testRepeatedNamedParameters() { String JPQL_POSITIONAL = JPQL + "WHERE p.p1 in (select max(p.p1) from Binder p where p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3) " + "AND p.p1=:p1 AND p.p2=:p2 AND p.p3=:p3"; Query q = em.createQuery(JPQL_POSITIONAL); q.setParameter("p1", INT_VALUE); q.setParameter("p2", STR_VALUE); q.setParameter("p3", DBL_VALUE); List list = q.getResultList(); assertEquals(1, list.size()); } void assertSetParameterFails(Query q, String name, Object v) { try { q.setParameter(name, v); fail("Expected to fail in setting named parameter [" + name + "] to a value of " + v); } catch (IllegalArgumentException e) { // good } } void assertSetParameterFails(Query q, int pos, Object v) { try { q.setParameter(pos, v); fail("Expected to fail in setting positional parameter [" + pos + "] to a value of " + v); } catch (IllegalArgumentException e) { // good } } void fail(Query q) { fail(q, false); } void fail(Query q, boolean single) { try { if (single) q.getSingleResult(); else q.getResultList(); fail("Expeceted " + ArgumentException.class.getName()); } catch (IllegalArgumentException ex) { // good } } }