This is an automated email from the ASF dual-hosted git repository.
pcristof pushed a commit to branch OPENJPA-2940
in repository https://gitbox.apache.org/repos/asf/openjpa.git
The following commit(s) were added to refs/heads/OPENJPA-2940 by this push:
new bef97d808 [WIP][OPENJPA-2940] Implemented ID(obj) FUNCTION on JPQL
bef97d808 is described below
commit bef97d80837cfa209f1e01a8761c9ab293acdc54
Author: Paulo Cristovão de Araújo Silva Filho <[email protected]>
AuthorDate: Mon Nov 17 08:43:38 2025 -0300
[WIP][OPENJPA-2940] Implemented ID(obj) FUNCTION on JPQL
---
.../jdbc/kernel/exps/GetNativeObjectId.java | 99 ++++++++++++++++++++++
.../openjpa/jdbc/kernel/exps/GetObjectId.java | 2 +-
.../jdbc/kernel/exps/JDBCExpressionFactory.java | 8 ++
.../openjpa/kernel/exps/ExpressionFactory.java | 12 ++-
.../kernel/exps/InMemoryExpressionFactory.java | 5 ++
.../openjpa/kernel/jpql/JPQLExpressionBuilder.java | 5 +-
.../org/apache/openjpa/util/ApplicationIds.java | 9 +-
.../jpql/functions/TestEJBQLFunction.java | 30 ++++++-
8 files changed, 161 insertions(+), 9 deletions(-)
diff --git
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetNativeObjectId.java
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetNativeObjectId.java
new file mode 100644
index 000000000..6b22fdd50
--- /dev/null
+++
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetNativeObjectId.java
@@ -0,0 +1,99 @@
+/*
+ * 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.jdbc.kernel.exps;
+
+import java.sql.SQLException;
+
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.meta.Joinable;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.util.ApplicationIds;
+import org.apache.openjpa.util.Id;
+import org.apache.openjpa.util.OpenJPAId;
+
+/**
+ * Select the id value of an object; typically used in projections.
+ *
+ * @author Abe White
+ * @author Paulo Cristovão Filho
+ */
+class GetNativeObjectId
+ extends GetObjectId {
+
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor. Provide the value whose id to extract.
+ */
+ public GetNativeObjectId(PCPath path) {
+ super(path);
+ }
+
+ @Override
+ public Object toDataStoreValue(Select sel, ExpContext ctx, ExpState state,
+ Object val) {
+ // if datastore identity, try to convert to a long value
+ ClassMapping mapping = _path.getClassMapping(state);
+ if (mapping.getIdentityType() == ClassMetaData.ID_DATASTORE) {
+ if (val instanceof Id)
+ return ((Id) val).getId();
+ return Filters.convert(val, long.class);
+ }
+
+ // if unknown identity, can't do much
+ if (mapping.getIdentityType() == ClassMetaData.ID_UNKNOWN)
+ return (val instanceof OpenJPAId) ? ((OpenJPAId)
val).getIdObject() : val;
+
+ // application identity; convert to pk values in the same order as
+ // the mapping's primary key columns will be returned
+ Object[] pks = ApplicationIds.toPKValues(val, mapping);
+ if (pks.length == 1)
+ return pks[0];
+ if (val == null)
+ return pks;
+ while (!mapping.isPrimaryKeyObjectId(false))
+ mapping = mapping.getJoinablePCSuperclassMapping();
+
+ Column[] cols = mapping.getPrimaryKeyColumns();
+ Object[] vals = new Object[cols.length];
+ Joinable join;
+ for (int i = 0; i < cols.length; i++) {
+ join = mapping.assertJoinable(cols[i]);
+ vals[i] = pks[mapping.getField(join.getFieldIndex()).
+ getPrimaryKeyIndex()];
+ vals[i] = join.getJoinValue(vals[i], cols[i], ctx.store);
+ }
+ return vals;
+ }
+
+ @Override
+ public Object load(ExpContext ctx, ExpState state, Result res)
+ throws SQLException {
+ Object ret = super.load(ctx, state, res);
+ return (ret != null && OpenJPAId.class.isAssignableFrom(ret.getClass()))
+ ? ((OpenJPAId) ret).getIdObject() : ret;
+ }
+
+}
+
diff --git
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
index d3db9f8a7..b7ed40e87 100644
---
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
+++
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
@@ -49,7 +49,7 @@ class GetObjectId
private static final Localizer _loc = Localizer.forPackage
(GetObjectId.class);
- private final PCPath _path;
+ protected final PCPath _path;
private ClassMetaData _meta = null;
/**
diff --git
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
index a77cb9f9d..ded7d807b 100644
---
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
+++
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
@@ -652,6 +652,14 @@ public class JDBCExpressionFactory
return new ConstGetObjectId((Const) val);
return new GetObjectId((PCPath) val);
}
+
+ @Override
+ public Value getNativeObjectId(Value val) {
+ if (val instanceof Const) {
+ return new ConstGetObjectId((Const) val);
+ }
+ return new GetNativeObjectId((PCPath) val);
+ }
@Override
public Value getMapValue(Value map, Value arg) {
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
index 80ca1ddbc..a4b19defd 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
@@ -527,14 +527,19 @@ public interface ExpressionFactory {
*
* @since 0.4.0.0
*/
- Value distinct (Value obj);
+ Value distinct(Value obj);
/**
* Return the object id of the given value.
*/
- Value getObjectId (Value val);
+ Value getObjectId(Value val);
- /**
+ /**
+ * Returns the id of the given value
+ */
+ Value getNativeObjectId(Value val);
+
+ /**
* Return a simple case expression
*/
Value simpleCaseExpression(Value caseOperand,
@@ -580,4 +585,5 @@ public interface ExpressionFactory {
* Return true if the Value is a Type expression and the Type uses joined
table strategy.
*/
boolean isVerticalType(Value val);
+
}
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
index b0e7c0e20..654839d46 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
@@ -815,6 +815,11 @@ public class InMemoryExpressionFactory
public Value getObjectId(Value val) {
return new GetObjectId((Val) val);
}
+
+ @Override
+ public Value getNativeObjectId(Value val) {
+ return new GetObjectId((Val) val);
+ }
/**
* Key that implements hashCode and equals methods for object arrays.
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
index 4be7a8ff3..91726cd44 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
@@ -1566,7 +1566,10 @@ public class JPQLExpressionBuilder
case JJTCASTTONUMBER:
return factory.newTypecastAsNumber(getValue(firstChild(node)),
resolveNumberTargetType((TypecastAsNumberPart)
eval(secondChild(node))));
-
+
+ case JJTIDFUNCTION:
+ return factory.getNativeObjectId(getValue(firstChild(node)));
+
default:
throw parseException(EX_FATAL, "bad-tree",
new Object[]{ node }, null);
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
index 81bdd57e4..09d2731b3 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
@@ -68,8 +68,13 @@ public class ApplicationIds {
Object[] pks;
if (meta.isOpenJPAIdentity()) {
pks = new Object[1];
- if (oid != null)
- pks[0] = ((OpenJPAId) oid).getIdObject();
+ if (oid != null) {
+ if (oid instanceof OpenJPAId ojid) {
+ pks[0] = ojid.getIdObject();
+ } else {
+ pks[0]= wrap(meta, oid);
+ }
+ }
return pks;
}
diff --git
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
index efb40cf7d..29ef52078 100644
---
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
+++
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
@@ -24,8 +24,6 @@ import java.time.LocalTime;
import java.time.temporal.ChronoField;
import java.util.List;
-import jakarta.persistence.EntityManager;
-
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.DerbyDictionary;
@@ -39,6 +37,8 @@ import org.apache.openjpa.persistence.common.apps.MaleUser;
import org.apache.openjpa.persistence.common.utils.AbstractTestCase;
import org.apache.openjpa.persistence.common.utils.DatabaseHelper;
+import jakarta.persistence.EntityManager;
+
public class TestEJBQLFunction extends AbstractTestCase {
private int userid1, userid2, userid3, userid4, userid5, userid6;
@@ -992,6 +992,32 @@ public class TestEJBQLFunction extends AbstractTestCase {
endEm(em);
}
+
+ public void testIdFunction() {
+ EntityManager em = currentEntityManager();
+
+ String query = "SELECT ID(u) FROM CompUser AS u WHERE u.name = :name";
+
+ List result = em.createQuery(query, Integer.class).setParameter("name",
"Seetha").getResultList();
+
+ assertEquals(1, result.size());
+ assertEquals(userid1, result.get(0));
+
+ endEm(em);
+ }
+
+ public void testIdFunctionOnWhere() {
+ EntityManager em = currentEntityManager();
+
+ String query = "SELECT u.name FROM CompUser AS u WHERE id(u)= :code";
+
+ List result = em.createQuery(query).setParameter("code",
userid1).getResultList();
+
+ assertEquals(1, result.size());
+ assertEquals("Seetha", (String) result.get(0));
+
+ endEm(em);
+ }
public CompUser createUser(String name, String cName, Address add, int age,
boolean isMale) {