blob: e6186ab400524230c8556c219ca9467b39192534 [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.persistence.jdbc.kernel;
import java.util.*;
import org.apache.openjpa.jdbc.conf.*;
import org.apache.openjpa.jdbc.meta.*;
import org.apache.openjpa.jdbc.sql.*;
import org.apache.openjpa.persistence.jdbc.common.apps.*;
import java.lang.annotation.Annotation;
import junit.framework.*;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.openjpa.persistence.OpenJPAQuery;
//import org.apache.openjpa.kernel.Extent;
import org.apache.openjpa.persistence.Extent;
/**
* <p>Test large result, to-many eager paging.</p>
*
*/
public class TestPagingResultObjectProvider
extends TestSQLListenerTestCase {
private OpenJPAEntityManagerFactory emf;
public TestPagingResultObjectProvider(String name)
{
super(name);
}
public void setUp() throws Exception{
super.setUp();
emf = getEmf(getProps());
EntityManager em =currentEntityManager();
}
public boolean skipTest() {
JDBCConfiguration conf = (JDBCConfiguration) ((OpenJPAEntityManagerFactorySPI) OpenJPAPersistence.cast(emf)).getConfiguration();
DBDictionary dict = conf.getDBDictionaryInstance();
if (dict.joinSyntax == Join.SYNTAX_TRADITIONAL)
return true;
// skip test case that requires subselect for DBs that don't support it
if ("testPagingRangeQuery".equals(getName())
|| "testNonPagingRangeQuery".equals(getName())) {
if (!conf.getDBDictionaryInstance().supportsSubselect)
return true;
}
return false;
}
public void testNonPagingExtent() {
initializePagingPCs();
EntityManager em= currentEntityManager();
//EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast (em);
Extent extent = kem.createExtent(PagingPC.class, true);
extent.getFetchPlan().setFetchBatchSize(0);
extent.getFetchPlan().addFetchGroup("rel");
// if we only access the rel field, we should only have used 1 select
List list = extent.list();
assertEquals(4, list.size());
assertRel(list, 4);
assertEquals(sql.toString(), 1, sql.size());
sql.clear();
// now accessing the rels collection should add selects
assertRels(list, 4);
assertEquals(sql.toString(), 4, sql.size());
sql.clear();
em.close();
}
public void testNonPagingQuery()
throws Exception {
initializePagingPCs();
EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
String theQuery="select a FROM "+PagingPC.class.getSimpleName()+" a where a.intField >= 0";
//OpenJPAQuery q = kem.createQuery(PagingPC.class.getSimpleName(), "intField >= 0");
OpenJPAQuery q = kem.createQuery(theQuery);
q.getFetchPlan().setFetchBatchSize(0);
q.getFetchPlan().addFetchGroups("rel");
// if we only access the rel field, we should only have used two
// selects: one for the query and one for the size
List list = (List) q.getResultList();
assertEquals(4, list.size());
assertRel(list, 4);
assertEquals(sql.toString(), 2, sql.size());
assertTrue((String) sql.get(0),
matches(" >= ", (String) sql.get(0)));
assertTrue((String) sql.get(1),
matches(" COUNT", (String) sql.get(1)));
sql.clear();
// now accessing the rels collection should add selects
assertRels(list, 4);
assertEquals(sql.toString(), 4, sql.size());
sql.clear();
em.close();
}
/**
* Check that the rel field was retrieved correctly.
*/
private void assertRel(List pcs, int size) {
PagingPC pc;
for (int i = 0; i < size; i++) {
pc = (PagingPC) pcs.get(i);
assertNotNull(pc.getRel());
assertEquals(pc.getIntField() + 1, pc.getRel().getIntField());
}
try {
pcs.get(size + 1);
fail("Retrieved past end of list");
} catch (Exception e) {
}
}
/**
* Check that the rels field was retrieved correctly.
*/
private void assertRels(List pcs, int size) {
PagingPC pc;
for (int i = 0; i < size; i++) {
pc = (PagingPC) pcs.get(i);
assertEquals(2, pc.getRels().size());
assertEquals(pc.getIntField() + 1, ((PagingHelperPC)
pc.getRels().get(0)).getIntField());
assertEquals(pc.getIntField() + 2, ((PagingHelperPC)
pc.getRels().get(1)).getIntField());
}
try {
pcs.get(size + 1);
fail("Retrieved past end of list");
} catch (Exception e) {
}
}
public void testPagingExtent()
throws Exception {
initializePagingPCs();
EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast (em);
Extent extent = kem.createExtent(PagingPC.class, true);
extent.getFetchPlan().setFetchBatchSize(0);
extent.getFetchPlan().addFetchGroup("rel");
extent.getFetchPlan().addFetchGroup("rels");
// we should get two selects: the initial select and the IN eager stmnt
List list = extent.list();
assertEquals(4, list.size());
assertRel(list, 4);
assertRels(list, 4);
assertEquals(sql.toString(), 2, sql.size());
assertTrue((String) sql.get(1),
matches(" IN ", (String) sql.get(1)));
sql.clear();
em.close();
}
public void testPagingQuery()
throws Exception {
initializePagingPCs();
EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast (em);
String theQuery="select a FROM "+PagingPC.class.getSimpleName()+" a where a.intField >= 0";
OpenJPAQuery q = kem.createQuery(theQuery);
q.getFetchPlan().setFetchBatchSize(0);
q.getFetchPlan().addFetchGroups("rel");
q.getFetchPlan().addFetchGroups("rels");
// we should get three selects: the initial select, the COUNT for the
// size, and the IN eager stmnt
List list = (List) q.getResultList();
assertEquals(4, list.size());
assertRel(list, 4);
assertRels(list, 4);
assertEquals(sql.toString(), 3, sql.size());
assertTrue((String) sql.get(0),
matches(" >= ", (String) sql.get(0)));
assertTrue((String) sql.get(1),
matches(" COUNT", (String) sql.get(1)));
assertTrue((String) sql.get(2),
matches(" IN ", (String) sql.get(2)));
assertFalse((String) sql.get(2),
matches(" >= ", (String) sql.get(2)));
sql.clear();
// if we execute and traverse a result before getting the size, we
// should only get 2 selects, since the caching of the page should
// reach the end of the list and therefore know the total size
list = (List) q.getResultList();
list.get(0);
assertEquals(4, list.size());
assertRel(list, 4);
assertRels(list, 4);
assertEquals(sql.toString(), 2, sql.size());
assertTrue((String) sql.get(1),
matches(" IN ", (String) sql.get(1)));
sql.clear();
em.close();
}
public void testPagingAppIdExtent()
throws Exception {
initializePagingAppIdPCs();
EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast (em);
Extent extent = kem.createExtent(PagingAppIdPC.class, true);
extent.getFetchPlan().setFetchBatchSize(0);
extent.getFetchPlan().addFetchGroup("rel");
extent.getFetchPlan().addFetchGroup("rels");
// we should get two selects: the initial select and the IN eager stmnt
List list = extent.list();
assertEquals(4, list.size());
assertAppIdRel(list, 4);
assertAppIdRels(list, 4);
assertEquals(sql.toString(), 2, sql.size());
assertTrue((String) sql.get(1),
matches(" OR ", (String) sql.get(1)));
sql.clear();
em.close();
}
public void testPagingAppIdQuery()
throws Exception {
initializePagingAppIdPCs();
EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
String theQuery="select a FROM "+PagingAppIdPC.class.getSimpleName()+" a where a.intField >= 0";
OpenJPAQuery q = kem.createQuery(theQuery);
q.getFetchPlan().setFetchBatchSize(0);
q.getFetchPlan().addFetchGroups("rel");
q.getFetchPlan().addFetchGroups("rels");
// we should get three selects: the initial select, the COUNT for the
// size, and the OR eager stmnt
List list = (List) q.getResultList();
assertEquals(4, list.size());
assertAppIdRel(list, 4);
assertAppIdRels(list, 4);
assertEquals(sql.toString(), 3, sql.size());
assertTrue((String) sql.get(0),
matches(" >= ", (String) sql.get(0)));
assertTrue((String) sql.get(1),
matches(" COUNT", (String) sql.get(1)));
assertTrue((String) sql.get(2),
matches(" OR ", (String) sql.get(2)));
assertFalse((String) sql.get(2),
matches(" >= ", (String) sql.get(2)));
sql.clear();
em.close();
}
/**
* Check that the rel field was retrieved correctly.
*/
private void assertAppIdRel(List pcs, int size) {
PagingAppIdPC pc;
for (int i = 0; i < size; i++) {
pc = (PagingAppIdPC) pcs.get(i);
assertNotNull(pc.getRel());
assertEquals(pc.getIntField() + 1, pc.getRel().getIntField());
}
try {
pcs.get(size + 1);
fail("Retrieved past end of list");
} catch (Exception e) {
}
}
/**
* Check that the rels field was retrieved correctly.
*/
private void assertAppIdRels(List pcs, int size) {
PagingAppIdPC pc;
for (int i = 0; i < size; i++) {
pc = (PagingAppIdPC) pcs.get(i);
assertEquals(2, pc.getRels().size());
assertEquals(pc.getIntField() + 1, ((PagingHelperPC)
pc.getRels().get(0)).getIntField());
assertEquals(pc.getIntField() + 2, ((PagingHelperPC)
pc.getRels().get(1)).getIntField());
}
try {
pcs.get(size + 1);
fail("Retrieved past end of list");
} catch (Exception e) {
}
}
public void testMultiPageExtent()
throws Exception {
initializePagingPCs();
EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
Extent extent = kem.createExtent(PagingPC.class, true);
extent.getFetchPlan().setFetchBatchSize(2); // 2 pages of 2
extent.getFetchPlan().addFetchGroup("rel");
extent.getFetchPlan().addFetchGroup("rels");
// we should get two selects: the initial select and the IN eager stmnt
List list = extent.list();
assertEquals(list.toString(), 4, list.size());
assertRel(list, 4);
assertRels(list, 4);
assertEquals(sql.toString(), 3, sql.size());
assertTrue((String) sql.get(1),
matches(" IN ", (String) sql.get(1)));
assertTrue((String) sql.get(2),
matches(" IN ", (String) sql.get(2)));
sql.clear();
em.close();
}
public void testMultiPageQuery()
throws Exception {
initializePagingPCs();
EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
String theQuery="select a FROM "+PagingPC.class.getSimpleName()+" a where a.intField >= 0";
OpenJPAQuery q = kem.createQuery(theQuery);
//FIXME jthomas commenting till we find how ordering can be done
//q.setOrdering("intField ascending");
q.getFetchPlan().setFetchBatchSize(2); // 2 pages of 2
q.getFetchPlan().addFetchGroup("rel");
q.getFetchPlan().addFetchGroup("rels");
// we should get four selects: the initial select, the count, and the
// two IN eager stmnts
List list = (List) q.getResultList();
assertEquals(list.toString(), 4, list.size());
// so we don't have to re-execute to move back to beginning
list = new ArrayList(list);
assertRel(list, 4);
assertRels(list, 4);
assertEquals(sql.toString(), 4, sql.size());
assertTrue((String) sql.get(1),
matches(" COUNT", (String) sql.get(1)));
assertTrue((String) sql.get(2),
matches(" IN ", (String) sql.get(2)));
assertTrue((String) sql.get(3),
matches(" IN ", (String) sql.get(3)));
sql.clear();
// if we access a result object on the second page, we should get only
// three selects: the initial select, the count, and the IN eager stmnt
// for page 2
list = (List) q.getResultList();
assertEquals(list.toString(), 4, list.size());
PagingPC pc = (PagingPC) list.get(2);
assertEquals(2, pc.getIntField());
assertEquals(sql.toString(), 3, sql.size());
assertTrue((String) sql.get(2),
matches(" IN", (String) sql.get(2)));
assertRel(list, 4);
assertRels(list, 4);
sql.clear();
em.close();
}
public void testLastPageQuery()
throws Exception {
initializePagingPCs();
EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
String theQuery="select a FROM "+PagingPC.class.getSimpleName()+" a where a.intField >= 0";
OpenJPAQuery q = kem.createQuery(theQuery);
//FIXME jthomas commenting till we find how ordering can be done
//q.setOrdering("intField ascending");
q.getFetchPlan().setFetchBatchSize(3); // 1 on page 2
q.getFetchPlan().addFetchGroups("rel");
q.getFetchPlan().addFetchGroups("rels");
// if we access a result object on the second page, we should get only
// two selects: the initial select and the eager stmnt for page
List list = (List) q.getResultList();
PagingPC pc = (PagingPC) list.get(3);
assertEquals(3, pc.getIntField());
assertEquals(list.toString(), 4, list.size());
assertEquals(sql.toString(), 2, sql.size());
// for single result, should use standard select, not IN
assertFalse((String) sql.get(1),
matches(" IN ", (String) sql.get(1)));
sql.clear();
em.close();
}
public void testSingleResultPage()
throws Exception {
initializePagingPCs();
EntityManager em =currentEntityManager();
OpenJPAEntityManager kem = OpenJPAPersistence.cast (em);
Extent extent = kem.createExtent(PagingPC.class, true);
extent.getFetchPlan().setFetchBatchSize(3); // 1 on page 2
extent.getFetchPlan().addFetchGroup("rel");
extent.getFetchPlan().addFetchGroup("rels");
// we should get two selects: the initial select and the IN eager stmnt
List list = extent.list();
assertEquals(list.toString(), 4, list.size());
assertRel(list, 4);
assertRels(list, 4);
assertEquals(sql.toString(), 3, sql.size());
assertTrue((String) sql.get(1),
matches(" IN ", (String) sql.get(1)));
assertFalse((String) sql.get(2),
matches(" IN ", (String) sql.get(2)));
sql.clear();
em.close();
}
/* public void testNonPagingRangeQuery()
throws Exception {
initializePagingPCs();
EntityManager em =currentEntityManager();
Query q = em.newQuery(PagingPC.class, "intField >= 0");
//FIXME jthomas commenting till we find how ordering can be done
//q.setOrdering("intField ascending");
q.setRange(1, 3);
q.getFetchPlan().setFetchSize(0);
q.getFetchPlan().addGroup("rel");
// if we only access the rel field, we should only have used one
// select; there won't be a size select since the range will be
// greedily consumed as it's so small
List list = (List) q.execute();
assertEquals(2, list.size());
assertRel(list, 2);
assertEquals(sql.toString(), 1, sql.size());
assertTrue((String) sql.get(0),
matches(" >= ", (String) sql.get(0)));
sql.clear();
// now accessing the rels collection should add selects
assertRels(list, 2);
assertEquals(sql.toString(), 2, sql.size());
sql.clear();
// now execute with a big range and small fetch size and bigger range
// and this time we should get a select for the size too
q.getFetchPlan().setFetchSize(2);
q.setRange(1, 4);
list = (List) q.execute();
assertEquals(3, list.size());
// so we don't have to re-execute to move back to beginning
list = new ArrayList(list);
assertRel(list, 3);
assertEquals(sql.toString(), 2, sql.size());
assertTrue((String) sql.get(0),
matches(" >= ", (String) sql.get(0)));
assertTrue((String) sql.get(1),
matches(" COUNT", (String) sql.get(1)));
sql.clear();
em.close();
}
/*
public void testPagingRangeQuery()
throws Exception {
initializePagingPCs();
EntityManager em =currentEntityManager();
Query q = em.newQuery(PagingPC.class, "intField >= 0");
//FIXME jthomas commenting till we find how ordering can be done
//q.setOrdering("intField ascending");
q.setRange(1, 3);
q.getFetchPlan().setFetchSize(0);
q.getFetchPlan().addGroup("rel");
q.getFetchPlan().addGroup("rels");
// expect two selects: the primary select and the IN select; no size
// select expected because the range will be consumed greedily since
// it's so small
List list = (List) q.execute();
assertEquals(2, list.size());
assertRel(list, 2);
assertRels(list, 2);
assertEquals(sql.toString(), 2, sql.size());
assertTrue((String) sql.get(0),
matches(" >= ", (String) sql.get(0)));
assertTrue(sql + "",
matches(" IN ", (String) sql.get(1)));
sql.clear();
// now execute with a big range and small fetch size and bigger range
// and this time we should get a select for the size too
q.getFetchPlan().setFetchSize(2);
q.setRange(1, 4);
list = (List) q.execute();
assertEquals(3, list.size());
// so we don't have to re-execute to move back to beginning
list = new ArrayList(list);
assertRel(list, 3);
assertRels(list, 3);
assertEquals(sql.toString(), 4, sql.size());
assertTrue((String) sql.get(0),
matches(" >= ", (String) sql.get(0)));
assertTrue((String) sql.get(1),
matches(" COUNT", (String) sql.get(1)));
assertTrue((String) sql.get(2),
matches(" IN ", (String) sql.get(2)));
assertFalse((String) sql.get(3),
matches(" IN ", (String) sql.get(3)));
sql.clear();
em.close();
}
*/
private void initializePagingPCs() {
EntityManager em =currentEntityManager();
startTx(em);
deleteAll(PagingPC.class,em);
deleteAll(PagingHelperPC.class,em);
endTx(em);
startTx(em);
PagingPC pc;
PagingHelperPC rel;
for (int i = 0; i < 4; i++) {
pc = new PagingPC();
pc.setIntField(i);
rel = new PagingHelperPC();
rel.setIntField(i + 1);
pc.setRel(rel);
pc.getRels().add(rel);
rel = new PagingHelperPC();
rel.setIntField(i + 2);
pc.getRels().add(rel);
em.persist(pc);
}
endTx(em);
em.close();
sql.clear();
}
private void initializePagingAppIdPCs() {
EntityManager em =currentEntityManager();
startTx(em);
deleteAll(PagingAppIdPC.class,em);
deleteAll(PagingHelperPC.class,em);
startTx(em);
startTx(em);
PagingAppIdPC pc;
PagingHelperPC rel;
for (int i = 0; i < 4; i++) {
pc = new PagingAppIdPC();
pc.setIntField(i);
pc.setLongField(i + 100);
rel = new PagingHelperPC();
rel.setIntField(i + 1);
pc.setRel(rel);
pc.getRels().add(rel);
rel = new PagingHelperPC();
rel.setIntField(i + 2);
pc.getRels().add(rel);
em.persist(pc);
}
endTx(em);
em.close();
sql.clear ();
}
private Map getProps() {
Map props=new HashMap();
props.put("openjpa.DataCache", "true");
props.put("openjpa.RemoteCommitProvider", "sjvm");
props.put("openjpa.FlushBeforeQueries", "true");
props.put("javax.jdo.option.IgnoreCache", "false");
//propsMap.put("openjpa.BrokerImpl", "kodo.datacache.CacheTestBroker");//CacheTestBroker.class.getName ());
return props;
}
}