blob: 02f5abe808238a12ae8679d39998d995f27c852c [file] [log] [blame]
/*
* 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.slice;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
/**
* Tests query ordering.
*
* @author Pinaki Poddar
*
*/
public class TestQuery extends SliceTestCase {
private int POBJECT_COUNT = 25;
private int VALUE_MIN = 100;
private int VALUE_MAX = VALUE_MIN + POBJECT_COUNT - 1;
@Override
protected String getPersistenceUnitName() {
return "ordering";
}
@Override
public void setUp() throws Exception {
super.setUp(PObject.class, Person.class, Address.class, Country.class,
Car.class, Manufacturer.class,
CLEAR_TABLES);
int count = count(PObject.class);
if (count == 0) {
create(POBJECT_COUNT);
}
}
void create(int N) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
for (int i=0;i<POBJECT_COUNT;i++) {
PObject pc = new PObject();
pc.setValue(VALUE_MIN + i);
em.persist(pc);
String slice = SlicePersistence.getSlice(pc);
String expected = (pc.getValue()%2 == 0) ? "Even" : "Odd";
assertEquals(expected, slice);
}
Person p1 = new Person();
Person p2 = new Person();
Address a1 = new Address();
Address a2 = new Address();
p1.setName("Even");
p2.setName("Odd");
a1.setCity("San Francisco");
a2.setCity("Rome");
p1.setAddress(a1);
p2.setAddress(a2);
em.persist(p1);
em.persist(p2);
assertEquals("Even", SlicePersistence.getSlice(p1));
assertEquals("Odd", SlicePersistence.getSlice(p2));
em.getTransaction().commit();
}
public void testOrderedQueryResultWhenOrderableItemSelected() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Query query = em.createQuery(
"SELECT p.value,p FROM PObject p ORDER BY p.value ASC");
List result = query.getResultList();
assertValidResult(result);
Integer old = Integer.MIN_VALUE;
for (Object row : result) {
Object[] line = (Object[])row;
int value = (Integer) line[0];
PObject pc = (PObject)line[1];
assertTrue(value >= old);
old = value;
assertEquals(value, pc.getValue());
}
em.getTransaction().rollback();
}
public void testOrderedQueryResultWhenOrderableItemNotSelected() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Query query =
em.createQuery("SELECT p FROM PObject p ORDER BY p.value ASC");
List<PObject> result = query.getResultList();
assertValidResult(result);
Integer old = Integer.MIN_VALUE;
for (PObject pc : result) {
int value = pc.getValue();
assertTrue(value >= old);
old = value;
}
em.getTransaction().rollback();
}
public void testOrderedQueryResultWhenNavigatedOrderableItemNotSelected() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Query query = em.createQuery(
"SELECT p FROM Person p JOIN p.address a ORDER BY a.zip ASC, a.city DESC");
List<Person> result = query.getResultList();
assertValidResult(result);
Integer oldZip = Integer.MIN_VALUE;
String oldCity = null;
for (Person pc : result) {
int zip = pc.getAddress().getZip();
String city = pc.getAddress().getCity();
assertTrue(zip >= oldZip);
assertTrue(oldCity == null || oldCity.compareTo(city) >= 0);
oldZip = zip;
oldCity = city;
}
em.getTransaction().rollback();
}
public void testAggregateQuery() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Object count = em.createQuery("SELECT COUNT(p) FROM PObject p")
.getSingleResult();
Object max = em.createQuery("SELECT MAX(p.value) FROM PObject p")
.getSingleResult();
Object min = em.createQuery("SELECT MIN(p.value) FROM PObject p")
.getSingleResult();
Object sum = em.createQuery("SELECT SUM(p.value) FROM PObject p")
.getSingleResult();
Object minmax = em.createQuery(
"SELECT MIN(p.value),MAX(p.value) FROM PObject p")
.getSingleResult();
Object min1 = ((Object[])minmax)[0];
Object max1 = ((Object[])minmax)[1];
em.getTransaction().rollback();
assertEquals(POBJECT_COUNT, ((Number)count).intValue());
assertEquals(VALUE_MAX, ((Number)max).intValue());
assertEquals(VALUE_MIN, ((Number)min).intValue());
assertEquals((VALUE_MIN + VALUE_MAX) * POBJECT_COUNT,
2 * ((Number)sum).intValue());
assertEquals(min, min1);
assertEquals(max, max1);
}
public void testAggregateQueryWithMissingValueFromSlice() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Object max = em.createQuery(
"SELECT MAX(p.value) FROM PObject p WHERE MOD(p.value,2)=0")
.getSingleResult();
em.getTransaction().rollback();
assertEquals(VALUE_MAX, ((Number)max).intValue());
}
public void testSetMaxResult() {
EntityManager em = emf.createEntityManager();
int limit = 3;
em.getTransaction().begin();
List<PObject> result =
em.createQuery("SELECT p FROM PObject p ORDER BY p.value ASC")
.setMaxResults(limit).getResultList();
assertValidResult(result);
Integer old = Integer.MIN_VALUE;
for (PObject pc : result) {
int value = pc.getValue();
assertTrue(value >= old);
old = value;
}
assertEquals(limit, result.size());
em.getTransaction().rollback();
}
public void testHint() {
List<String> targets = new ArrayList<>();
targets.add("Even");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Query query = em.createQuery("SELECT p FROM PObject p");
query.setHint(SlicePersistence.HINT_TARGET, "Even");
List result = query.getResultList();
for (Object pc : result) {
String slice = SlicePersistence.getSlice(pc);
assertTrue("Expected original slice " + slice + " in " + targets, targets.contains(slice));
}
em.getTransaction().rollback();
}
public void testQueryTargetPolicy() {
List<String> targets = new ArrayList<>();
targets.add("Even");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Query query = em.createQuery("SELECT p FROM PObject p");
query.setHint(SlicePersistence.HINT_TARGET, "Even");
List result = query.getResultList();
for (Object pc : result) {
String slice = SlicePersistence.getSlice(pc);
assertTrue(targets.contains(slice));
}
em.getTransaction().rollback();
}
public void testInMemoryOrderBy() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Query query =
em.createQuery("SELECT p FROM PObject p ORDER BY p.value");
List result = query.getResultList();
em.getTransaction().rollback();
}
public void testQueryParameter() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Query query = em.createQuery(
"SELECT p FROM PObject p WHERE p.value > :v")
.setParameter("v", 200);
List result = query.getResultList();
em.getTransaction().rollback();
}
public void testQueryParameterEntity() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Address a = (Address)em.createQuery(
"select a from Address a where a.city = :city")
.setParameter("city", "Rome").getSingleResult();
assertNotNull(a);
assertEquals("Odd", SlicePersistence.getSlice(a));
Query query =
em.createQuery("SELECT p FROM Person p WHERE p.address = :a")
.setParameter("a", a);
List<Person> result = query.getResultList();
assertEquals(1, result.size());
Person p = result.get(0);
assertEquals("Odd", SlicePersistence.getSlice(p));
assertEquals("Rome", p.getAddress().getCity());
em.getTransaction().rollback();
}
/**
* Verifies that a lazy relation can be stored across different slices i.e.
* collocation constraint can be violated under some restrictions.
*
* Car refers to Manufacturer. The relationship is uni-directional, no
* cascade and most importantly lazy.
* The distribution policy is designed to store Car and Manufacturer
* *always* in different slices.
*
*/
public void testCollocationConstraintViolation() {
// This transaction will store Manufacturer only
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Manufacturer bmw = new Manufacturer();
bmw.setName("BMW");
em.persist(bmw);
em.getTransaction().commit();
// This transaction will store a Car in a slice but the Car is related
// to a Manufacturer that *always* reside in a different slice.
em.getTransaction().begin();
Car z4 = new Car();
z4.setVin("1234V56789");
z4.setMaker(bmw);
z4.setModel("Z4");
em.persist(z4);
em.getTransaction().commit();
em.clear();
// Verify that all cars are stored in "Even" slice
List cars = em.createQuery("select c from Car c").getResultList();
assertFalse(cars.isEmpty());
for (Object c : cars)
assertEquals("Even", SlicePersistence.getSlice(c));
// While all Manufacturers are stored in "Odd" slice.
List makers =
em.createQuery("select m from Manufacturer m").getResultList();
assertFalse(makers.isEmpty());
for (Object m : makers)
assertEquals("Odd", SlicePersistence.getSlice(m));
em.clear();
// Now query for cars. The related manufacturer will be fetched
// correctly, though it resides in a different slice because the
// relationship is lazy and hence two separate SQLs are issued for
// Car and Manufacturer rather than a single SQL with JOIN.
cars = em.createQuery("select c from Car c").getResultList();
assertFalse(cars.isEmpty());
for (Object c : cars)
assertNotNull(((Car)c).getMaker());
}
void assertValidResult(List result) {
assertNotNull(result);
assertFalse(result.isEmpty());
assertTrue(result.size() > 1);
}
}