This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/STABLE-4.2 by this push:
new 336bcf16a CAY-2895 Incorrect Lazy Pagination Comparison for BigInteger
PK
336bcf16a is described below
commit 336bcf16a46490c90257a4959fa6a5e6d5f9c551
Author: Nikita Timofeev <[email protected]>
AuthorDate: Tue Oct 7 15:40:10 2025 +0400
CAY-2895 Incorrect Lazy Pagination Comparison for BigInteger PK
---
.../translator/select/BaseColumnExtractor.java | 4 +-
.../translator/select/IdColumnExtractor.java | 13 +++-
.../DataContextEntityWithMeaningfulPKIT.java | 60 +++++++++++++++
.../testdo/meaningful_pk/MeaningfulPkBigint.java} | 24 +-----
.../meaningful_pk/auto/_MeaningfulPkBigint.java | 88 ++++++++++++++++++++++
.../src/test/resources/meaningful-pk.map.xml | 6 ++
6 files changed, 172 insertions(+), 23 deletions(-)
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/BaseColumnExtractor.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/BaseColumnExtractor.java
index de8a1bc44..7b0fee15e 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/BaseColumnExtractor.java
+++
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/BaseColumnExtractor.java
@@ -35,10 +35,10 @@ abstract class BaseColumnExtractor implements
ColumnExtractor {
this.context = context;
}
- protected void addDbAttribute(String prefix, String labelPrefix,
DbAttribute dba) {
+ protected ResultNodeDescriptor addDbAttribute(String prefix, String
labelPrefix, DbAttribute dba) {
String alias = context.getTableTree().aliasForPath(prefix);
String dataRowKey = labelPrefix != null ? labelPrefix + '.' +
dba.getName() : dba.getName();
Node columnNode = table(alias).column(dba).build();
- context.addResultNode(columnNode, dataRowKey).setDbAttribute(dba);
+ return context.addResultNode(columnNode,
dataRowKey).setDbAttribute(dba);
}
}
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/IdColumnExtractor.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/IdColumnExtractor.java
index 3f237c08a..3c3f536ab 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/IdColumnExtractor.java
+++
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/IdColumnExtractor.java
@@ -22,6 +22,7 @@ package org.apache.cayenne.access.translator.select;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.EntityResult;
+import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjEntity;
/**
@@ -30,15 +31,18 @@ import org.apache.cayenne.map.ObjEntity;
class IdColumnExtractor extends BaseColumnExtractor {
private final DbEntity dbEntity;
+ private ObjEntity objEntity;
private EntityResult result;
IdColumnExtractor(TranslatorContext context, DbEntity dbEntity) {
super(context);
this.dbEntity = dbEntity;
+ this.objEntity = null;
}
IdColumnExtractor(TranslatorContext context, ObjEntity objEntity) {
this(context, objEntity.getDbEntity());
+ this.objEntity = objEntity;
if(context.getQuery().needsResultSetMapping()) {
this.result = new EntityResult(objEntity.getName());
}
@@ -47,10 +51,17 @@ class IdColumnExtractor extends BaseColumnExtractor {
@Override
public void extract(String prefix) {
for (DbAttribute dba : dbEntity.getPrimaryKeys()) {
- addDbAttribute(prefix, prefix, dba);
+ ResultNodeDescriptor resultNodeDescriptor = addDbAttribute(prefix,
prefix, dba);
if(result != null) {
result.addDbField(dba.getName(), prefix + dba.getName());
}
+ if(objEntity != null) {
+ // redefine PK type if there's a corresponding ObjAttribute
for it
+ ObjAttribute meaningfulPK =
objEntity.getAttributeForDbAttribute(dba);
+ if(meaningfulPK != null) {
+ resultNodeDescriptor.setJavaType(meaningfulPK.getType());
+ }
+ }
}
if(result != null) {
context.getSqlResult().addEntityResult(result);
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextEntityWithMeaningfulPKIT.java
b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextEntityWithMeaningfulPKIT.java
index 770072f7c..16198a384 100644
---
a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextEntityWithMeaningfulPKIT.java
+++
b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextEntityWithMeaningfulPKIT.java
@@ -31,6 +31,7 @@ import org.apache.cayenne.query.ObjectSelect;
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPKDep;
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPKTest1;
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPk;
+import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkBigint;
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkDep2;
import org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkTest2;
import org.apache.cayenne.unit.di.server.CayenneProjects;
@@ -39,6 +40,7 @@ import org.apache.cayenne.unit.di.server.UseServerRuntime;
import org.junit.Ignore;
import org.junit.Test;
+import java.math.BigInteger;
import java.util.List;
import java.util.Map;
@@ -270,4 +272,62 @@ public class DataContextEntityWithMeaningfulPKIT extends
ServerCase {
obj.setPkAttribute(1002);
context.commitChanges();
}
+
+ @Test
+ public void testPaginatedQuery() {
+ MeaningfulPk pkObj = context.newObject(MeaningfulPk.class);
+ pkObj.setPk("123");
+ context.commitChanges();
+
+ MeaningfulPk pkObj2 = context.newObject(MeaningfulPk.class);
+ pkObj2.setPk("124");
+ context.commitChanges();
+
+ MeaningfulPk pkObj3 = context.newObject(MeaningfulPk.class);
+ pkObj3.setPk("125");
+ context.commitChanges();
+
+ ObjectContext cleanContext = runtime.newContext();
+
+ List<MeaningfulPk> select = ObjectSelect.query(MeaningfulPk.class)
+ .orderBy(MeaningfulPk.PK.asc())
+ .pageSize(1)
+ .select(cleanContext);
+
+ assertEquals(3, select.size());
+ for(MeaningfulPk pk : select) {
+ assertNotNull(pk.getPk());
+ assertTrue(pk.getPk().startsWith("12"));
+ }
+ }
+
+
+ @Test
+ public void testPaginatedQueryBigInteger() {
+ MeaningfulPkBigint pkObj = context.newObject(MeaningfulPkBigint.class);
+ pkObj.setPk(BigInteger.valueOf(123));
+ context.commitChanges();
+
+ MeaningfulPkBigint pkObj2 =
context.newObject(MeaningfulPkBigint.class);
+ pkObj2.setPk(BigInteger.valueOf(124));
+ context.commitChanges();
+
+ MeaningfulPkBigint pkObj3 =
context.newObject(MeaningfulPkBigint.class);
+ pkObj3.setPk(BigInteger.valueOf(125));
+ context.commitChanges();
+
+ ObjectContext cleanContext = runtime.newContext();
+
+ List<MeaningfulPkBigint> select =
ObjectSelect.query(MeaningfulPkBigint.class)
+ .orderBy(MeaningfulPk.PK.asc())
+ .pageSize(1)
+ .select(cleanContext);
+
+ assertEquals(3, select.size());
+ for(MeaningfulPkBigint pk : select) {
+ assertNotNull(pk.getPk());
+ assertTrue(pk.getPk().compareTo(BigInteger.valueOf(120)) > 0);
+ }
+ }
+
}
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/BaseColumnExtractor.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/meaningful_pk/MeaningfulPkBigint.java
similarity index 53%
copy from
cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/BaseColumnExtractor.java
copy to
cayenne-server/src/test/java/org/apache/cayenne/testdo/meaningful_pk/MeaningfulPkBigint.java
index de8a1bc44..fbc51cbfc 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/BaseColumnExtractor.java
+++
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/meaningful_pk/MeaningfulPkBigint.java
@@ -17,28 +17,12 @@
* under the License.
****************************************************************/
-package org.apache.cayenne.access.translator.select;
+package org.apache.cayenne.testdo.meaningful_pk;
-import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
-import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.testdo.meaningful_pk.auto._MeaningfulPkBigint;
-import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.table;
+public class MeaningfulPkBigint extends _MeaningfulPkBigint {
-/**
- * @since 4.2
- */
-abstract class BaseColumnExtractor implements ColumnExtractor {
+ private static final long serialVersionUID = 1L;
- protected final TranslatorContext context;
-
- BaseColumnExtractor(TranslatorContext context) {
- this.context = context;
- }
-
- protected void addDbAttribute(String prefix, String labelPrefix,
DbAttribute dba) {
- String alias = context.getTableTree().aliasForPath(prefix);
- String dataRowKey = labelPrefix != null ? labelPrefix + '.' +
dba.getName() : dba.getName();
- Node columnNode = table(alias).column(dba).build();
- context.addResultNode(columnNode, dataRowKey).setDbAttribute(dba);
- }
}
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/meaningful_pk/auto/_MeaningfulPkBigint.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/meaningful_pk/auto/_MeaningfulPkBigint.java
new file mode 100644
index 000000000..5994ffa8c
--- /dev/null
+++
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/meaningful_pk/auto/_MeaningfulPkBigint.java
@@ -0,0 +1,88 @@
+package org.apache.cayenne.testdo.meaningful_pk.auto;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.NumericProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+
+/**
+ * Class _MeaningfulPkBigint was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _MeaningfulPkBigint extends BaseDataObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String PK_PK_COLUMN = "PK";
+
+ public static final NumericProperty<BigInteger> PK =
PropertyFactory.createNumeric("pk", BigInteger.class);
+
+ protected BigInteger pk;
+
+
+ public void setPk(BigInteger pk) {
+ beforePropertyWrite("pk", this.pk, pk);
+ this.pk = pk;
+ }
+
+ public BigInteger getPk() {
+ beforePropertyRead("pk");
+ return this.pk;
+ }
+
+ @Override
+ public Object readPropertyDirectly(String propName) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch(propName) {
+ case "pk":
+ return this.pk;
+ default:
+ return super.readPropertyDirectly(propName);
+ }
+ }
+
+ @Override
+ public void writePropertyDirectly(String propName, Object val) {
+ if(propName == null) {
+ throw new IllegalArgumentException();
+ }
+
+ switch (propName) {
+ case "pk":
+ this.pk = (BigInteger)val;
+ break;
+ default:
+ super.writePropertyDirectly(propName, val);
+ }
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ writeSerialized(out);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
+ readSerialized(in);
+ }
+
+ @Override
+ protected void writeState(ObjectOutputStream out) throws IOException {
+ super.writeState(out);
+ out.writeObject(this.pk);
+ }
+
+ @Override
+ protected void readState(ObjectInputStream in) throws IOException,
ClassNotFoundException {
+ super.readState(in);
+ this.pk = (BigInteger)in.readObject();
+ }
+
+}
diff --git a/cayenne-server/src/test/resources/meaningful-pk.map.xml
b/cayenne-server/src/test/resources/meaningful-pk.map.xml
index 2ed609d4d..4202bed9f 100644
--- a/cayenne-server/src/test/resources/meaningful-pk.map.xml
+++ b/cayenne-server/src/test/resources/meaningful-pk.map.xml
@@ -9,6 +9,9 @@
<db-entity name="MEANINGFUL_PK">
<db-attribute name="PK" type="VARCHAR" isPrimaryKey="true"
isMandatory="true" length="100"/>
</db-entity>
+ <db-entity name="MEANINGFUL_PK_BIGINT">
+ <db-attribute name="PK" type="INTEGER" isPrimaryKey="true"
isMandatory="true"/>
+ </db-entity>
<db-entity name="MEANINGFUL_PK_DEP">
<db-attribute name="DESCR" type="VARCHAR" length="50"/>
<db-attribute name="MASTER_PK" type="INTEGER"/>
@@ -42,6 +45,9 @@
<obj-entity name="MeaningfulPk"
className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPk"
clientClassName="org.apache.cayenne.testdo.meaningful_pk.ClientMeaningfulPk"
dbEntityName="MEANINGFUL_PK">
<obj-attribute name="pk" type="java.lang.String"
db-attribute-path="PK"/>
</obj-entity>
+ <obj-entity name="MeaningfulPkBigint"
className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkBigint"
dbEntityName="MEANINGFUL_PK_BIGINT">
+ <obj-attribute name="pk" type="java.math.BigInteger"
db-attribute-path="PK"/>
+ </obj-entity>
<obj-entity name="MeaningfulPkDep2"
className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkDep2"
clientClassName="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPkDep2"
dbEntityName="MEANINGFUL_PK_DEP2">
<obj-attribute name="descr" type="java.lang.String"
db-attribute-path="DESCR"/>
<obj-attribute name="pk" type="java.lang.String"
db-attribute-path="PK"/>