From f25f879301d4022f3b17861ad3d13a256b8ed75a Mon Sep 17 00:00:00 2001 From: Jody Grassel Date: Mon, 7 Oct 2013 19:03:25 +0000 Subject: [PATCH] OPENJPA-2433: Queries with a sort clause returns fewer entries than the same query that does not have a sort clause git-svn-id: https://svn.apache.org/repos/asf/openjpa/branches/2.1.x@1530028 13f79535-47bb-0310-9956-ffa450edef68 --- .../openjpa/jdbc/kernel/exps/PCPath.java | 3 +- .../apache/openjpa/jdbc/sql/DBDictionary.java | 1 + .../openjpa/persistence/query/Hardware.java | 80 ++++++++++ .../openjpa/persistence/query/Person.java | 66 ++++++++ .../query/Test1x1OrderByResultCollection.java | 144 ++++++++++++++++++ 5 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Hardware.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Person.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Test1x1OrderByResultCollection.java diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java index 2fb8f4156..8123efa83 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java @@ -576,7 +576,8 @@ public class PCPath pstate.joins.setJoinContext(null); } - rel = traverseField(pstate, key, forceOuter, false); + rel = traverseField(pstate, key, forceOuter || + ctx.store.getDBDictionary().fullResultCollectionInOrderByRelation, false); } // mark if the next traversal should go through diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java index 8f1b53113..a26ea1812 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java @@ -213,6 +213,7 @@ public class DBDictionary public String fixedSizeTypeNames = null; public String schemaCase = SCHEMA_CASE_UPPER; public boolean setStringRightTruncationOn = true; + public boolean fullResultCollectionInOrderByRelation = false; // sql public String validationSQL = null; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Hardware.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Hardware.java new file mode 100644 index 000000000..6a2ef1df1 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Hardware.java @@ -0,0 +1,80 @@ +/* + * 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.query; + +import java.io.Serializable; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; + +/** + * The persistent class for the Hardware table. Include references to + * the People table for various owners. + */ +@Entity +public class Hardware implements Serializable { + private static final long serialVersionUID = 1L; + + @Id + private int id; + + @Column(length = 20) + private String empNo; + + @OneToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER) + @JoinColumn(referencedColumnName = "EmpNo") + private Person techOwner; + + public Hardware() { + } + + public Hardware(int id, String empNo) { + this.id = id; + this.empNo = empNo; + } + + public int getId() { + return this.id; + } + + public void setId(int id) { + this.id = id; + } + + public String getEmpNo() { + return this.empNo; + } + + public void setEmpNo(String empNo) { + this.empNo = empNo; + } + + public Person getTechOwner() { + return techOwner; + } + + public void setTechOwner(Person techOwner) { + this.techOwner = techOwner; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Person.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Person.java new file mode 100644 index 000000000..c7fe0d025 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Person.java @@ -0,0 +1,66 @@ +/* + * 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.query; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +/** + * The persistent class for the People table. + */ +@Entity +@Table(name="PERSONNAB") +public class Person implements Serializable { + private static final long serialVersionUID = 1L; + + @Id + @Column(length = 20) + private String empNo; + + @Column(length = 20) + private String name; + + public Person() { + } + + public Person(String empNo, String name) { + this.empNo = empNo; + this.name = name; + } + + public String getEmpNo() { + return this.empNo; + } + + public void setEmpNo(String empNo) { + this.empNo = empNo; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Test1x1OrderByResultCollection.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Test1x1OrderByResultCollection.java new file mode 100644 index 000000000..b20664e1e --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/Test1x1OrderByResultCollection.java @@ -0,0 +1,144 @@ +/* + * 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.query; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import org.apache.openjpa.persistence.test.SingleEMTestCase; + +public class Test1x1OrderByResultCollection extends SingleEMTestCase { + + public void setUp() { + super.setUp(Hardware.class, Person.class, CLEAR_TABLES + , "openjpa.jdbc.DBDictionary", "fullResultCollectionInOrderByRelation=true" + ); + + populateData(); + } + + public void testCollectionSizeNoOrderBy() { + Query query = em.createQuery("select h from Hardware h where h.empNo = :empNo"); + query.setParameter("empNo", "Emp1"); + List results = (List) query.getResultList(); + + printResults("UnSorted", results); + + assertEquals(4, results.size()); + } + + public void testCollectionSizeOrderBy() { + Query query = em.createQuery("select h from Hardware h where h.empNo = :empNo order by h.techOwner.name"); + query.setParameter("empNo", "Emp1"); + List results = (List) query.getResultList(); + + printResults("Sorted asc", results); + + assertOrderBy(results, true); + } + + public void testCollectionSizeOrderByDesc() { + Query query = em.createQuery("select h from Hardware h where h.empNo = :empNo order by h.techOwner.name desc"); + query.setParameter("empNo", "Emp1"); + List results = (List) query.getResultList(); + + printResults("Sorted desc", results); + + assertOrderBy(results, false); + } + + private void assertOrderBy(List results, boolean asc) { + assertEquals(4, results.size()); + + // remove null techOwner or techOwner.name entries in collection first + List nonNullResults = new ArrayList(results.size()); + for (Hardware hw : results) { + if (hw.getTechOwner() != null + && hw.getTechOwner().getName() != null) { + nonNullResults.add(hw); + } + } + // Asert the remain entries in the collection are sort accordingly. + String curTechOwner = null; + String lastTechOwner = null; + for (Hardware hw : nonNullResults) { + if (lastTechOwner == null) { + lastTechOwner = hw.getTechOwner().getName(); + } else { + curTechOwner = hw.getTechOwner().getName(); + if (asc) { + assertTrue(lastTechOwner.compareTo(curTechOwner) <= 0); + } else { + assertTrue(lastTechOwner.compareTo(curTechOwner) >= 0); + } + lastTechOwner = curTechOwner; + } + } + } + + private void populateData() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + Person p1 = new Person("p1", "Person One"); + persist(p1); + Person p2 = new Person("p2", "Person Two"); + persist(p2); + Person p3 = new Person("p3", "Person Three"); + persist(p3); + Person p4 = new Person("p4", "Person Four"); + persist(p4); + Person pn = new Person("pn", null); + persist(pn); + + Hardware hwe1p2 = new Hardware(1, "Emp1"); + hwe1p2.setTechOwner(p2); + persist(hwe1p2); + Hardware hwe1p1 = new Hardware(2, "Emp1"); + hwe1p1.setTechOwner(p1); + persist(hwe1p1); + Hardware hwen = new Hardware(3, null); + hwen.setTechOwner(p4); + persist(hwen); + Hardware hwe1pn = new Hardware(4, "Emp1"); + hwe1pn.setTechOwner(pn); + persist(hwe1pn); + Hardware hwe2p3 = new Hardware(5, "Emp2"); + hwe2p3.setTechOwner(p3); + persist(hwe2p3); + Hardware hwe1np = new Hardware(6, "Emp1"); + persist(hwe1np); + + em.getTransaction().commit(); + em.close(); + } + + public void printResults(String heading, List results) { + System.out.println(heading + ": collection size= " + ((results == null) ? "0" : results.size())); + if (results != null) { + for (Hardware hw : results) { + Person to = hw.getTechOwner(); + String n = (to == null) ? "technical-owner-is-null" : to.getName(); + System.out.println(" id=" + hw.getId() + " TechnicalOwner=" + n); + } + } + } +}