Skip to content

Commit f6bbeeb

Browse files
author
Tomáš Kraus
authored
Issue #2301 - Sorting not honored with JPA and Oracle (#2315)
Signed-off-by: Tomáš Kraus <tomas.kraus@oracle.com>
1 parent 2db4798 commit f6bbeeb

File tree

6 files changed

+257
-11
lines changed

6 files changed

+257
-11
lines changed

foundation/eclipselink.core.test/src/org/eclipse/persistence/testing/framework/TogglingFastTableCreator.java

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2010, 2015 IBM Corporation.
44
* Copyright (c) 2010, 2015 Dies Koper (Fujitsu).
55
*
@@ -241,22 +241,37 @@ protected static FieldDefinition createNumericFk(
241241
* with given name and size and without any additional constraints.
242242
* @param name Column name.
243243
* @param size Column numeric type size.
244+
* @param subSize Column numeric type sub size.
244245
* @param allowNull Allow {@code null} values for column.
245246
* @return Initialized {@link FieldDefinition} instance.
246247
*/
247248
protected static FieldDefinition createNumericColumn(
248-
final String name, final int size, final boolean allowNull) {
249+
final String name, final int size, final int subSize, final boolean allowNull) {
249250
final FieldDefinition field = new FieldDefinition();
250251
field.setName(name);
251252
field.setTypeName("NUMERIC");
252253
field.setSize(size);
254+
field.setSubSize(subSize);
253255
field.setShouldAllowNull(allowNull);
254256
field.setIsPrimaryKey(false);
255257
field.setUnique(false);
256258
field.setIsIdentity(false);
257259
return field;
258260
}
259261

262+
/**
263+
* Helper method to create {@link FieldDefinition} instance for numeric column
264+
* with given name and size and without any additional constraints.
265+
* @param name Column name.
266+
* @param size Column numeric type size.
267+
* @param allowNull Allow {@code null} values for column.
268+
* @return Initialized {@link FieldDefinition} instance.
269+
*/
270+
protected static FieldDefinition createNumericColumn(
271+
final String name, final int size, final boolean allowNull) {
272+
return createNumericColumn(name, size, 0, allowNull);
273+
}
274+
260275
/**
261276
* Helper method to create {@link FieldDefinition} instance for numeric column
262277
* with given name, size of {@code 15}, with {@code null} value allowed and
@@ -271,6 +286,44 @@ protected static FieldDefinition createNumericColumn(
271286
return createNumericColumn(name, 15, true);
272287
}
273288

289+
/**
290+
* Helper method to create {@link FieldDefinition} instance for numeric column
291+
* with given name to store float type values.
292+
* @param name Column name.
293+
* @param allowNull Allow {@code null} values for column.
294+
* @return Initialized {@link FieldDefinition} instance.
295+
*/
296+
protected static FieldDefinition createFloatColumn(
297+
final String name, final boolean allowNull) {
298+
final FieldDefinition field = new FieldDefinition();
299+
field.setName(name);
300+
field.setType(Float.class);
301+
field.setShouldAllowNull(allowNull);
302+
field.setIsPrimaryKey(false);
303+
field.setUnique(false);
304+
field.setIsIdentity(false);
305+
return field;
306+
}
307+
308+
/**
309+
* Helper method to create {@link FieldDefinition} instance for numeric column
310+
* with given name to store double type values.
311+
* @param name Column name.
312+
* @param allowNull Allow {@code null} values for column.
313+
* @return Initialized {@link FieldDefinition} instance.
314+
*/
315+
protected static FieldDefinition createDoubleColumn(
316+
final String name, final boolean allowNull) {
317+
final FieldDefinition field = new FieldDefinition();
318+
field.setName(name);
319+
field.setType(Double.class);
320+
field.setShouldAllowNull(allowNull);
321+
field.setIsPrimaryKey(false);
322+
field.setUnique(false);
323+
field.setIsIdentity(false);
324+
return field;
325+
}
326+
274327
/**
275328
* Helper method to create {@link FieldDefinition} instance for <code>DTYPE</code>
276329
* column used for inheritance in model.
@@ -319,7 +372,7 @@ protected static FieldDefinition createStringColumn(
319372
*/
320373
protected static FieldDefinition createStringColumn(
321374
final String name) {
322-
return createStringColumn(name, 32, true);
375+
return createStringColumn(name, 255, true);
323376
}
324377

325378
/**

foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/platform/database/OraclePlatform.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2023 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 1998, 2023 IBM Corporation. All rights reserved.
44
*
55
* This program and the accompanying materials are made available under the
@@ -1030,8 +1030,16 @@ public void printSQLSelectStatement(DatabaseCall call, ExpressionSQLPrinter prin
10301030
printer.printString(primaryKeyFields);
10311031
printer.printString(FROM_ID);
10321032
printer.printString(queryString);
1033-
printer.printString(ORDER_BY_ID);
1034-
printer.printString(primaryKeyFields);
1033+
if (statement.hasOrderByExpressions()) {
1034+
try {
1035+
statement.printSQLOrderByClause(printer);
1036+
} catch (IOException exception) {
1037+
throw ValidationException.fileError(exception);
1038+
}
1039+
} else {
1040+
printer.printString(ORDER_BY_ID);
1041+
printer.printString(primaryKeyFields);
1042+
}
10351043
printer.printString(END_FROM_ID);
10361044
printer.printString(MAX_ROW);
10371045
printer.printParameter(DatabaseCall.MAXROW_FIELD);

jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/AdvancedTableCreator.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 1998, 2019 IBM Corporation. All rights reserved.
44
*
55
* This program and the accompanying materials are made available under the
@@ -124,6 +124,7 @@ public AdvancedTableCreator() {
124124
addTableDefinition(buildORD_ENTITYATable());
125125
addTableDefinition(buildORD_ENTITYZTable());
126126
addTableDefinition(buildMyTestEntityTable());
127+
addTableDefinition(buildEntityFloatTable());
127128
}
128129

129130
public TableDefinition buildADDRESSTable() {
@@ -3377,7 +3378,20 @@ public TableDefinition buildMyTestEntityTable() {
33773378

33783379
return table;
33793380
}
3380-
3381+
3382+
3383+
// Supported data types according to https://docs.oracle.com/cd/E19501-01/819-3659/gcmaz/
3384+
private TableDefinition buildEntityFloatTable() {
3385+
TableDefinition table = new TableDefinition();
3386+
table.setName(EntityFloat.TABLE_NAME);
3387+
table.addField(createNumericPk("ID", 10));
3388+
table.addField(createFloatColumn("HEIGHT", false));
3389+
table.addField(createFloatColumn("LENGTH", false));
3390+
table.addField(createFloatColumn("WIDTH", false));
3391+
table.addField(createStringColumn("DESCRIPTION", 255,false));
3392+
return table;
3393+
}
3394+
33813395
@Override
33823396
public void replaceTables(DatabaseSession session) {
33833397
DatabasePlatform dbPlatform = session.getPlatform();
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2024 IBM Corporation. All rights reserved.
4+
*
5+
* This program and the accompanying materials are made available under the
6+
* terms of the Eclipse Public License v. 2.0 which is available at
7+
* http://www.eclipse.org/legal/epl-2.0,
8+
* or the Eclipse Distribution License v. 1.0 which is available at
9+
* http://www.eclipse.org/org/documents/edl-v10.php.
10+
*
11+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
12+
*/
13+
package org.eclipse.persistence.testing.models.jpa.advanced;
14+
15+
import javax.persistence.Column;
16+
import javax.persistence.Entity;
17+
import javax.persistence.Id;
18+
import javax.persistence.Table;
19+
20+
// Based on reproduction scenario from issue #2301 (https://github.com/eclipse-ee4j/eclipselink/issues/2301)
21+
@Entity
22+
@Table(name = EntityFloat.TABLE_NAME)
23+
public class EntityFloat {
24+
25+
public static final String TABLE_NAME = "ADV_ENTITY_FLOAT";
26+
27+
@Id
28+
@Column(name = "ID")
29+
private int id;
30+
31+
@Column(name = "HEIGHT")
32+
private float height;
33+
34+
@Column(name = "LENGTH")
35+
private float length;
36+
37+
@Column(name = "WIDTH")
38+
private float width;
39+
40+
@Column(name = "DESCRIPTION")
41+
private String description;
42+
43+
public EntityFloat() {
44+
this(-1, 0f, 0f, 0f, null);
45+
}
46+
47+
public EntityFloat(int id, float length, float width, float height, String description) {
48+
this.id = id;
49+
this.length = length;
50+
this.width = width;
51+
this.height = height;
52+
this.description = description;
53+
}
54+
55+
public int getId() {
56+
return id;
57+
}
58+
59+
public void setId(int id) {
60+
this.id = id;
61+
}
62+
63+
public float getHeight() {
64+
return height;
65+
}
66+
67+
public void setHeight(float height) {
68+
this.height = height;
69+
}
70+
71+
public float getLength() {
72+
return length;
73+
}
74+
75+
public void setLength(float length) {
76+
this.length = length;
77+
}
78+
79+
public float getWidth() {
80+
return width;
81+
}
82+
83+
public void setWidth(float width) {
84+
this.width = width;
85+
}
86+
87+
public String getDescription() {
88+
return description;
89+
}
90+
91+
public void setDescription(String description) {
92+
this.description = description;
93+
}
94+
95+
@Override
96+
public String toString() {
97+
return String.format(
98+
"EntityFloat{ id=%d, length=%f, width=%f, height=%f, description=\"%s\"}",
99+
id, length, width, height, description);
100+
}
101+
102+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2024 IBM Corporation. All rights reserved.
4+
*
5+
* This program and the accompanying materials are made available under the
6+
* terms of the Eclipse Public License v. 2.0 which is available at
7+
* http://www.eclipse.org/legal/epl-2.0,
8+
* or the Eclipse Distribution License v. 1.0 which is available at
9+
* http://www.eclipse.org/org/documents/edl-v10.php.
10+
*
11+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
12+
*/
13+
package org.eclipse.persistence.testing.models.jpa.advanced;
14+
15+
import java.util.Arrays;
16+
import java.util.List;
17+
18+
import org.eclipse.persistence.sessions.Session;
19+
import org.eclipse.persistence.sessions.UnitOfWork;
20+
21+
public class EntityFloatPopulator {
22+
23+
private EntityFloatPopulator() {
24+
throw new UnsupportedOperationException("No instances of EntityFloatPopulator are allowed");
25+
}
26+
27+
static EntityFloat[] ENTITY_FLOAT = new EntityFloat[] {
28+
// Tallest and smallest length
29+
new EntityFloat(70071, 17.0f, 17.1f, 7.7f, "testOLGH28289#70071"),
30+
// Tallest and largest length
31+
new EntityFloat(70077, 77.0f, 17.7f, 7.7f, "testOLGH28289#70077"),
32+
new EntityFloat(70007, 70.0f, 10.7f, 0.7f, "testOLGH28289#70007")
33+
};
34+
35+
public static void populate(Session session) {
36+
List<Object> entities = Arrays.asList(ENTITY_FLOAT);
37+
UnitOfWork unitOfWork = session.acquireUnitOfWork();
38+
unitOfWork.removeAllReadOnlyClasses();
39+
unitOfWork.registerAllObjects(entities);
40+
unitOfWork.commit();
41+
}
42+
43+
}

jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/jpql/AdvancedQueryTestSuite.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2023 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2019 IBM Corporation. All rights reserved.
44
*
55
* This program and the accompanying materials are made available under the
@@ -60,11 +60,13 @@
6060
import org.eclipse.persistence.testing.models.jpa.inheritance.Engineer;
6161
import org.eclipse.persistence.testing.models.jpa.inheritance.InheritancePopulator;
6262
import org.eclipse.persistence.testing.models.jpa.inheritance.InheritanceTableCreator;
63+
import org.eclipse.persistence.testing.models.jpa.advanced.Address;
6364
import org.eclipse.persistence.testing.models.jpa.advanced.Buyer;
6465
import org.eclipse.persistence.testing.models.jpa.advanced.Department;
6566
import org.eclipse.persistence.testing.models.jpa.advanced.Employee;
66-
import org.eclipse.persistence.testing.models.jpa.advanced.Address;
67+
import org.eclipse.persistence.testing.models.jpa.advanced.EntityFloat;
6768
import org.eclipse.persistence.testing.models.jpa.advanced.EmployeePopulator;
69+
import org.eclipse.persistence.testing.models.jpa.advanced.EntityFloatPopulator;
6870
import org.eclipse.persistence.testing.models.jpa.advanced.AdvancedTableCreator;
6971
import org.eclipse.persistence.testing.models.jpa.advanced.Employee.Gender;
7072
import org.eclipse.persistence.testing.models.jpa.inheritance.Person;
@@ -170,6 +172,7 @@ public static Test suite() {
170172
suite.addTest(new AdvancedQueryTestSuite("testQueryPESSIMISTIC_FORCE_INCREMENTLock"));
171173
suite.addTest(new AdvancedQueryTestSuite("testVersionChangeWithReadLock"));
172174
suite.addTest(new AdvancedQueryTestSuite("testVersionChangeWithWriteLock"));
175+
suite.addTest(new AdvancedQueryTestSuite("testFloatSortWithPessimisticLock"));
173176
suite.addTest(new AdvancedQueryTestSuite("testNamedQueryAnnotationOverwritePersistenceXML"));
174177
}
175178
return suite;
@@ -192,7 +195,8 @@ public void testSetup() {
192195
employeePopulator.buildExamples();
193196
//Persist the examples in the database
194197
employeePopulator.persistExample(session);
195-
198+
// EntityFloat instances to test issue #2301
199+
EntityFloatPopulator.populate(session);
196200
new RelationshipsTableManager().replaceTables(session);
197201
//populate the relationships model and persist as well
198202
new RelationshipsExamples().buildExamples(session);
@@ -2950,4 +2954,26 @@ public void run() {
29502954
closeEntityManager(em);
29512955
}
29522956
}
2957+
2958+
// Based on reproduction scenario from issue #2301 (https://github.com/eclipse-ee4j/eclipselink/issues/2301)
2959+
public void testFloatSortWithPessimisticLock() {
2960+
EntityManager em = createEntityManager();
2961+
beginTransaction(em);
2962+
List<EntityFloat> entities;
2963+
try {
2964+
entities = em.createQuery("SELECT f FROM EntityFloat f WHERE (f.height < ?1) ORDER BY f.height DESC, f.length",
2965+
EntityFloat.class)
2966+
.setParameter(1, 8.0)
2967+
.setLockMode(LockModeType.PESSIMISTIC_WRITE) // Cause of issue
2968+
.setMaxResults(2)
2969+
.getResultList();
2970+
commitTransaction(em);
2971+
} catch (PersistenceException ex) {
2972+
rollbackTransaction(em);
2973+
throw ex;
2974+
}
2975+
assertEquals(2, entities.size());
2976+
assertEquals(70071, entities.get(0).getId());
2977+
assertEquals(70077, entities.get(1).getId());
2978+
}
29532979
}

0 commit comments

Comments
 (0)