Skip to content

Commit 336bcf1

Browse files
committed
CAY-2895 Incorrect Lazy Pagination Comparison for BigInteger PK
1 parent 15edc46 commit 336bcf1

6 files changed

Lines changed: 196 additions & 3 deletions

File tree

cayenne-server/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
@@ -35,10 +35,10 @@ abstract class BaseColumnExtractor implements ColumnExtractor {
3535
this.context = context;
3636
}
3737

38-
protected void addDbAttribute(String prefix, String labelPrefix, DbAttribute dba) {
38+
protected ResultNodeDescriptor addDbAttribute(String prefix, String labelPrefix, DbAttribute dba) {
3939
String alias = context.getTableTree().aliasForPath(prefix);
4040
String dataRowKey = labelPrefix != null ? labelPrefix + '.' + dba.getName() : dba.getName();
4141
Node columnNode = table(alias).column(dba).build();
42-
context.addResultNode(columnNode, dataRowKey).setDbAttribute(dba);
42+
return context.addResultNode(columnNode, dataRowKey).setDbAttribute(dba);
4343
}
4444
}

cayenne-server/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
@@ -22,6 +22,7 @@
2222
import org.apache.cayenne.map.DbAttribute;
2323
import org.apache.cayenne.map.DbEntity;
2424
import org.apache.cayenne.map.EntityResult;
25+
import org.apache.cayenne.map.ObjAttribute;
2526
import org.apache.cayenne.map.ObjEntity;
2627

2728
/**
@@ -30,15 +31,18 @@
3031
class IdColumnExtractor extends BaseColumnExtractor {
3132

3233
private final DbEntity dbEntity;
34+
private ObjEntity objEntity;
3335
private EntityResult result;
3436

3537
IdColumnExtractor(TranslatorContext context, DbEntity dbEntity) {
3638
super(context);
3739
this.dbEntity = dbEntity;
40+
this.objEntity = null;
3841
}
3942

4043
IdColumnExtractor(TranslatorContext context, ObjEntity objEntity) {
4144
this(context, objEntity.getDbEntity());
45+
this.objEntity = objEntity;
4246
if(context.getQuery().needsResultSetMapping()) {
4347
this.result = new EntityResult(objEntity.getName());
4448
}
@@ -47,10 +51,17 @@ class IdColumnExtractor extends BaseColumnExtractor {
4751
@Override
4852
public void extract(String prefix) {
4953
for (DbAttribute dba : dbEntity.getPrimaryKeys()) {
50-
addDbAttribute(prefix, prefix, dba);
54+
ResultNodeDescriptor resultNodeDescriptor = addDbAttribute(prefix, prefix, dba);
5155
if(result != null) {
5256
result.addDbField(dba.getName(), prefix + dba.getName());
5357
}
58+
if(objEntity != null) {
59+
// redefine PK type if there's a corresponding ObjAttribute for it
60+
ObjAttribute meaningfulPK = objEntity.getAttributeForDbAttribute(dba);
61+
if(meaningfulPK != null) {
62+
resultNodeDescriptor.setJavaType(meaningfulPK.getType());
63+
}
64+
}
5465
}
5566
if(result != null) {
5667
context.getSqlResult().addEntityResult(result);

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

Lines changed: 60 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.server.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
import java.util.Map;
4446

@@ -270,4 +272,62 @@ public void test_MeaningfulPkWithFkUpdate() {
270272
obj.setPkAttribute(1002);
271273
context.commitChanges();
272274
}
275+
276+
@Test
277+
public void testPaginatedQuery() {
278+
MeaningfulPk pkObj = context.newObject(MeaningfulPk.class);
279+
pkObj.setPk("123");
280+
context.commitChanges();
281+
282+
MeaningfulPk pkObj2 = context.newObject(MeaningfulPk.class);
283+
pkObj2.setPk("124");
284+
context.commitChanges();
285+
286+
MeaningfulPk pkObj3 = context.newObject(MeaningfulPk.class);
287+
pkObj3.setPk("125");
288+
context.commitChanges();
289+
290+
ObjectContext cleanContext = runtime.newContext();
291+
292+
List<MeaningfulPk> select = ObjectSelect.query(MeaningfulPk.class)
293+
.orderBy(MeaningfulPk.PK.asc())
294+
.pageSize(1)
295+
.select(cleanContext);
296+
297+
assertEquals(3, select.size());
298+
for(MeaningfulPk pk : select) {
299+
assertNotNull(pk.getPk());
300+
assertTrue(pk.getPk().startsWith("12"));
301+
}
302+
}
303+
304+
305+
@Test
306+
public void testPaginatedQueryBigInteger() {
307+
MeaningfulPkBigint pkObj = context.newObject(MeaningfulPkBigint.class);
308+
pkObj.setPk(BigInteger.valueOf(123));
309+
context.commitChanges();
310+
311+
MeaningfulPkBigint pkObj2 = context.newObject(MeaningfulPkBigint.class);
312+
pkObj2.setPk(BigInteger.valueOf(124));
313+
context.commitChanges();
314+
315+
MeaningfulPkBigint pkObj3 = context.newObject(MeaningfulPkBigint.class);
316+
pkObj3.setPk(BigInteger.valueOf(125));
317+
context.commitChanges();
318+
319+
ObjectContext cleanContext = runtime.newContext();
320+
321+
List<MeaningfulPkBigint> select = ObjectSelect.query(MeaningfulPkBigint.class)
322+
.orderBy(MeaningfulPk.PK.asc())
323+
.pageSize(1)
324+
.select(cleanContext);
325+
326+
assertEquals(3, select.size());
327+
for(MeaningfulPkBigint pk : select) {
328+
assertNotNull(pk.getPk());
329+
assertTrue(pk.getPk().compareTo(BigInteger.valueOf(120)) > 0);
330+
}
331+
}
332+
273333
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
20+
package org.apache.cayenne.testdo.meaningful_pk;
21+
22+
import org.apache.cayenne.testdo.meaningful_pk.auto._MeaningfulPkBigint;
23+
24+
public class MeaningfulPkBigint extends _MeaningfulPkBigint {
25+
26+
private static final long serialVersionUID = 1L;
27+
28+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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.BaseDataObject;
9+
import org.apache.cayenne.exp.property.NumericProperty;
10+
import org.apache.cayenne.exp.property.PropertyFactory;
11+
12+
/**
13+
* Class _MeaningfulPkBigint was generated by Cayenne.
14+
* It is probably a good idea to avoid changing this class manually,
15+
* since it may be overwritten next time code is regenerated.
16+
* If you need to make any customizations, please use subclass.
17+
*/
18+
public abstract class _MeaningfulPkBigint extends BaseDataObject {
19+
20+
private static final long serialVersionUID = 1L;
21+
22+
public static final String PK_PK_COLUMN = "PK";
23+
24+
public static final NumericProperty<BigInteger> PK = PropertyFactory.createNumeric("pk", BigInteger.class);
25+
26+
protected BigInteger pk;
27+
28+
29+
public void setPk(BigInteger pk) {
30+
beforePropertyWrite("pk", this.pk, pk);
31+
this.pk = pk;
32+
}
33+
34+
public BigInteger getPk() {
35+
beforePropertyRead("pk");
36+
return this.pk;
37+
}
38+
39+
@Override
40+
public Object readPropertyDirectly(String propName) {
41+
if(propName == null) {
42+
throw new IllegalArgumentException();
43+
}
44+
45+
switch(propName) {
46+
case "pk":
47+
return this.pk;
48+
default:
49+
return super.readPropertyDirectly(propName);
50+
}
51+
}
52+
53+
@Override
54+
public void writePropertyDirectly(String propName, Object val) {
55+
if(propName == null) {
56+
throw new IllegalArgumentException();
57+
}
58+
59+
switch (propName) {
60+
case "pk":
61+
this.pk = (BigInteger)val;
62+
break;
63+
default:
64+
super.writePropertyDirectly(propName, val);
65+
}
66+
}
67+
68+
private void writeObject(ObjectOutputStream out) throws IOException {
69+
writeSerialized(out);
70+
}
71+
72+
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
73+
readSerialized(in);
74+
}
75+
76+
@Override
77+
protected void writeState(ObjectOutputStream out) throws IOException {
78+
super.writeState(out);
79+
out.writeObject(this.pk);
80+
}
81+
82+
@Override
83+
protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
84+
super.readState(in);
85+
this.pk = (BigInteger)in.readObject();
86+
}
87+
88+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
<db-entity name="MEANINGFUL_PK">
1010
<db-attribute name="PK" type="VARCHAR" isPrimaryKey="true" isMandatory="true" length="100"/>
1111
</db-entity>
12+
<db-entity name="MEANINGFUL_PK_BIGINT">
13+
<db-attribute name="PK" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
14+
</db-entity>
1215
<db-entity name="MEANINGFUL_PK_DEP">
1316
<db-attribute name="DESCR" type="VARCHAR" length="50"/>
1417
<db-attribute name="MASTER_PK" type="INTEGER"/>
@@ -42,6 +45,9 @@
4245
<obj-entity name="MeaningfulPk" className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPk" clientClassName="org.apache.cayenne.testdo.meaningful_pk.ClientMeaningfulPk" dbEntityName="MEANINGFUL_PK">
4346
<obj-attribute name="pk" type="java.lang.String" db-attribute-path="PK"/>
4447
</obj-entity>
48+
<obj-entity name="MeaningfulPkBigint" className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkBigint" dbEntityName="MEANINGFUL_PK_BIGINT">
49+
<obj-attribute name="pk" type="java.math.BigInteger" db-attribute-path="PK"/>
50+
</obj-entity>
4551
<obj-entity name="MeaningfulPkDep2" className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkDep2" clientClassName="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkDep2" dbEntityName="MEANINGFUL_PK_DEP2">
4652
<obj-attribute name="descr" type="java.lang.String" db-attribute-path="DESCR"/>
4753
<obj-attribute name="pk" type="java.lang.String" db-attribute-path="PK"/>

0 commit comments

Comments
 (0)