Skip to content

Commit 647edf3

Browse files
committed
CAY-2895 Incorrect Lazy Pagination Comparison for BigInteger PK
1 parent 93e9681 commit 647edf3

6 files changed

Lines changed: 197 additions & 3 deletions

File tree

cayenne/src/main/java/org/apache/cayenne/access/translator/select/BaseColumnExtractor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ abstract class BaseColumnExtractor implements ColumnExtractor {
3636
this.context = context;
3737
}
3838

39-
protected void addDbAttribute(CayennePath prefix, CayennePath labelPrefix, DbAttribute dba) {
39+
protected ResultNodeDescriptor addDbAttribute(CayennePath prefix, CayennePath labelPrefix, DbAttribute dba) {
4040
String alias = context.getTableTree().aliasForPath(prefix);
4141
CayennePath dataRowKey = labelPrefix.dot(dba.getName());
4242
Node columnNode = table(alias).column(dba).build();
43-
context.addResultNode(columnNode, dataRowKey).setDbAttribute(dba);
43+
return context.addResultNode(columnNode, dataRowKey).setDbAttribute(dba);
4444
}
4545
}

cayenne/src/main/java/org/apache/cayenne/access/translator/select/IdColumnExtractor.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.cayenne.map.DbAttribute;
2424
import org.apache.cayenne.map.DbEntity;
2525
import org.apache.cayenne.map.EntityResult;
26+
import org.apache.cayenne.map.ObjAttribute;
2627
import org.apache.cayenne.map.ObjEntity;
2728

2829
/**
@@ -31,15 +32,18 @@
3132
class IdColumnExtractor extends BaseColumnExtractor {
3233

3334
private final DbEntity dbEntity;
35+
private ObjEntity objEntity;
3436
private EntityResult result;
3537

3638
IdColumnExtractor(TranslatorContext context, DbEntity dbEntity) {
3739
super(context);
3840
this.dbEntity = dbEntity;
41+
this.objEntity = null;
3942
}
4043

4144
IdColumnExtractor(TranslatorContext context, ObjEntity objEntity) {
4245
this(context, objEntity.getDbEntity());
46+
this.objEntity = objEntity;
4347
if(context.getQuery().needsResultSetMapping()) {
4448
this.result = new EntityResult(objEntity.getName());
4549
}
@@ -48,10 +52,17 @@ class IdColumnExtractor extends BaseColumnExtractor {
4852
@Override
4953
public void extract(CayennePath prefix) {
5054
for (DbAttribute dba : dbEntity.getPrimaryKeys()) {
51-
addDbAttribute(prefix, prefix, dba);
55+
ResultNodeDescriptor resultNodeDescriptor = addDbAttribute(prefix, prefix, dba);
5256
if(result != null) {
5357
result.addDbField(dba.getName(), prefix + dba.getName());
5458
}
59+
if(objEntity != null) {
60+
// redefine PK type if there's a corresponding ObjAttribute for it
61+
ObjAttribute meaningfulPK = objEntity.getAttributeForDbAttribute(dba);
62+
if(meaningfulPK != null) {
63+
resultNodeDescriptor.setJavaType(meaningfulPK.getType());
64+
}
65+
}
5566
}
5667
if(result != null) {
5768
context.getSqlResult().addEntityResult(result);

cayenne/src/test/java/org/apache/cayenne/access/DataContextEntityWithMeaningfulPKIT.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPKDep;
3232
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPKTest1;
3333
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPk;
34+
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkBigint;
3435
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkDep2;
3536
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkTest2;
3637
import org.apache.cayenne.unit.di.runtime.CayenneProjects;
@@ -39,6 +40,7 @@
3940
import org.junit.Ignore;
4041
import org.junit.Test;
4142

43+
import java.math.BigInteger;
4244
import java.util.List;
4345

4446
import static org.junit.Assert.*;
@@ -269,4 +271,60 @@ public void test_MeaningfulPkWithFkUpdate() {
269271
obj.setPkAttribute(1002);
270272
context.commitChanges();
271273
}
274+
275+
@Test
276+
public void testPaginatedQuery() {
277+
MeaningfulPk pkObj = context.newObject(MeaningfulPk.class);
278+
pkObj.setPk("123");
279+
context.commitChanges();
280+
281+
MeaningfulPk pkObj2 = context.newObject(MeaningfulPk.class);
282+
pkObj2.setPk("124");
283+
context.commitChanges();
284+
285+
MeaningfulPk pkObj3 = context.newObject(MeaningfulPk.class);
286+
pkObj3.setPk("125");
287+
context.commitChanges();
288+
289+
ObjectContext cleanContext = runtime.newContext();
290+
291+
List<MeaningfulPk> select = ObjectSelect.query(MeaningfulPk.class)
292+
.orderBy(MeaningfulPk.PK.asc())
293+
.pageSize(1)
294+
.select(cleanContext);
295+
296+
assertEquals(3, select.size());
297+
for(MeaningfulPk pk : select) {
298+
assertNotNull(pk.getPk());
299+
assertTrue(pk.getPk().startsWith("12"));
300+
}
301+
}
302+
303+
@Test
304+
public void testPaginatedQueryBigInteger() {
305+
MeaningfulPkBigint pkObj = context.newObject(MeaningfulPkBigint.class);
306+
pkObj.setPk(BigInteger.valueOf(123));
307+
context.commitChanges();
308+
309+
MeaningfulPkBigint pkObj2 = context.newObject(MeaningfulPkBigint.class);
310+
pkObj2.setPk(BigInteger.valueOf(124));
311+
context.commitChanges();
312+
313+
MeaningfulPkBigint pkObj3 = context.newObject(MeaningfulPkBigint.class);
314+
pkObj3.setPk(BigInteger.valueOf(125));
315+
context.commitChanges();
316+
317+
ObjectContext cleanContext = runtime.newContext();
318+
319+
List<MeaningfulPkBigint> select = ObjectSelect.query(MeaningfulPkBigint.class)
320+
.orderBy(MeaningfulPk.PK.asc())
321+
.pageSize(1)
322+
.select(cleanContext);
323+
324+
assertEquals(3, select.size());
325+
for(MeaningfulPkBigint pk : select) {
326+
assertNotNull(pk.getPk());
327+
assertTrue(pk.getPk().compareTo(BigInteger.valueOf(120)) > 0);
328+
}
329+
}
272330
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
****************************************************************/
19+
package org.apache.cayenne.testdo.meaningful_pk;
20+
21+
import org.apache.cayenne.testdo.meaningful_pk.auto._MeaningfulPkBigint;
22+
23+
public class MeaningfulPkBigint extends _MeaningfulPkBigint {
24+
25+
private static final long serialVersionUID = 1L;
26+
27+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package org.apache.cayenne.testdo.meaningful_pk.auto;
2+
3+
import java.io.IOException;
4+
import java.io.ObjectInputStream;
5+
import java.io.ObjectOutputStream;
6+
import java.math.BigInteger;
7+
8+
import org.apache.cayenne.PersistentObject;
9+
import org.apache.cayenne.exp.property.NumericProperty;
10+
import org.apache.cayenne.exp.property.PropertyFactory;
11+
import org.apache.cayenne.exp.property.SelfProperty;
12+
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkBigint;
13+
14+
/**
15+
* Class _MeaningfulPkBigint was generated by Cayenne.
16+
* It is probably a good idea to avoid changing this class manually,
17+
* since it may be overwritten next time code is regenerated.
18+
* If you need to make any customizations, please use subclass.
19+
*/
20+
public abstract class _MeaningfulPkBigint extends PersistentObject {
21+
22+
private static final long serialVersionUID = 1L;
23+
24+
public static final SelfProperty<MeaningfulPkBigint> SELF = PropertyFactory.createSelf(MeaningfulPkBigint.class);
25+
26+
public static final String PK_PK_COLUMN = "PK";
27+
28+
public static final NumericProperty<BigInteger> PK = PropertyFactory.createNumeric("pk", BigInteger.class);
29+
30+
protected BigInteger pk;
31+
32+
33+
public void setPk(BigInteger pk) {
34+
beforePropertyWrite("pk", this.pk, pk);
35+
this.pk = pk;
36+
}
37+
38+
public BigInteger getPk() {
39+
beforePropertyRead("pk");
40+
return this.pk;
41+
}
42+
43+
@Override
44+
public Object readPropertyDirectly(String propName) {
45+
if(propName == null) {
46+
throw new IllegalArgumentException();
47+
}
48+
49+
switch(propName) {
50+
case "pk":
51+
return this.pk;
52+
default:
53+
return super.readPropertyDirectly(propName);
54+
}
55+
}
56+
57+
@Override
58+
public void writePropertyDirectly(String propName, Object val) {
59+
if(propName == null) {
60+
throw new IllegalArgumentException();
61+
}
62+
63+
switch (propName) {
64+
case "pk":
65+
this.pk = (BigInteger)val;
66+
break;
67+
default:
68+
super.writePropertyDirectly(propName, val);
69+
}
70+
}
71+
72+
private void writeObject(ObjectOutputStream out) throws IOException {
73+
writeSerialized(out);
74+
}
75+
76+
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
77+
readSerialized(in);
78+
}
79+
80+
@Override
81+
protected void writeState(ObjectOutputStream out) throws IOException {
82+
super.writeState(out);
83+
out.writeObject(this.pk);
84+
}
85+
86+
@Override
87+
protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
88+
super.readState(in);
89+
this.pk = (BigInteger)in.readObject();
90+
}
91+
92+
}

cayenne/src/test/resources/meaningful-pk.map.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
<db-entity name="MEANINGFUL_PK">
88
<db-attribute name="PK" type="VARCHAR" isPrimaryKey="true" isMandatory="true" length="100"/>
99
</db-entity>
10+
<db-entity name="MEANINGFUL_PK_BIGINT">
11+
<db-attribute name="PK" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
12+
</db-entity>
1013
<db-entity name="MEANINGFUL_PK_DEP">
1114
<db-attribute name="DESCR" type="VARCHAR" length="50"/>
1215
<db-attribute name="MASTER_PK" type="INTEGER"/>
@@ -40,6 +43,9 @@
4043
<obj-entity name="MeaningfulPk" className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPk" dbEntityName="MEANINGFUL_PK">
4144
<obj-attribute name="pk" type="java.lang.String" db-attribute-path="PK"/>
4245
</obj-entity>
46+
<obj-entity name="MeaningfulPkBigint" className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkBigint" dbEntityName="MEANINGFUL_PK_BIGINT">
47+
<obj-attribute name="pk" type="java.math.BigInteger" db-attribute-path="PK"/>
48+
</obj-entity>
4349
<obj-entity name="MeaningfulPkDep2" className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkDep2" dbEntityName="MEANINGFUL_PK_DEP2">
4450
<obj-attribute name="descr" type="java.lang.String" db-attribute-path="DESCR"/>
4551
<obj-attribute name="pk" type="java.lang.String" db-attribute-path="PK"/>

0 commit comments

Comments
 (0)